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;