Mercurial > dropbear
comparison netio.c @ 1511:5916af64acd4 fuzz
merge from main
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 17 Feb 2018 19:29:51 +0800 |
parents | 69862e8cc405 78d8c3ffdfe1 |
children | 2f64cb3d3007 |
comparison
equal
deleted
inserted
replaced
1457:32f990cc96b1 | 1511:5916af64acd4 |
---|---|
17 or NULL. */ | 17 or NULL. */ |
18 | 18 |
19 int sock; | 19 int sock; |
20 | 20 |
21 char* errstring; | 21 char* errstring; |
22 char *bind_address, *bind_port; | |
22 }; | 23 }; |
23 | 24 |
24 /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. | 25 /* Deallocate a progress connection. Removes from the pending list if iter!=NULL. |
25 Does not close sockets */ | 26 Does not close sockets */ |
26 static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) { | 27 static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) { |
28 freeaddrinfo(c->res); | 29 freeaddrinfo(c->res); |
29 } | 30 } |
30 m_free(c->remotehost); | 31 m_free(c->remotehost); |
31 m_free(c->remoteport); | 32 m_free(c->remoteport); |
32 m_free(c->errstring); | 33 m_free(c->errstring); |
34 m_free(c->bind_address); | |
35 m_free(c->bind_port); | |
33 m_free(c); | 36 m_free(c); |
34 | 37 |
35 if (iter) { | 38 if (iter) { |
36 list_remove(iter); | 39 list_remove(iter); |
37 } | 40 } |
49 c->cb_data = NULL; | 52 c->cb_data = NULL; |
50 } | 53 } |
51 | 54 |
52 static void connect_try_next(struct dropbear_progress_connection *c) { | 55 static void connect_try_next(struct dropbear_progress_connection *c) { |
53 struct addrinfo *r; | 56 struct addrinfo *r; |
57 int err; | |
54 int res = 0; | 58 int res = 0; |
55 int fastopen = 0; | 59 int fastopen = 0; |
56 #if DROPBEAR_CLIENT_TCP_FAST_OPEN | 60 #if DROPBEAR_CLIENT_TCP_FAST_OPEN |
57 struct msghdr message; | 61 struct msghdr message; |
58 #endif | 62 #endif |
62 dropbear_assert(c->sock == -1); | 66 dropbear_assert(c->sock == -1); |
63 | 67 |
64 c->sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); | 68 c->sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); |
65 if (c->sock < 0) { | 69 if (c->sock < 0) { |
66 continue; | 70 continue; |
71 } | |
72 | |
73 if (c->bind_address || c->bind_port) { | |
74 /* bind to a source port/address */ | |
75 struct addrinfo hints; | |
76 struct addrinfo *bindaddr = NULL; | |
77 memset(&hints, 0, sizeof(hints)); | |
78 hints.ai_socktype = SOCK_STREAM; | |
79 hints.ai_family = r->ai_family; | |
80 hints.ai_flags = AI_PASSIVE; | |
81 | |
82 err = getaddrinfo(c->bind_address, c->bind_port, &hints, &bindaddr); | |
83 if (err) { | |
84 int len = 100 + strlen(gai_strerror(err)); | |
85 m_free(c->errstring); | |
86 c->errstring = (char*)m_malloc(len); | |
87 snprintf(c->errstring, len, "Error resolving bind address '%s' (port %s). %s", | |
88 c->bind_address, c->bind_port, gai_strerror(err)); | |
89 TRACE(("Error resolving bind: %s", gai_strerror(err))) | |
90 close(c->sock); | |
91 c->sock = -1; | |
92 continue; | |
93 } | |
94 res = bind(c->sock, bindaddr->ai_addr, bindaddr->ai_addrlen); | |
95 freeaddrinfo(bindaddr); | |
96 bindaddr = NULL; | |
97 if (res < 0) { | |
98 /* failure */ | |
99 int keep_errno = errno; | |
100 int len = 300; | |
101 m_free(c->errstring); | |
102 c->errstring = m_malloc(len); | |
103 snprintf(c->errstring, len, "Error binding local address '%s' (port %s). %s", | |
104 c->bind_address, c->bind_port, strerror(keep_errno)); | |
105 close(c->sock); | |
106 c->sock = -1; | |
107 continue; | |
108 } | |
67 } | 109 } |
68 | 110 |
69 ses.maxfd = MAX(ses.maxfd, c->sock); | 111 ses.maxfd = MAX(ses.maxfd, c->sock); |
70 set_sock_nodelay(c->sock); | 112 set_sock_nodelay(c->sock); |
71 setnonblocking(c->sock); | 113 setnonblocking(c->sock); |
128 } | 170 } |
129 } | 171 } |
130 | 172 |
131 /* Connect via TCP to a host. */ | 173 /* Connect via TCP to a host. */ |
132 struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, | 174 struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport, |
133 connect_callback cb, void* cb_data) | 175 connect_callback cb, void* cb_data, |
176 const char* bind_address, const char* bind_port) | |
134 { | 177 { |
135 struct dropbear_progress_connection *c = NULL; | 178 struct dropbear_progress_connection *c = NULL; |
136 int err; | 179 int err; |
137 struct addrinfo hints; | 180 struct addrinfo hints; |
138 | 181 |
158 remotehost, remoteport, gai_strerror(err)); | 201 remotehost, remoteport, gai_strerror(err)); |
159 TRACE(("Error resolving: %s", gai_strerror(err))) | 202 TRACE(("Error resolving: %s", gai_strerror(err))) |
160 } else { | 203 } else { |
161 c->res_iter = c->res; | 204 c->res_iter = c->res; |
162 } | 205 } |
206 | |
207 if (bind_address) { | |
208 c->bind_address = m_strdup(bind_address); | |
209 } | |
210 if (bind_port) { | |
211 c->bind_port = m_strdup(bind_port); | |
212 } | |
163 | 213 |
164 return c; | 214 return c; |
165 } | 215 } |
166 | 216 |
167 void remove_connect_pending() { | 217 void remove_connect_pending() { |
196 iter = next_iter; | 246 iter = next_iter; |
197 } | 247 } |
198 TRACE(("leave set_connect_fds")) | 248 TRACE(("leave set_connect_fds")) |
199 } | 249 } |
200 | 250 |
201 void handle_connect_fds(fd_set *writefd) { | 251 void handle_connect_fds(const fd_set *writefd) { |
202 m_list_elem *iter; | 252 m_list_elem *iter; |
203 TRACE(("enter handle_connect_fds")) | 253 TRACE(("enter handle_connect_fds")) |
204 for (iter = ses.conn_pending.first; iter; iter = iter->next) { | 254 for (iter = ses.conn_pending.first; iter; iter = iter->next) { |
205 int val; | 255 int val; |
206 socklen_t vallen = sizeof(val); | 256 socklen_t vallen = sizeof(val); |
239 | 289 |
240 void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) { | 290 void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) { |
241 c->writequeue = writequeue; | 291 c->writequeue = writequeue; |
242 } | 292 } |
243 | 293 |
244 void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) { | 294 void packet_queue_to_iovec(const struct Queue *queue, struct iovec *iov, unsigned int *iov_count) { |
245 struct Link *l; | 295 struct Link *l; |
246 unsigned int i; | 296 unsigned int i; |
247 int len; | 297 int len; |
248 buffer *writebuf; | 298 buffer *writebuf; |
249 | 299 |
353 strerror(errno)); | 403 strerror(errno)); |
354 #endif | 404 #endif |
355 | 405 |
356 } | 406 } |
357 | 407 |
408 /* from openssh/canohost.c avoid premature-optimization */ | |
409 int get_sock_port(int sock) { | |
410 struct sockaddr_storage from; | |
411 socklen_t fromlen; | |
412 char strport[NI_MAXSERV]; | |
413 int r; | |
414 | |
415 /* Get IP address of client. */ | |
416 fromlen = sizeof(from); | |
417 memset(&from, 0, sizeof(from)); | |
418 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { | |
419 TRACE(("getsockname failed: %d", errno)) | |
420 return 0; | |
421 } | |
422 | |
423 /* Work around Linux IPv6 weirdness */ | |
424 if (from.ss_family == AF_INET6) | |
425 fromlen = sizeof(struct sockaddr_in6); | |
426 | |
427 /* Non-inet sockets don't have a port number. */ | |
428 if (from.ss_family != AF_INET && from.ss_family != AF_INET6) | |
429 return 0; | |
430 | |
431 /* Return port number. */ | |
432 if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, | |
433 strport, sizeof(strport), NI_NUMERICSERV)) != 0) { | |
434 TRACE(("netio.c/get_sock_port/getnameinfo NI_NUMERICSERV failed: %d", r)) | |
435 } | |
436 return atoi(strport); | |
437 } | |
438 | |
358 /* Listen on address:port. | 439 /* Listen on address:port. |
359 * Special cases are address of "" listening on everything, | 440 * Special cases are address of "" listening on everything, |
360 * and address of NULL listening on localhost only. | 441 * and address of NULL listening on localhost only. |
361 * Returns the number of sockets bound on success, or -1 on failure. On | 442 * Returns the number of sockets bound on success, or -1 on failure. On |
362 * failure, if errstring wasn't NULL, it'll be a newly malloced error | 443 * failure, if errstring wasn't NULL, it'll be a newly malloced error |
405 } | 486 } |
406 TRACE(("leave dropbear_listen: failed resolving")) | 487 TRACE(("leave dropbear_listen: failed resolving")) |
407 return -1; | 488 return -1; |
408 } | 489 } |
409 | 490 |
491 /* | |
492 * when listening on server-assigned-port 0 | |
493 * the assigned ports may differ for address families (v4/v6) | |
494 * causing problems for tcpip-forward | |
495 * caller can do a get_socket_address to discover assigned-port | |
496 * hence, use same port for all address families | |
497 */ | |
498 u_int16_t *allocated_lport_p = NULL; | |
499 int allocated_lport = 0; | |
410 | 500 |
411 nsock = 0; | 501 nsock = 0; |
412 for (res = res0; res != NULL && nsock < sockcount; | 502 for (res = res0; res != NULL && nsock < sockcount; |
413 res = res->ai_next) { | 503 res = res->ai_next) { |
504 | |
505 if (allocated_lport > 0) { | |
506 if (AF_INET == res->ai_family) { | |
507 allocated_lport_p = &((struct sockaddr_in *)res->ai_addr)->sin_port; | |
508 } else if (AF_INET6 == res->ai_family) { | |
509 allocated_lport_p = &((struct sockaddr_in6 *)res->ai_addr)->sin6_port; | |
510 } | |
511 *allocated_lport_p = htons(allocated_lport); | |
512 } | |
414 | 513 |
415 /* Get a socket */ | 514 /* Get a socket */ |
416 socks[nsock] = socket(res->ai_family, res->ai_socktype, | 515 socks[nsock] = socket(res->ai_family, res->ai_socktype, |
417 res->ai_protocol); | 516 res->ai_protocol); |
418 | 517 |
456 close(sock); | 555 close(sock); |
457 TRACE(("listen() failed")) | 556 TRACE(("listen() failed")) |
458 continue; | 557 continue; |
459 } | 558 } |
460 | 559 |
560 if (0 == allocated_lport) { | |
561 allocated_lport = get_sock_port(sock); | |
562 } | |
563 | |
461 *maxfd = MAX(*maxfd, sock); | 564 *maxfd = MAX(*maxfd, sock); |
462 | 565 |
463 nsock++; | 566 nsock++; |
464 } | 567 } |
465 | 568 |
522 unsigned int len; | 625 unsigned int len; |
523 int ret; | 626 int ret; |
524 | 627 |
525 int flags = NI_NUMERICSERV | NI_NUMERICHOST; | 628 int flags = NI_NUMERICSERV | NI_NUMERICHOST; |
526 | 629 |
527 #ifndef DO_HOST_LOOKUP | 630 #if !DO_HOST_LOOKUP |
528 host_lookup = 0; | 631 host_lookup = 0; |
529 #endif | 632 #endif |
530 | 633 |
531 if (host_lookup) { | 634 if (host_lookup) { |
532 flags = NI_NUMERICSERV; | 635 flags = NI_NUMERICSERV; |