comparison dbutil.c @ 1051:359fba4b1a49

merge tcp fastopen
author Matt Johnston <matt@ucc.asn.au>
date Sat, 28 Feb 2015 23:24:30 +0800
parents 01eea88963f3
children 36557295418e
comparison
equal deleted inserted replaced
1045:31727a8abd4b 1051:359fba4b1a49
211 fprintf(stderr, "\n"); 211 fprintf(stderr, "\n");
212 va_end(param); 212 va_end(param);
213 } 213 }
214 #endif /* DEBUG_TRACE */ 214 #endif /* DEBUG_TRACE */
215 215
216 void set_sock_nodelay(int sock) {
217 int val;
218
219 /* disable nagle */
220 val = 1;
221 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
222 }
223
224 void set_sock_priority(int sock, enum dropbear_prio prio) {
225
226 int iptos_val = 0, so_prio_val = 0, rc;
227
228 /* Don't log ENOTSOCK errors so that this can harmlessly be called
229 * on a client '-J' proxy pipe */
230
231 /* set the TOS bit for either ipv4 or ipv6 */
232 #ifdef IPTOS_LOWDELAY
233 if (prio == DROPBEAR_PRIO_LOWDELAY) {
234 iptos_val = IPTOS_LOWDELAY;
235 } else if (prio == DROPBEAR_PRIO_BULK) {
236 iptos_val = IPTOS_THROUGHPUT;
237 }
238 #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
239 rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
240 if (rc < 0 && errno != ENOTSOCK) {
241 TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
242 }
243 #endif
244 rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
245 if (rc < 0 && errno != ENOTSOCK) {
246 TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
247 }
248 #endif
249
250 #ifdef SO_PRIORITY
251 if (prio == DROPBEAR_PRIO_LOWDELAY) {
252 so_prio_val = TC_PRIO_INTERACTIVE;
253 } else if (prio == DROPBEAR_PRIO_BULK) {
254 so_prio_val = TC_PRIO_BULK;
255 }
256 /* linux specific, sets QoS class. see tc-prio(8) */
257 rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
258 if (rc < 0 && errno != ENOTSOCK)
259 dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
260 strerror(errno));
261 #endif
262
263 }
264
265 /* Listen on address:port.
266 * Special cases are address of "" listening on everything,
267 * and address of NULL listening on localhost only.
268 * Returns the number of sockets bound on success, or -1 on failure. On
269 * failure, if errstring wasn't NULL, it'll be a newly malloced error
270 * string.*/
271 int dropbear_listen(const char* address, const char* port,
272 int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
273
274 struct addrinfo hints, *res = NULL, *res0 = NULL;
275 int err;
276 unsigned int nsock;
277 struct linger linger;
278 int val;
279 int sock;
280
281 TRACE(("enter dropbear_listen"))
282
283 memset(&hints, 0, sizeof(hints));
284 hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
285 hints.ai_socktype = SOCK_STREAM;
286
287 /* for calling getaddrinfo:
288 address == NULL and !AI_PASSIVE: local loopback
289 address == NULL and AI_PASSIVE: all interfaces
290 address != NULL: whatever the address says */
291 if (!address) {
292 TRACE(("dropbear_listen: local loopback"))
293 } else {
294 if (address[0] == '\0') {
295 TRACE(("dropbear_listen: all interfaces"))
296 address = NULL;
297 }
298 hints.ai_flags = AI_PASSIVE;
299 }
300 err = getaddrinfo(address, port, &hints, &res0);
301
302 if (err) {
303 if (errstring != NULL && *errstring == NULL) {
304 int len;
305 len = 20 + strlen(gai_strerror(err));
306 *errstring = (char*)m_malloc(len);
307 snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
308 }
309 if (res0) {
310 freeaddrinfo(res0);
311 res0 = NULL;
312 }
313 TRACE(("leave dropbear_listen: failed resolving"))
314 return -1;
315 }
316
317
318 nsock = 0;
319 for (res = res0; res != NULL && nsock < sockcount;
320 res = res->ai_next) {
321
322 /* Get a socket */
323 socks[nsock] = socket(res->ai_family, res->ai_socktype,
324 res->ai_protocol);
325
326 sock = socks[nsock]; /* For clarity */
327
328 if (sock < 0) {
329 err = errno;
330 TRACE(("socket() failed"))
331 continue;
332 }
333
334 /* Various useful socket options */
335 val = 1;
336 /* set to reuse, quick timeout */
337 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
338 linger.l_onoff = 1;
339 linger.l_linger = 5;
340 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
341
342 #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
343 if (res->ai_family == AF_INET6) {
344 int on = 1;
345 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
346 &on, sizeof(on)) == -1) {
347 dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
348 }
349 }
350 #endif
351
352 set_sock_nodelay(sock);
353
354 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
355 err = errno;
356 close(sock);
357 TRACE(("bind(%s) failed", port))
358 continue;
359 }
360
361 if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
362 err = errno;
363 close(sock);
364 TRACE(("listen() failed"))
365 continue;
366 }
367
368 *maxfd = MAX(*maxfd, sock);
369
370 nsock++;
371 }
372
373 if (res0) {
374 freeaddrinfo(res0);
375 res0 = NULL;
376 }
377
378 if (nsock == 0) {
379 if (errstring != NULL && *errstring == NULL) {
380 int len;
381 len = 20 + strlen(strerror(err));
382 *errstring = (char*)m_malloc(len);
383 snprintf(*errstring, len, "Error listening: %s", strerror(err));
384 }
385 TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
386 return -1;
387 }
388
389 TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
390 return nsock;
391 }
392
393 /* Connect to a given unix socket. The socket is blocking */ 216 /* Connect to a given unix socket. The socket is blocking */
394 #ifdef ENABLE_CONNECT_UNIX 217 #ifdef ENABLE_CONNECT_UNIX
395 int connect_unix(const char* path) { 218 int connect_unix(const char* path) {
396 struct sockaddr_un addr; 219 struct sockaddr_un addr;
397 int fd = -1; 220 int fd = -1;
410 return -1; 233 return -1;
411 } 234 }
412 return fd; 235 return fd;
413 } 236 }
414 #endif 237 #endif
415
416 #if defined(__linux__) && defined(TCP_DEFER_ACCEPT)
417 static void set_piggyback_ack(int sock) {
418 /* Undocumented Linux feature - set TCP_DEFER_ACCEPT and data will be piggybacked
419 on the 3rd packet (ack) of the TCP handshake. Saves a IP packet.
420 http://thread.gmane.org/gmane.linux.network/224627/focus=224727
421 "Piggyback the final ACK of the three way TCP connection establishment with the data" */
422 int val = 1;
423 /* No error checking, this is opportunistic */
424 int err = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (void*)&val, sizeof(val));
425 if (err)
426 {
427 TRACE(("Failed setsockopt TCP_DEFER_ACCEPT: %s", strerror(errno)))
428 }
429 }
430 #endif
431
432
433 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
434 * return immediately if nonblocking is set. On failure, if errstring
435 * wasn't null, it will be a newly malloced error message */
436
437 /* TODO: maxfd */
438 int connect_remote(const char* remotehost, const char* remoteport, char ** errstring) {
439
440 struct addrinfo *res0 = NULL, *res = NULL, hints;
441 int sock;
442 int err;
443
444 TRACE(("enter connect_remote"))
445
446 if (errstring != NULL) {
447 *errstring = NULL;
448 }
449
450 memset(&hints, 0, sizeof(hints));
451 hints.ai_socktype = SOCK_STREAM;
452 hints.ai_family = PF_UNSPEC;
453
454 err = getaddrinfo(remotehost, remoteport, &hints, &res0);
455 if (err) {
456 if (errstring != NULL && *errstring == NULL) {
457 int len;
458 len = 100 + strlen(gai_strerror(err));
459 *errstring = (char*)m_malloc(len);
460 snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
461 remotehost, remoteport, gai_strerror(err));
462 }
463 TRACE(("Error resolving: %s", gai_strerror(err)))
464 return -1;
465 }
466
467 sock = -1;
468 err = EADDRNOTAVAIL;
469 for (res = res0; res; res = res->ai_next) {
470
471 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
472 if (sock < 0) {
473 err = errno;
474 continue;
475 }
476
477 setnonblocking(sock);
478
479 #if defined(__linux__) && defined(TCP_DEFER_ACCEPT)
480 set_piggyback_ack(sock);
481 #endif
482
483 if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
484 if (errno == EINPROGRESS) {
485 TRACE(("Connect in progress"))
486 break;
487 } else {
488 err = errno;
489 close(sock);
490 sock = -1;
491 continue;
492 }
493 }
494
495 break; /* Success */
496 }
497
498 if (sock < 0 && !(errno == EINPROGRESS)) {
499 /* Failed */
500 if (errstring != NULL && *errstring == NULL) {
501 int len;
502 len = 20 + strlen(strerror(err));
503 *errstring = (char*)m_malloc(len);
504 snprintf(*errstring, len, "Error connecting: %s", strerror(err));
505 }
506 TRACE(("Error connecting: %s", strerror(err)))
507 } else {
508 /* Success */
509 set_sock_nodelay(sock);
510 }
511
512 freeaddrinfo(res0);
513 if (sock > 0 && errstring != NULL && *errstring != NULL) {
514 m_free(*errstring);
515 }
516
517 TRACE(("leave connect_remote: sock %d\n", sock))
518 return sock;
519 }
520 238
521 /* Sets up a pipe for a, returning three non-blocking file descriptors 239 /* Sets up a pipe for a, returning three non-blocking file descriptors
522 * and the pid. exec_fn is the function that will actually execute the child process, 240 * and the pid. exec_fn is the function that will actually execute the child process,
523 * it will be run after the child has fork()ed, and is passed exec_data. 241 * it will be run after the child has fork()ed, and is passed exec_data.
524 * If ret_errfd == NULL then stderr will not be captured. 242 * If ret_errfd == NULL then stderr will not be captured.
649 for (i = 3; i <= maxfd; i++) { 367 for (i = 3; i <= maxfd; i++) {
650 m_close(i); 368 m_close(i);
651 } 369 }
652 370
653 execv(usershell, argv); 371 execv(usershell, argv);
654 }
655
656 void get_socket_address(int fd, char **local_host, char **local_port,
657 char **remote_host, char **remote_port, int host_lookup)
658 {
659 struct sockaddr_storage addr;
660 socklen_t addrlen;
661
662 if (local_host || local_port) {
663 addrlen = sizeof(addr);
664 if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
665 dropbear_exit("Failed socket address: %s", strerror(errno));
666 }
667 getaddrstring(&addr, local_host, local_port, host_lookup);
668 }
669 if (remote_host || remote_port) {
670 addrlen = sizeof(addr);
671 if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
672 dropbear_exit("Failed socket address: %s", strerror(errno));
673 }
674 getaddrstring(&addr, remote_host, remote_port, host_lookup);
675 }
676 }
677
678 /* Return a string representation of the socket address passed. The return
679 * value is allocated with malloc() */
680 void getaddrstring(struct sockaddr_storage* addr,
681 char **ret_host, char **ret_port,
682 int host_lookup) {
683
684 char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
685 unsigned int len;
686 int ret;
687
688 int flags = NI_NUMERICSERV | NI_NUMERICHOST;
689
690 #ifndef DO_HOST_LOOKUP
691 host_lookup = 0;
692 #endif
693
694 if (host_lookup) {
695 flags = NI_NUMERICSERV;
696 }
697
698 len = sizeof(struct sockaddr_storage);
699 /* Some platforms such as Solaris 8 require that len is the length
700 * of the specific structure. Some older linux systems (glibc 2.1.3
701 * such as debian potato) have sockaddr_storage.__ss_family instead
702 * but we'll ignore them */
703 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
704 if (addr->ss_family == AF_INET) {
705 len = sizeof(struct sockaddr_in);
706 }
707 #ifdef AF_INET6
708 if (addr->ss_family == AF_INET6) {
709 len = sizeof(struct sockaddr_in6);
710 }
711 #endif
712 #endif
713
714 ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
715 serv, sizeof(serv)-1, flags);
716
717 if (ret != 0) {
718 if (host_lookup) {
719 /* On some systems (Darwin does it) we get EINTR from getnameinfo
720 * somehow. Eew. So we'll just return the IP, since that doesn't seem
721 * to exhibit that behaviour. */
722 getaddrstring(addr, ret_host, ret_port, 0);
723 return;
724 } else {
725 /* if we can't do a numeric lookup, something's gone terribly wrong */
726 dropbear_exit("Failed lookup: %s", gai_strerror(ret));
727 }
728 }
729
730 if (ret_host) {
731 *ret_host = m_strdup(host);
732 }
733 if (ret_port) {
734 *ret_port = m_strdup(serv);
735 }
736 } 372 }
737 373
738 #ifdef DEBUG_TRACE 374 #ifdef DEBUG_TRACE
739 void printhex(const char * label, const unsigned char * buf, int len) { 375 void printhex(const char * label, const unsigned char * buf, int len) {
740 376
1057 693
1058 /* Fallback for everything else - this will sometimes go backwards */ 694 /* Fallback for everything else - this will sometimes go backwards */
1059 return time(NULL); 695 return time(NULL);
1060 } 696 }
1061 697
698