xconnect.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Utility routines.
  4. *
  5. * Connect to host at port using address resolution from getaddrinfo
  6. *
  7. */
  8. #include <netinet/in.h>
  9. #include "libbb.h"
  10. void setsockopt_reuseaddr(int fd)
  11. {
  12. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
  13. }
  14. int setsockopt_broadcast(int fd)
  15. {
  16. return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
  17. }
  18. void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
  19. {
  20. if (connect(s, s_addr, addrlen) < 0) {
  21. if (ENABLE_FEATURE_CLEAN_UP)
  22. close(s);
  23. if (s_addr->sa_family == AF_INET)
  24. bb_perror_msg_and_die("%s (%s)",
  25. "cannot connect to remote host",
  26. inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
  27. bb_perror_msg_and_die("cannot connect to remote host");
  28. }
  29. }
  30. /* Return port number for a service.
  31. * If "port" is a number use it as the port.
  32. * If "port" is a name it is looked up in /etc/services, if it isnt found return
  33. * default_port */
  34. unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
  35. {
  36. unsigned port_nr = default_port;
  37. if (port) {
  38. int old_errno;
  39. /* Since this is a lib function, we're not allowed to reset errno to 0.
  40. * Doing so could break an app that is deferring checking of errno. */
  41. old_errno = errno;
  42. port_nr = bb_strtou(port, NULL, 10);
  43. if (errno || port_nr > 65535) {
  44. struct servent *tserv = getservbyname(port, protocol);
  45. port_nr = default_port;
  46. if (tserv)
  47. port_nr = ntohs(tserv->s_port);
  48. }
  49. errno = old_errno;
  50. }
  51. return (uint16_t)port_nr;
  52. }
  53. /* "Old" networking API - only IPv4 */
  54. /*
  55. void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
  56. {
  57. struct hostent *he;
  58. memset(s_in, 0, sizeof(struct sockaddr_in));
  59. s_in->sin_family = AF_INET;
  60. he = xgethostbyname(host);
  61. memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
  62. }
  63. int xconnect_tcp_v4(struct sockaddr_in *s_addr)
  64. {
  65. int s = xsocket(AF_INET, SOCK_STREAM, 0);
  66. xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
  67. return s;
  68. }
  69. */
  70. /* "New" networking API */
  71. int get_nport(const struct sockaddr *sa)
  72. {
  73. #if ENABLE_FEATURE_IPV6
  74. if (sa->sa_family == AF_INET6) {
  75. return ((struct sockaddr_in6*)sa)->sin6_port;
  76. }
  77. #endif
  78. if (sa->sa_family == AF_INET) {
  79. return ((struct sockaddr_in*)sa)->sin_port;
  80. }
  81. /* What? UNIX socket? IPX?? :) */
  82. return -1;
  83. }
  84. void set_nport(len_and_sockaddr *lsa, unsigned port)
  85. {
  86. #if ENABLE_FEATURE_IPV6
  87. if (lsa->u.sa.sa_family == AF_INET6) {
  88. lsa->u.sin6.sin6_port = port;
  89. return;
  90. }
  91. #endif
  92. if (lsa->u.sa.sa_family == AF_INET) {
  93. lsa->u.sin.sin_port = port;
  94. return;
  95. }
  96. /* What? UNIX socket? IPX?? :) */
  97. }
  98. /* We hijack this constant to mean something else */
  99. /* It doesn't hurt because we will remove this bit anyway */
  100. #define DIE_ON_ERROR AI_CANONNAME
  101. /* host: "1.2.3.4[:port]", "www.google.com[:port]"
  102. * port: if neither of above specifies port # */
  103. static len_and_sockaddr* str2sockaddr(
  104. const char *host, int port,
  105. USE_FEATURE_IPV6(sa_family_t af,)
  106. int ai_flags)
  107. {
  108. int rc;
  109. len_and_sockaddr *r = NULL;
  110. struct addrinfo *result = NULL;
  111. struct addrinfo *used_res;
  112. const char *org_host = host; /* only for error msg */
  113. const char *cp;
  114. struct addrinfo hint;
  115. /* Ugly parsing of host:addr */
  116. if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
  117. /* Even uglier parsing of [xx]:nn */
  118. host++;
  119. cp = strchr(host, ']');
  120. if (!cp || cp[1] != ':') { /* Malformed: must have [xx]:nn */
  121. bb_error_msg("bad address '%s'", org_host);
  122. if (ai_flags & DIE_ON_ERROR)
  123. xfunc_die();
  124. return NULL;
  125. }
  126. } else {
  127. cp = strrchr(host, ':');
  128. if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
  129. /* There is more than one ':' (e.g. "::1") */
  130. cp = NULL; /* it's not a port spec */
  131. }
  132. }
  133. if (cp) { /* points to ":" or "]:" */
  134. int sz = cp - host + 1;
  135. host = safe_strncpy(alloca(sz), host, sz);
  136. if (ENABLE_FEATURE_IPV6 && *cp != ':')
  137. cp++; /* skip ']' */
  138. cp++; /* skip ':' */
  139. port = bb_strtou(cp, NULL, 10);
  140. if (errno || (unsigned)port > 0xffff) {
  141. bb_error_msg("bad port spec '%s'", org_host);
  142. if (ai_flags & DIE_ON_ERROR)
  143. xfunc_die();
  144. return NULL;
  145. }
  146. }
  147. memset(&hint, 0 , sizeof(hint));
  148. #if !ENABLE_FEATURE_IPV6
  149. hint.ai_family = AF_INET; /* do not try to find IPv6 */
  150. #else
  151. hint.ai_family = af;
  152. #endif
  153. /* Needed. Or else we will get each address thrice (or more)
  154. * for each possible socket type (tcp,udp,raw...): */
  155. hint.ai_socktype = SOCK_STREAM;
  156. hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
  157. rc = getaddrinfo(host, NULL, &hint, &result);
  158. if (rc || !result) {
  159. bb_error_msg("bad address '%s'", org_host);
  160. if (ai_flags & DIE_ON_ERROR)
  161. xfunc_die();
  162. goto ret;
  163. }
  164. used_res = result;
  165. #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
  166. while (1) {
  167. if (used_res->ai_family == AF_INET)
  168. break;
  169. used_res = used_res->ai_next;
  170. if (!used_res) {
  171. used_res = result;
  172. break;
  173. }
  174. }
  175. #endif
  176. r = xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen);
  177. r->len = used_res->ai_addrlen;
  178. memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
  179. set_nport(r, htons(port));
  180. ret:
  181. freeaddrinfo(result);
  182. return r;
  183. }
  184. #if !ENABLE_FEATURE_IPV6
  185. #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
  186. #endif
  187. #if ENABLE_FEATURE_IPV6
  188. len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)
  189. {
  190. return str2sockaddr(host, port, af, 0);
  191. }
  192. len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
  193. {
  194. return str2sockaddr(host, port, af, DIE_ON_ERROR);
  195. }
  196. #endif
  197. len_and_sockaddr* host2sockaddr(const char *host, int port)
  198. {
  199. return str2sockaddr(host, port, AF_UNSPEC, 0);
  200. }
  201. len_and_sockaddr* xhost2sockaddr(const char *host, int port)
  202. {
  203. return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
  204. }
  205. len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
  206. {
  207. return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
  208. }
  209. #undef xsocket_type
  210. int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
  211. {
  212. SKIP_FEATURE_IPV6(enum { family = AF_INET };)
  213. len_and_sockaddr *lsa;
  214. int fd;
  215. int len;
  216. #if ENABLE_FEATURE_IPV6
  217. if (family == AF_UNSPEC) {
  218. fd = socket(AF_INET6, sock_type, 0);
  219. if (fd >= 0) {
  220. family = AF_INET6;
  221. goto done;
  222. }
  223. family = AF_INET;
  224. }
  225. #endif
  226. fd = xsocket(family, sock_type, 0);
  227. len = sizeof(struct sockaddr_in);
  228. #if ENABLE_FEATURE_IPV6
  229. if (family == AF_INET6) {
  230. done:
  231. len = sizeof(struct sockaddr_in6);
  232. }
  233. #endif
  234. lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
  235. lsa->len = len;
  236. lsa->u.sa.sa_family = family;
  237. *lsap = lsa;
  238. return fd;
  239. }
  240. int xsocket_stream(len_and_sockaddr **lsap)
  241. {
  242. return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
  243. }
  244. static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
  245. {
  246. int fd;
  247. len_and_sockaddr *lsa;
  248. if (bindaddr && bindaddr[0]) {
  249. lsa = xdotted2sockaddr(bindaddr, port);
  250. /* user specified bind addr dictates family */
  251. fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
  252. } else {
  253. fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
  254. set_nport(lsa, htons(port));
  255. }
  256. setsockopt_reuseaddr(fd);
  257. xbind(fd, &lsa->u.sa, lsa->len);
  258. free(lsa);
  259. return fd;
  260. }
  261. int create_and_bind_stream_or_die(const char *bindaddr, int port)
  262. {
  263. return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
  264. }
  265. int create_and_bind_dgram_or_die(const char *bindaddr, int port)
  266. {
  267. return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
  268. }
  269. int create_and_connect_stream_or_die(const char *peer, int port)
  270. {
  271. int fd;
  272. len_and_sockaddr *lsa;
  273. lsa = xhost2sockaddr(peer, port);
  274. fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
  275. setsockopt_reuseaddr(fd);
  276. xconnect(fd, &lsa->u.sa, lsa->len);
  277. free(lsa);
  278. return fd;
  279. }
  280. int xconnect_stream(const len_and_sockaddr *lsa)
  281. {
  282. int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
  283. xconnect(fd, &lsa->u.sa, lsa->len);
  284. return fd;
  285. }
  286. /* We hijack this constant to mean something else */
  287. /* It doesn't hurt because we will add this bit anyway */
  288. #define IGNORE_PORT NI_NUMERICSERV
  289. static char* sockaddr2str(const struct sockaddr *sa, int flags)
  290. {
  291. char host[128];
  292. char serv[16];
  293. int rc;
  294. socklen_t salen;
  295. salen = LSA_SIZEOF_SA;
  296. #if ENABLE_FEATURE_IPV6
  297. if (sa->sa_family == AF_INET)
  298. salen = sizeof(struct sockaddr_in);
  299. if (sa->sa_family == AF_INET6)
  300. salen = sizeof(struct sockaddr_in6);
  301. #endif
  302. rc = getnameinfo(sa, salen,
  303. host, sizeof(host),
  304. /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
  305. serv, sizeof(serv),
  306. /* do not resolve port# into service _name_ */
  307. flags | NI_NUMERICSERV
  308. );
  309. if (rc)
  310. return NULL;
  311. if (flags & IGNORE_PORT)
  312. return xstrdup(host);
  313. #if ENABLE_FEATURE_IPV6
  314. if (sa->sa_family == AF_INET6) {
  315. if (strchr(host, ':')) /* heh, it's not a resolved hostname */
  316. return xasprintf("[%s]:%s", host, serv);
  317. /*return xasprintf("%s:%s", host, serv);*/
  318. /* - fall through instead */
  319. }
  320. #endif
  321. /* For now we don't support anything else, so it has to be INET */
  322. /*if (sa->sa_family == AF_INET)*/
  323. return xasprintf("%s:%s", host, serv);
  324. /*return xstrdup(host);*/
  325. }
  326. char* xmalloc_sockaddr2host(const struct sockaddr *sa)
  327. {
  328. return sockaddr2str(sa, 0);
  329. }
  330. char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
  331. {
  332. return sockaddr2str(sa, IGNORE_PORT);
  333. }
  334. char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
  335. {
  336. return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
  337. }
  338. char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)
  339. {
  340. return sockaddr2str(sa, NI_NUMERICHOST);
  341. }
  342. char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
  343. {
  344. return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
  345. }