netio.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. #include "netio.h"
  2. #include "list.h"
  3. #include "dbutil.h"
  4. #include "session.h"
  5. #include "debug.h"
  6. struct dropbear_progress_connection {
  7. struct addrinfo *res;
  8. struct addrinfo *res_iter;
  9. char *remotehost, *remoteport; /* For error reporting */
  10. connect_callback cb;
  11. void *cb_data;
  12. struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
  13. or NULL. */
  14. int sock;
  15. char* errstring;
  16. char *bind_address, *bind_port;
  17. enum dropbear_prio prio;
  18. };
  19. /* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
  20. Does not close sockets */
  21. static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
  22. if (c->res) {
  23. freeaddrinfo(c->res);
  24. }
  25. m_free(c->remotehost);
  26. m_free(c->remoteport);
  27. m_free(c->errstring);
  28. m_free(c->bind_address);
  29. m_free(c->bind_port);
  30. m_free(c);
  31. if (iter) {
  32. list_remove(iter);
  33. }
  34. }
  35. static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
  36. if (result == DROPBEAR_SUCCESS)
  37. {
  38. m_close(sock);
  39. }
  40. }
  41. void cancel_connect(struct dropbear_progress_connection *c) {
  42. c->cb = cancel_callback;
  43. c->cb_data = NULL;
  44. }
  45. static void connect_try_next(struct dropbear_progress_connection *c) {
  46. struct addrinfo *r;
  47. int err;
  48. int res = 0;
  49. int fastopen = 0;
  50. #if DROPBEAR_CLIENT_TCP_FAST_OPEN
  51. struct msghdr message;
  52. #endif
  53. for (r = c->res_iter; r; r = r->ai_next)
  54. {
  55. dropbear_assert(c->sock == -1);
  56. c->sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
  57. if (c->sock < 0) {
  58. continue;
  59. }
  60. if (c->bind_address || c->bind_port) {
  61. /* bind to a source port/address */
  62. struct addrinfo hints;
  63. struct addrinfo *bindaddr = NULL;
  64. memset(&hints, 0, sizeof(hints));
  65. hints.ai_socktype = SOCK_STREAM;
  66. hints.ai_family = r->ai_family;
  67. hints.ai_flags = AI_PASSIVE;
  68. err = getaddrinfo(c->bind_address, c->bind_port, &hints, &bindaddr);
  69. if (err) {
  70. int len = 100 + strlen(gai_strerror(err));
  71. m_free(c->errstring);
  72. c->errstring = (char*)m_malloc(len);
  73. snprintf(c->errstring, len, "Error resolving bind address '%s' (port %s). %s",
  74. c->bind_address, c->bind_port, gai_strerror(err));
  75. TRACE(("Error resolving bind: %s", gai_strerror(err)))
  76. close(c->sock);
  77. c->sock = -1;
  78. continue;
  79. }
  80. res = bind(c->sock, bindaddr->ai_addr, bindaddr->ai_addrlen);
  81. freeaddrinfo(bindaddr);
  82. bindaddr = NULL;
  83. if (res < 0) {
  84. /* failure */
  85. int keep_errno = errno;
  86. int len = 300;
  87. m_free(c->errstring);
  88. c->errstring = m_malloc(len);
  89. snprintf(c->errstring, len, "Error binding local address '%s' (port %s). %s",
  90. c->bind_address, c->bind_port, strerror(keep_errno));
  91. close(c->sock);
  92. c->sock = -1;
  93. continue;
  94. }
  95. }
  96. ses.maxfd = MAX(ses.maxfd, c->sock);
  97. set_sock_nodelay(c->sock);
  98. set_sock_priority(c->sock, c->prio);
  99. setnonblocking(c->sock);
  100. #if DROPBEAR_CLIENT_TCP_FAST_OPEN
  101. fastopen = (c->writequeue != NULL);
  102. if (fastopen) {
  103. memset(&message, 0x0, sizeof(message));
  104. message.msg_name = r->ai_addr;
  105. message.msg_namelen = r->ai_addrlen;
  106. /* 6 is arbitrary, enough to hold initial packets */
  107. unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
  108. struct iovec iov[6];
  109. packet_queue_to_iovec(c->writequeue, iov, &iovlen);
  110. message.msg_iov = iov;
  111. message.msg_iovlen = iovlen;
  112. res = sendmsg(c->sock, &message, MSG_FASTOPEN);
  113. /* Returns EINPROGRESS if FASTOPEN wasn't available */
  114. if (res < 0) {
  115. if (errno != EINPROGRESS) {
  116. m_free(c->errstring);
  117. c->errstring = m_strdup(strerror(errno));
  118. /* Not entirely sure which kind of errors are normal - 2.6.32 seems to
  119. return EPIPE for any (nonblocking?) sendmsg(). just fall back */
  120. TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
  121. /* No kernel MSG_FASTOPEN support. Fall back below */
  122. fastopen = 0;
  123. /* Set to NULL to avoid trying again */
  124. c->writequeue = NULL;
  125. }
  126. } else {
  127. packet_queue_consume(c->writequeue, res);
  128. }
  129. }
  130. #endif
  131. /* Normal connect(), used as fallback for TCP fastopen too */
  132. if (!fastopen) {
  133. res = connect(c->sock, r->ai_addr, r->ai_addrlen);
  134. }
  135. if (res < 0 && errno != EINPROGRESS) {
  136. /* failure */
  137. m_free(c->errstring);
  138. c->errstring = m_strdup(strerror(errno));
  139. close(c->sock);
  140. c->sock = -1;
  141. continue;
  142. } else {
  143. /* new connection was successful, wait for it to complete */
  144. break;
  145. }
  146. }
  147. if (r) {
  148. c->res_iter = r->ai_next;
  149. } else {
  150. c->res_iter = NULL;
  151. }
  152. }
  153. /* Connect via TCP to a host. */
  154. struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
  155. connect_callback cb, void* cb_data,
  156. const char* bind_address, const char* bind_port, enum dropbear_prio prio)
  157. {
  158. struct dropbear_progress_connection *c = NULL;
  159. int err;
  160. struct addrinfo hints;
  161. c = m_malloc(sizeof(*c));
  162. c->remotehost = m_strdup(remotehost);
  163. c->remoteport = m_strdup(remoteport);
  164. c->sock = -1;
  165. c->cb = cb;
  166. c->cb_data = cb_data;
  167. c->prio = prio;
  168. list_append(&ses.conn_pending, c);
  169. #if DROPBEAR_FUZZ
  170. if (fuzz.fuzzing) {
  171. c->errstring = m_strdup("fuzzing connect_remote always fails");
  172. return c;
  173. }
  174. #endif
  175. memset(&hints, 0, sizeof(hints));
  176. hints.ai_socktype = SOCK_STREAM;
  177. hints.ai_family = AF_UNSPEC;
  178. err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
  179. if (err) {
  180. int len;
  181. len = 100 + strlen(gai_strerror(err));
  182. c->errstring = (char*)m_malloc(len);
  183. snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
  184. remotehost, remoteport, gai_strerror(err));
  185. TRACE(("Error resolving: %s", gai_strerror(err)))
  186. } else {
  187. c->res_iter = c->res;
  188. }
  189. if (bind_address) {
  190. c->bind_address = m_strdup(bind_address);
  191. }
  192. if (bind_port) {
  193. c->bind_port = m_strdup(bind_port);
  194. }
  195. return c;
  196. }
  197. void remove_connect_pending() {
  198. while (ses.conn_pending.first) {
  199. struct dropbear_progress_connection *c = ses.conn_pending.first->item;
  200. remove_connect(c, ses.conn_pending.first);
  201. }
  202. }
  203. void set_connect_fds(fd_set *writefd) {
  204. m_list_elem *iter;
  205. iter = ses.conn_pending.first;
  206. while (iter) {
  207. m_list_elem *next_iter = iter->next;
  208. struct dropbear_progress_connection *c = iter->item;
  209. /* Set one going */
  210. while (c->res_iter && c->sock < 0) {
  211. connect_try_next(c);
  212. }
  213. if (c->sock >= 0) {
  214. FD_SET(c->sock, writefd);
  215. } else {
  216. /* Final failure */
  217. if (!c->errstring) {
  218. c->errstring = m_strdup("unexpected failure");
  219. }
  220. c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
  221. remove_connect(c, iter);
  222. }
  223. iter = next_iter;
  224. }
  225. }
  226. void handle_connect_fds(const fd_set *writefd) {
  227. m_list_elem *iter;
  228. for (iter = ses.conn_pending.first; iter; iter = iter->next) {
  229. int val;
  230. socklen_t vallen = sizeof(val);
  231. struct dropbear_progress_connection *c = iter->item;
  232. if (c->sock < 0 || !FD_ISSET(c->sock, writefd)) {
  233. continue;
  234. }
  235. TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
  236. if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
  237. TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
  238. /* This isn't expected to happen - Unix has surprises though, continue gracefully. */
  239. m_close(c->sock);
  240. c->sock = -1;
  241. } else if (val != 0) {
  242. /* Connect failed */
  243. TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
  244. m_close(c->sock);
  245. c->sock = -1;
  246. m_free(c->errstring);
  247. c->errstring = m_strdup(strerror(val));
  248. } else {
  249. /* New connection has been established */
  250. c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
  251. remove_connect(c, iter);
  252. TRACE(("leave handle_connect_fds - success"))
  253. /* Must return here - remove_connect() invalidates iter */
  254. return;
  255. }
  256. }
  257. }
  258. void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
  259. c->writequeue = writequeue;
  260. }
  261. void packet_queue_to_iovec(const struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
  262. struct Link *l;
  263. unsigned int i;
  264. int len;
  265. buffer *writebuf;
  266. #ifndef IOV_MAX
  267. #if defined(__CYGWIN__) && !defined(UIO_MAXIOV)
  268. #define IOV_MAX 1024
  269. #elif defined(__sgi)
  270. #define IOV_MAX 512
  271. #else
  272. #define IOV_MAX UIO_MAXIOV
  273. #endif
  274. #endif
  275. *iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
  276. for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
  277. {
  278. writebuf = (buffer*)l->item;
  279. len = writebuf->len - writebuf->pos;
  280. dropbear_assert(len > 0);
  281. TRACE2(("write_packet writev #%d len %d/%d", i,
  282. len, writebuf->len))
  283. iov[i].iov_base = buf_getptr(writebuf, len);
  284. iov[i].iov_len = len;
  285. }
  286. }
  287. void packet_queue_consume(struct Queue *queue, ssize_t written) {
  288. buffer *writebuf;
  289. int len;
  290. while (written > 0) {
  291. writebuf = (buffer*)examine(queue);
  292. len = writebuf->len - writebuf->pos;
  293. if (len > written) {
  294. /* partial buffer write */
  295. buf_incrpos(writebuf, written);
  296. written = 0;
  297. } else {
  298. written -= len;
  299. dequeue(queue);
  300. buf_free(writebuf);
  301. }
  302. }
  303. }
  304. void set_sock_nodelay(int sock) {
  305. int val;
  306. /* disable nagle */
  307. val = 1;
  308. setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
  309. }
  310. #if DROPBEAR_SERVER_TCP_FAST_OPEN
  311. void set_listen_fast_open(int sock) {
  312. int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
  313. if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
  314. TRACE(("set_listen_fast_open failed for socket %d: %s", sock, strerror(errno)))
  315. }
  316. }
  317. #endif
  318. void set_sock_priority(int sock, enum dropbear_prio prio) {
  319. int rc;
  320. int val;
  321. #if DROPBEAR_FUZZ
  322. if (fuzz.fuzzing) {
  323. TRACE(("fuzzing skips set_sock_prio"))
  324. return;
  325. }
  326. #endif
  327. /* Don't log ENOTSOCK errors so that this can harmlessly be called
  328. * on a client '-J' proxy pipe */
  329. #ifdef IP_TOS
  330. /* Set the DSCP field for outbound IP packet priority.
  331. rfc4594 has some guidance to meanings.
  332. We set AF21 as "Low-Latency" class for interactive (tty session,
  333. also handshake/setup packets). Other traffic is left at the default.
  334. OpenSSH at present uses AF21/CS1, rationale
  335. https://cvsweb.openbsd.org/src/usr.bin/ssh/readconf.c#rev1.284
  336. Old Dropbear/OpenSSH and Debian/Ubuntu OpenSSH (at Jan 2022) use
  337. IPTOS_LOWDELAY/IPTOS_THROUGHPUT
  338. DSCP constants are from Linux headers, applicable to other platforms
  339. such as macos.
  340. */
  341. if (prio == DROPBEAR_PRIO_LOWDELAY) {
  342. val = 0x48; /* IPTOS_DSCP_AF21 */
  343. } else {
  344. val = 0; /* default */
  345. }
  346. #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
  347. rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
  348. if (rc < 0 && errno != ENOTSOCK) {
  349. TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
  350. }
  351. #endif
  352. rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
  353. if (rc < 0 && errno != ENOTSOCK) {
  354. TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
  355. }
  356. #endif /* IP_TOS */
  357. #ifdef HAVE_LINUX_PKT_SCHED_H
  358. /* Set scheduling priority within the local Linux network stack */
  359. if (prio == DROPBEAR_PRIO_LOWDELAY) {
  360. val = TC_PRIO_INTERACTIVE;
  361. } else {
  362. val = 0;
  363. }
  364. /* linux specific, sets QoS class. see tc-prio(8) */
  365. rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
  366. if (rc < 0 && errno != ENOTSOCK) {
  367. TRACE(("Couldn't set SO_PRIORITY (%s)", strerror(errno)))
  368. }
  369. #endif
  370. }
  371. /* from openssh/canohost.c avoid premature-optimization */
  372. int get_sock_port(int sock) {
  373. struct sockaddr_storage from;
  374. socklen_t fromlen;
  375. char strport[NI_MAXSERV];
  376. int r;
  377. /* Get IP address of client. */
  378. fromlen = sizeof(from);
  379. memset(&from, 0, sizeof(from));
  380. if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
  381. TRACE(("getsockname failed: %d", errno))
  382. return 0;
  383. }
  384. /* Work around Linux IPv6 weirdness */
  385. if (from.ss_family == AF_INET6)
  386. fromlen = sizeof(struct sockaddr_in6);
  387. /* Non-inet sockets don't have a port number. */
  388. if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
  389. return 0;
  390. /* Return port number. */
  391. if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
  392. strport, sizeof(strport), NI_NUMERICSERV)) != 0) {
  393. TRACE(("netio.c/get_sock_port/getnameinfo NI_NUMERICSERV failed: %d", r))
  394. }
  395. return atoi(strport);
  396. }
  397. /* Listen on address:port.
  398. * Special cases are address of "" listening on everything,
  399. * and address of NULL listening on localhost only.
  400. * Returns the number of sockets bound on success, or -1 on failure. On
  401. * failure, if errstring wasn't NULL, it'll be a newly malloced error
  402. * string.*/
  403. int dropbear_listen(const char* address, const char* port,
  404. int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
  405. struct addrinfo hints, *res = NULL, *res0 = NULL;
  406. int err;
  407. unsigned int nsock;
  408. struct linger linger;
  409. int val;
  410. int sock;
  411. uint16_t *allocated_lport_p = NULL;
  412. int allocated_lport = 0;
  413. TRACE(("enter dropbear_listen"))
  414. #if DROPBEAR_FUZZ
  415. if (fuzz.fuzzing) {
  416. return fuzz_dropbear_listen(address, port, socks, sockcount, errstring, maxfd);
  417. }
  418. #endif
  419. memset(&hints, 0, sizeof(hints));
  420. hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
  421. hints.ai_socktype = SOCK_STREAM;
  422. /* for calling getaddrinfo:
  423. address == NULL and !AI_PASSIVE: local loopback
  424. address == NULL and AI_PASSIVE: all interfaces
  425. address != NULL: whatever the address says */
  426. if (!address) {
  427. TRACE(("dropbear_listen: local loopback"))
  428. } else {
  429. if (address[0] == '\0') {
  430. TRACE(("dropbear_listen: all interfaces"))
  431. address = NULL;
  432. }
  433. hints.ai_flags = AI_PASSIVE;
  434. }
  435. err = getaddrinfo(address, port, &hints, &res0);
  436. if (err) {
  437. if (errstring != NULL && *errstring == NULL) {
  438. int len;
  439. len = 20 + strlen(gai_strerror(err));
  440. *errstring = (char*)m_malloc(len);
  441. snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
  442. }
  443. if (res0) {
  444. freeaddrinfo(res0);
  445. res0 = NULL;
  446. }
  447. TRACE(("leave dropbear_listen: failed resolving"))
  448. return -1;
  449. }
  450. /* When listening on server-assigned-port 0
  451. * the assigned ports may differ for address families (v4/v6)
  452. * causing problems for tcpip-forward.
  453. * Caller can do a get_socket_address to discover assigned-port
  454. * hence, use same port for all address families */
  455. allocated_lport = 0;
  456. nsock = 0;
  457. for (res = res0; res != NULL && nsock < sockcount;
  458. res = res->ai_next) {
  459. if (allocated_lport > 0) {
  460. if (AF_INET == res->ai_family) {
  461. allocated_lport_p = &((struct sockaddr_in *)res->ai_addr)->sin_port;
  462. } else if (AF_INET6 == res->ai_family) {
  463. allocated_lport_p = &((struct sockaddr_in6 *)res->ai_addr)->sin6_port;
  464. }
  465. *allocated_lport_p = htons(allocated_lport);
  466. }
  467. /* Get a socket */
  468. socks[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  469. sock = socks[nsock]; /* For clarity */
  470. if (sock < 0) {
  471. err = errno;
  472. TRACE(("socket() failed"))
  473. continue;
  474. }
  475. /* Various useful socket options */
  476. val = 1;
  477. /* set to reuse, quick timeout */
  478. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
  479. linger.l_onoff = 1;
  480. linger.l_linger = 5;
  481. setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
  482. #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
  483. if (res->ai_family == AF_INET6) {
  484. int on = 1;
  485. if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
  486. &on, sizeof(on)) == -1) {
  487. dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
  488. }
  489. }
  490. #endif
  491. set_sock_nodelay(sock);
  492. if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
  493. err = errno;
  494. close(sock);
  495. TRACE(("bind(%s) failed", port))
  496. continue;
  497. }
  498. if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
  499. err = errno;
  500. close(sock);
  501. TRACE(("listen() failed"))
  502. continue;
  503. }
  504. if (0 == allocated_lport) {
  505. allocated_lport = get_sock_port(sock);
  506. }
  507. *maxfd = MAX(*maxfd, sock);
  508. nsock++;
  509. }
  510. if (res0) {
  511. freeaddrinfo(res0);
  512. res0 = NULL;
  513. }
  514. if (nsock == 0) {
  515. if (errstring != NULL && *errstring == NULL) {
  516. int len;
  517. len = 20 + strlen(strerror(err));
  518. *errstring = (char*)m_malloc(len);
  519. snprintf(*errstring, len, "Error listening: %s", strerror(err));
  520. }
  521. TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
  522. return -1;
  523. }
  524. TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
  525. return nsock;
  526. }
  527. void get_socket_address(int fd, char **local_host, char **local_port,
  528. char **remote_host, char **remote_port, int host_lookup)
  529. {
  530. struct sockaddr_storage addr;
  531. socklen_t addrlen;
  532. #if DROPBEAR_FUZZ
  533. if (fuzz.fuzzing) {
  534. fuzz_get_socket_address(fd, local_host, local_port, remote_host, remote_port, host_lookup);
  535. return;
  536. }
  537. #endif
  538. if (local_host || local_port) {
  539. addrlen = sizeof(addr);
  540. if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
  541. dropbear_exit("Failed socket address: %s", strerror(errno));
  542. }
  543. getaddrstring(&addr, local_host, local_port, host_lookup);
  544. }
  545. if (remote_host || remote_port) {
  546. addrlen = sizeof(addr);
  547. if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
  548. dropbear_exit("Failed socket address: %s", strerror(errno));
  549. }
  550. getaddrstring(&addr, remote_host, remote_port, host_lookup);
  551. }
  552. }
  553. /* Return a string representation of the socket address passed. The return
  554. * value is allocated with malloc() */
  555. void getaddrstring(struct sockaddr_storage* addr,
  556. char **ret_host, char **ret_port,
  557. int host_lookup) {
  558. char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
  559. unsigned int len;
  560. int ret;
  561. int flags = NI_NUMERICSERV | NI_NUMERICHOST;
  562. #if !DO_HOST_LOOKUP
  563. host_lookup = 0;
  564. #endif
  565. if (host_lookup) {
  566. flags = NI_NUMERICSERV;
  567. }
  568. len = sizeof(struct sockaddr_storage);
  569. /* Some platforms such as Solaris 8 require that len is the length
  570. * of the specific structure. Some older linux systems (glibc 2.1.3
  571. * such as debian potato) have sockaddr_storage.__ss_family instead
  572. * but we'll ignore them */
  573. #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
  574. if (addr->ss_family == AF_INET) {
  575. len = sizeof(struct sockaddr_in);
  576. }
  577. #ifdef AF_INET6
  578. if (addr->ss_family == AF_INET6) {
  579. len = sizeof(struct sockaddr_in6);
  580. }
  581. #endif
  582. #endif
  583. ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
  584. serv, sizeof(serv)-1, flags);
  585. if (ret != 0) {
  586. if (host_lookup) {
  587. /* On some systems (Darwin does it) we get EINTR from getnameinfo
  588. * somehow. Eew. So we'll just return the IP, since that doesn't seem
  589. * to exhibit that behaviour. */
  590. getaddrstring(addr, ret_host, ret_port, 0);
  591. return;
  592. } else {
  593. /* if we can't do a numeric lookup, something's gone terribly wrong */
  594. dropbear_exit("Failed lookup: %s", gai_strerror(ret));
  595. }
  596. }
  597. if (ret_host) {
  598. *ret_host = m_strdup(host);
  599. }
  600. if (ret_port) {
  601. *ret_port = m_strdup(serv);
  602. }
  603. }