Mercurial > dropbear
comparison netio.c @ 1478:3a933956437e coverity
update coverity
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 09 Feb 2018 23:49:22 +0800 |
parents | f787f60f8e45 |
children | 2d450c1056e3 |
comparison
equal
deleted
inserted
replaced
1439:8d24733026c5 | 1478:3a933956437e |
---|---|
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() { |
195 } | 245 } |
196 iter = next_iter; | 246 iter = next_iter; |
197 } | 247 } |
198 } | 248 } |
199 | 249 |
200 void handle_connect_fds(fd_set *writefd) { | 250 void handle_connect_fds(const fd_set *writefd) { |
201 m_list_elem *iter; | 251 m_list_elem *iter; |
202 TRACE(("enter handle_connect_fds")) | 252 TRACE(("enter handle_connect_fds")) |
203 for (iter = ses.conn_pending.first; iter; iter = iter->next) { | 253 for (iter = ses.conn_pending.first; iter; iter = iter->next) { |
204 int val; | 254 int val; |
205 socklen_t vallen = sizeof(val); | 255 socklen_t vallen = sizeof(val); |
238 | 288 |
239 void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) { | 289 void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) { |
240 c->writequeue = writequeue; | 290 c->writequeue = writequeue; |
241 } | 291 } |
242 | 292 |
243 void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) { | 293 void packet_queue_to_iovec(const struct Queue *queue, struct iovec *iov, unsigned int *iov_count) { |
244 struct Link *l; | 294 struct Link *l; |
245 unsigned int i; | 295 unsigned int i; |
246 int len; | 296 int len; |
247 buffer *writebuf; | 297 buffer *writebuf; |
248 | 298 |
346 strerror(errno)); | 396 strerror(errno)); |
347 #endif | 397 #endif |
348 | 398 |
349 } | 399 } |
350 | 400 |
401 /* from openssh/canohost.c avoid premature-optimization */ | |
402 int get_sock_port(int sock) { | |
403 struct sockaddr_storage from; | |
404 socklen_t fromlen; | |
405 char strport[NI_MAXSERV]; | |
406 int r; | |
407 | |
408 /* Get IP address of client. */ | |
409 fromlen = sizeof(from); | |
410 memset(&from, 0, sizeof(from)); | |
411 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { | |
412 TRACE(("getsockname failed: %d", errno)) | |
413 return 0; | |
414 } | |
415 | |
416 /* Work around Linux IPv6 weirdness */ | |
417 if (from.ss_family == AF_INET6) | |
418 fromlen = sizeof(struct sockaddr_in6); | |
419 | |
420 /* Non-inet sockets don't have a port number. */ | |
421 if (from.ss_family != AF_INET && from.ss_family != AF_INET6) | |
422 return 0; | |
423 | |
424 /* Return port number. */ | |
425 if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, | |
426 strport, sizeof(strport), NI_NUMERICSERV)) != 0) { | |
427 TRACE(("netio.c/get_sock_port/getnameinfo NI_NUMERICSERV failed: %d", r)) | |
428 } | |
429 return atoi(strport); | |
430 } | |
431 | |
351 /* Listen on address:port. | 432 /* Listen on address:port. |
352 * Special cases are address of "" listening on everything, | 433 * Special cases are address of "" listening on everything, |
353 * and address of NULL listening on localhost only. | 434 * and address of NULL listening on localhost only. |
354 * Returns the number of sockets bound on success, or -1 on failure. On | 435 * Returns the number of sockets bound on success, or -1 on failure. On |
355 * failure, if errstring wasn't NULL, it'll be a newly malloced error | 436 * failure, if errstring wasn't NULL, it'll be a newly malloced error |
398 } | 479 } |
399 TRACE(("leave dropbear_listen: failed resolving")) | 480 TRACE(("leave dropbear_listen: failed resolving")) |
400 return -1; | 481 return -1; |
401 } | 482 } |
402 | 483 |
484 /* | |
485 * when listening on server-assigned-port 0 | |
486 * the assigned ports may differ for address families (v4/v6) | |
487 * causing problems for tcpip-forward | |
488 * caller can do a get_socket_address to discover assigned-port | |
489 * hence, use same port for all address families | |
490 */ | |
491 u_int16_t *allocated_lport_p = 0; | |
492 int allocated_lport = 0; | |
403 | 493 |
404 nsock = 0; | 494 nsock = 0; |
405 for (res = res0; res != NULL && nsock < sockcount; | 495 for (res = res0; res != NULL && nsock < sockcount; |
406 res = res->ai_next) { | 496 res = res->ai_next) { |
497 | |
498 if (allocated_lport > 0) { | |
499 if (AF_INET == res->ai_family) { | |
500 allocated_lport_p = &((struct sockaddr_in *)res->ai_addr)->sin_port; | |
501 } else if (AF_INET6 == res->ai_family) { | |
502 allocated_lport_p = &((struct sockaddr_in6 *)res->ai_addr)->sin6_port; | |
503 } | |
504 *allocated_lport_p = htons(allocated_lport); | |
505 } | |
407 | 506 |
408 /* Get a socket */ | 507 /* Get a socket */ |
409 socks[nsock] = socket(res->ai_family, res->ai_socktype, | 508 socks[nsock] = socket(res->ai_family, res->ai_socktype, |
410 res->ai_protocol); | 509 res->ai_protocol); |
411 | 510 |
447 if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) { | 546 if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) { |
448 err = errno; | 547 err = errno; |
449 close(sock); | 548 close(sock); |
450 TRACE(("listen() failed")) | 549 TRACE(("listen() failed")) |
451 continue; | 550 continue; |
551 } | |
552 | |
553 if (0 == allocated_lport) { | |
554 allocated_lport = get_sock_port(sock); | |
452 } | 555 } |
453 | 556 |
454 *maxfd = MAX(*maxfd, sock); | 557 *maxfd = MAX(*maxfd, sock); |
455 | 558 |
456 nsock++; | 559 nsock++; |