1 /*
2 * 6tunnel v0.13
3 * (C) Copyright 2000-2005,2013,2016,2019 by Wojtek Kaniewski <wojtekka@toxygen.net>
4 *
5 * Contributions by:
6 * - Dariusz Jackowski <ascent@linux.pl>
7 * - Ramunas Lukosevicius <lukoramu@parok.lt>
8 * - Roland Stigge <stigge@antcom.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License Version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <netdb.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <sys/select.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <ctype.h>
39 #include <pwd.h>
40 #include <time.h>
41
42 #define debug(x...) do { \
43 if (verbose) \
44 printf(x); \
45 } while(0)
46
47 int verbose = 0, conn_count = 0;
48 int remote_port, verbose, hexdump = 0;
49 int remote_hint[2] = { AF_INET6, AF_INET };
50 int local_hint = AF_INET;
51 char *remote_host, *irc_pass = NULL;
52 char *irc_send_pass = NULL;
53 char *pid_file = NULL;
54 const char *source_host;
55
56 typedef struct source_map {
57 char *ipv4;
58 char *ipv6;
59 struct source_map *next;
60 } source_map_t;
61
62 source_map_t *source_map = NULL;
63 char *source_map_file = NULL;
64
xmalloc(int size)65 char *xmalloc(int size)
66 {
67 char *tmp;
68
69 tmp = malloc(size);
70
71 if (tmp == NULL) {
72 perror("malloc");
73 exit(1);
74 }
75
76 return tmp;
77 }
78
xrealloc(char * ptr,int size)79 char *xrealloc(char *ptr, int size)
80 {
81 char *tmp;
82
83 tmp = realloc(ptr, size);
84
85 if (tmp == NULL) {
86 perror("realloc");
87 exit(1);
88 }
89
90 return tmp;
91 }
92
xstrdup(const char * str)93 char *xstrdup(const char *str)
94 {
95 char *tmp;
96
97 tmp = strdup(str);
98
99 if (tmp == NULL) {
100 perror("strdup");
101 exit(1);
102 }
103
104 return tmp;
105 }
106
xntop(const struct sockaddr * sa)107 char *xntop(const struct sockaddr *sa)
108 {
109 char *tmp = NULL;
110
111 if (sa->sa_family == AF_INET)
112 {
113 struct sockaddr_in *sin = (struct sockaddr_in*) sa;
114
115 tmp = xmalloc(INET_ADDRSTRLEN);
116
117 if (inet_ntop(sa->sa_family, &sin->sin_addr, tmp, INET_ADDRSTRLEN) == NULL)
118 {
119 free(tmp);
120 tmp = NULL;
121 }
122 }
123 else if (sa->sa_family == AF_INET6)
124 {
125 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*) sa;
126 tmp = xmalloc(INET6_ADDRSTRLEN);
127
128 if (inet_ntop(sa->sa_family, &sin6->sin6_addr, tmp, INET6_ADDRSTRLEN) == NULL)
129 {
130 free(tmp);
131 tmp = NULL;
132 }
133 }
134
135 return tmp;
136 }
137
resolve_host(const char * name,int port,int hint)138 struct addrinfo *resolve_host(const char *name, int port, int hint)
139 {
140 struct addrinfo *result = NULL;
141 struct addrinfo hints;
142 char port_str[16];
143 int rc;
144
145 snprintf(port_str, sizeof(port_str), "%u", port);
146
147 memset(&hints, 0, sizeof(hints));
148 hints.ai_family = hint;
149 hints.ai_socktype = SOCK_STREAM;
150 hints.ai_flags = (name == NULL && port != 0) ? AI_PASSIVE : 0;
151
152 rc = getaddrinfo(name, (port != 0) ? port_str : NULL, &hints, &result);
153
154 if (rc == 0)
155 return result;
156
157 debug("resolver %s port %d hint %d failed: %s\n", name, port, hint, gai_strerror(rc));
158
159 return NULL;
160 }
161
print_hexdump(const char * buf,int len)162 void print_hexdump(const char *buf, int len)
163 {
164 int i, j;
165
166 for (i = 0; i < ((len / 16) + ((len % 16) ? 1 : 0)); i++) {
167 printf("%.4x: ", i * 16);
168
169 for (j = 0; j < 16; j++) {
170 if (i * 16 + j < len)
171 printf("%.2x ", buf[i*16+j]);
172 else
173 printf(" ");
174 if (j == 7)
175 printf(" ");
176 }
177
178 printf(" ");
179
180 for (j = 0; j < 16; j++) {
181 if (i * 16 + j < len) {
182 char ch = buf[i * 16 + j];
183
184 printf("%c", (isprint(ch)) ? ch : '.');
185 }
186 }
187
188 printf("\n");
189 }
190 }
191
source_map_find(const char * ipv4)192 const char *source_map_find(const char *ipv4)
193 {
194 source_map_t *m;
195
196 for (m = source_map; m != NULL; m = m->next) {
197 if (strcmp(m->ipv4, ipv4) == 0)
198 return m->ipv6;
199 }
200
201 for (m = source_map; m != NULL; m = m->next) {
202 if ((strcmp(m->ipv4, "0.0.0.0") == 0) || (strcmp(m->ipv4, "default") == 0))
203 return m->ipv6;
204 }
205
206 return source_host;
207 }
208
make_tunnel(int rsock,const char * client_addr)209 void make_tunnel(int rsock, const char *client_addr)
210 {
211 char buf[4096], *outbuf = NULL, *inbuf = NULL;
212 int sock = -1, outlen = 0, inlen = 0;
213 struct sockaddr *sa = NULL;
214 const char *source;
215 struct addrinfo *connect_ai = NULL;
216 struct addrinfo *bind_ai = NULL;
217 struct addrinfo *ai_ptr;
218 int source_hint;
219
220 if (source_map != NULL) {
221 source = source_map_find(client_addr);
222
223 if (source == NULL) {
224 debug("<%d> connection from unmapped address (%s), disconnecting\n", rsock, client_addr);
225 goto cleanup;
226 }
227
228 debug("<%d> mapped to %s\n", rsock, source);
229 } else
230 source = source_host;
231
232 if (irc_pass != NULL) {
233 int i, ret;
234
235 for (i = 0; i < sizeof(buf) - 1; i++) {
236 if ((ret = read(rsock, buf + i, 1)) < 1)
237 goto cleanup;
238 if (buf[i] == '\n')
239 break;
240 }
241
242 buf[i] = 0;
243
244 if (i > 0 && buf[i - 1] == '\r')
245 buf[i - 1] = 0;
246
247 if (i == 4095 || strncasecmp(buf, "PASS ", 5) != 0) {
248 char *tmp;
249
250 debug("<%d> irc proxy auth failed - junk\n", rsock);
251
252 tmp = "ERROR :Closing link: Make your client send password first\r\n";
253 if (write(rsock, tmp, strlen(tmp)) != strlen(tmp)) {
254 // Do nothing. We're failing anyway.
255 }
256
257 goto cleanup;
258 }
259
260 if (strcmp(buf + 5, irc_pass) != 0) {
261 char *tmp;
262
263 debug("<%d> irc proxy auth failed - password incorrect\n", rsock);
264 tmp = ":6tunnel 464 * :Password incorrect\r\nERROR :Closing link: Password incorrect\r\n";
265 if (write(rsock, tmp, strlen(tmp)) != strlen(tmp)) {
266 // Do nothing. We're failing anyway.
267 }
268
269 goto cleanup;
270 }
271
272 debug("<%d> irc proxy auth succeeded\n", rsock);
273 }
274
275 connect_ai = resolve_host(remote_host, remote_port, remote_hint[0]);
276
277 if (connect_ai == NULL) {
278 connect_ai = resolve_host(remote_host, remote_port, remote_hint[1]);
279
280 if (connect_ai == NULL) {
281 debug("<%d> unable to resolve %s,%d\n", rsock, remote_host, remote_port);
282 goto cleanup;
283 }
284
285 source_hint = remote_hint[1];
286 } else {
287 source_hint = remote_hint[0];
288 }
289
290 for (ai_ptr = connect_ai; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
291 sock = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, 0);
292
293 if (sock == -1) {
294 if (ai_ptr->ai_next != NULL)
295 continue;
296 debug("<%d> unable to create socket (%s)\n", rsock, strerror(errno));
297 goto cleanup;
298 }
299
300 if (source != NULL)
301 {
302 bind_ai = resolve_host(source, 0, source_hint);
303
304 if (bind_ai == NULL) {
305 debug("<%d> unable to resolve source host (%s)\n", rsock, (source != NULL) ? source : "default");
306 goto cleanup;
307 }
308
309 if (bind(sock, bind_ai->ai_addr, bind_ai->ai_addrlen) == -1) {
310 if (ai_ptr->ai_next != NULL) {
311 close(sock);
312 sock = -1;
313 continue;
314 }
315 debug("<%d> unable to bind to source host (%s)\n", rsock, (source != NULL) ? source : "default");
316 goto cleanup;
317 }
318
319 freeaddrinfo(bind_ai);
320 bind_ai = NULL;
321 }
322
323 if (connect(sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen) != -1)
324 break;
325
326 if (ai_ptr->ai_next == NULL) {
327 debug("<%d> connection failed (%s,%d)\n", rsock, remote_host, remote_port);
328 goto cleanup;
329 }
330
331 close(sock);
332 sock = -1;
333 }
334
335 freeaddrinfo(connect_ai);
336 connect_ai = NULL;
337
338 debug("<%d> connected to %s,%d\n", rsock, remote_host, remote_port);
339
340 if (irc_send_pass != NULL) {
341 snprintf(buf, sizeof(buf), "PASS %s\r\n", irc_send_pass);
342 if (write(sock, buf, strlen(buf)) != strlen(buf))
343 goto cleanup;
344 }
345
346 for (;;) {
347 fd_set rds, wds;
348 int ret, sent;
349
350 FD_ZERO(&rds);
351 FD_SET(sock, &rds);
352 FD_SET(rsock, &rds);
353
354 FD_ZERO(&wds);
355 if (outbuf && outlen)
356 FD_SET(rsock, &wds);
357 if (inbuf && inlen)
358 FD_SET(sock, &wds);
359
360 ret = select((sock > rsock) ? (sock + 1) : (rsock + 1), &rds, &wds, NULL, NULL);
361
362 if (FD_ISSET(rsock, &wds)) {
363 sent = write(rsock, outbuf, outlen);
364
365 if (sent < 1)
366 goto cleanup;
367
368 if (sent == outlen) {
369 free(outbuf);
370 outbuf = NULL;
371 outlen = 0;
372 } else {
373 memmove(outbuf, outbuf + sent, outlen - sent);
374 outlen -= sent;
375 }
376 }
377
378 if (FD_ISSET(sock, &wds)) {
379 sent = write(sock, inbuf, inlen);
380
381 if (sent < 1)
382 goto cleanup;
383
384 if (sent == inlen) {
385 free(inbuf);
386 inbuf = NULL;
387 inlen = 0;
388 } else {
389 memmove(inbuf, inbuf + sent, inlen - sent);
390 inlen -= sent;
391 }
392 }
393
394 if (FD_ISSET(sock, &rds)) {
395 if ((ret = read(sock, buf, sizeof(buf))) < 1)
396 goto cleanup;
397
398 if (hexdump) {
399 printf("<%d> recvfrom %s,%d\n", rsock, remote_host, remote_port);
400 print_hexdump(buf, ret);
401 }
402
403 sent = write(rsock, buf, ret);
404
405 if (sent < 1)
406 goto cleanup;
407
408 if (sent < ret) {
409 outbuf = xrealloc(outbuf, outlen + ret - sent);
410 memcpy(outbuf + outlen, buf + sent, ret - sent);
411 outlen = ret - sent;
412 }
413 }
414
415 if (FD_ISSET(rsock, &rds)) {
416 if ((ret = read(rsock, buf, sizeof(buf))) < 1)
417 goto cleanup;
418
419 if (hexdump) {
420 printf("<%d> sendto %s,%d\n", rsock, remote_host, remote_port);
421 print_hexdump(buf, ret);
422 }
423
424 sent = write(sock, buf, ret);
425
426 if (sent < 1)
427 goto cleanup;
428
429 if (sent < ret) {
430 inbuf = xrealloc(inbuf, inlen + ret - sent);
431 memcpy(inbuf + inlen, buf + sent, ret - sent);
432 inlen = ret - sent;
433 }
434 }
435 }
436
437 cleanup:
438 if (connect_ai != NULL)
439 freeaddrinfo(connect_ai);
440
441 if (bind_ai != NULL)
442 freeaddrinfo(bind_ai);
443
444 close(rsock);
445
446 if (sock != -1)
447 close(sock);
448 }
449
usage(const char * arg0)450 void usage(const char *arg0)
451 {
452 fprintf(stderr,
453
454 "usage: %s [-146dvh] [-s sourcehost] [-l localhost] [-i pass]\n"
455 " [-I pass] [-L limit] [-A filename] [-p pidfile]\n"
456 " [-m mapfile] localport remotehost [remoteport]\n"
457 "\n"
458 " -1 allow only single connection and quit\n"
459 " -4 connect to IPv4 endpoints (default: connect to IPv6)\n"
460 " -6 bind to IPv6 address (default: bind to IPv4)\n"
461 " -d don't detach\n"
462 " -f force tunneling (even if remotehost isn't resolvable)\n"
463 " -h print hex dump of packets\n"
464 " -u change UID and GID after bind()\n"
465 " -i act like irc proxy and ask for password\n"
466 " -I send specified password to the irc server\n"
467 " -l bind to specified address\n"
468 " -L limit simultaneous connections\n"
469 " -p write down pid to specified file\n"
470 " -s connect using specified address\n"
471 " -m read specified IPv4-to-IPv6 map file\n"
472 " -v be verbose\n"
473 "\n", arg0);
474 }
475
clear_argv(char * argv)476 void clear_argv(char *argv)
477 {
478 int x;
479
480 for (x = 0; x < strlen(argv); x++)
481 argv[x] = 'x';
482
483 return;
484 }
485
source_map_destroy(void)486 void source_map_destroy(void)
487 {
488 source_map_t *m;
489
490 debug("source_map_destroy()\n");
491
492 for (m = source_map; m != NULL; ) {
493 source_map_t *n;
494
495 free(m->ipv4);
496 free(m->ipv6);
497 n = m;
498 m = m->next;
499 free(n);
500 }
501
502 source_map = NULL;
503 }
504
map_read(void)505 void map_read(void)
506 {
507 char buf[256];
508 FILE *f;
509
510 debug("reading map from %s\n", source_map_file);
511
512 f = fopen(source_map_file, "r");
513
514 if (f == NULL) {
515 debug("unable to read map file, ignoring\n");
516 return;
517 }
518
519 while (fgets(buf, sizeof(buf), f) != NULL) {
520 char *p, *ipv4, *ipv6;
521 source_map_t *m;
522
523 for (p = buf; *p == ' ' || *p == '\t'; p++);
524
525 if (!*p)
526 continue;
527
528 ipv4 = p;
529
530 for (; *p && *p != ' ' && *p != '\t'; p++);
531
532 if (!*p)
533 continue;
534
535 *p = 0;
536 p++;
537
538 for (; *p == ' ' || *p == '\t'; p++);
539
540 if (!*p)
541 continue;
542
543 ipv6 = p;
544
545 for (; *p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n'; p++);
546
547 *p = 0;
548
549 debug("[%s] mapped to [%s]\n", ipv4, ipv6);
550
551 m = (source_map_t*) xmalloc(sizeof(source_map_t));
552 m->ipv4 = xstrdup(ipv4);
553 m->ipv6 = xstrdup(ipv6);
554 m->next = source_map;
555 source_map = m;
556 }
557
558 fclose(f);
559 }
560
sighup()561 void sighup()
562 {
563 source_map_destroy();
564 map_read();
565
566 signal(SIGHUP, sighup);
567 }
568
sigchld()569 void sigchld()
570 {
571 while (waitpid(-1, NULL, WNOHANG) > 0) {
572 debug("child process exited\n");
573 conn_count--;
574 }
575
576 signal(SIGCHLD, sigchld);
577 }
578
sigterm()579 void sigterm()
580 {
581 if (pid_file != NULL)
582 unlink(pid_file);
583
584 exit(0);
585 }
586
main(int argc,char ** argv)587 int main(int argc, char **argv)
588 {
589 int force = 0, listen_fd, single_connection = 0, jeden = 1, local_port;
590 int detach = 1, sa_len, conn_limit = 0, optc;
591 const char *username = NULL;
592 char *local_host = NULL;
593 struct addrinfo *ai;
594 struct addrinfo *ai_ptr;
595 struct sockaddr *sa;
596 struct sockaddr_in laddr;
597 struct sockaddr_in6 laddr6;
598 struct passwd *pw = NULL;
599 char *tmp;
600 int source_hint;
601
602 while ((optc = getopt(argc, argv, "1dv46fHs:l:I:i:hu:m:L:A:p:")) != -1) {
603 switch (optc) {
604 case '1':
605 single_connection = 1;
606 break;
607 case 'd':
608 detach = 0;
609 break;
610 case 'v':
611 verbose = 1;
612 break;
613 case '4':
614 remote_hint[0] = AF_INET;
615 remote_hint[1] = AF_INET6;
616 break;
617 case '6':
618 local_hint = AF_INET6;
619 break;
620 case 's':
621 source_host = optarg;
622 break;
623 case 'l':
624 local_host = optarg;
625 break;
626 case 'f':
627 force = 1;
628 break;
629 case 'i':
630 irc_pass = xstrdup(optarg);
631 clear_argv(argv[optind - 1]);
632 break;
633 case 'I':
634 irc_send_pass = xstrdup(optarg);
635 clear_argv(argv[optind - 1]);
636 break;
637 case 'h':
638 hexdump = 1;
639 break;
640 case 'u':
641 username = optarg;
642 break;
643 case 'm':
644 source_map_file = optarg;
645 break;
646 case 'L':
647 conn_limit = atoi(optarg);
648 break;
649 case 'p':
650 pid_file = optarg;
651 break;
652 case 'H':
653 fprintf(stderr, "%s: warning: -H is deprecated, please use proper combination of -4 and -6.\n", argv[0]);
654 break;
655 default:
656 return 1;
657 }
658 }
659
660 if (hexdump)
661 verbose = 1;
662
663 if (verbose)
664 detach = 0;
665
666 if (detach)
667 verbose = 0;
668
669 if (argc - optind < 2) {
670 usage(argv[0]);
671 exit(1);
672 }
673
674 if (username != NULL) {
675 pw = getpwnam(username);
676
677 if (pw == NULL) {
678 fprintf(stderr, "%s: unknown user %s\n", argv[0], username);
679 exit(1);
680 }
681 }
682
683 if (source_map_file != NULL)
684 map_read();
685
686 local_port = atoi(argv[optind++]);
687 remote_host = argv[optind++];
688 remote_port = (argc == optind) ? local_port : atoi(argv[optind]);
689
690 /* Check if destination and source hosts are resolvable. If it's expected to be
691 * available later, -f can be used. */
692
693 debug("resolving %s\n", remote_host);
694
695 ai = resolve_host(remote_host, remote_port, remote_hint[0]);
696
697 if (ai == NULL) {
698 ai = resolve_host(remote_host, remote_port, remote_hint[1]);
699
700 if (ai == NULL && !force) {
701 fprintf(stderr, "%s: unable to resolve host %s\n", argv[0], remote_host);
702 exit(1);
703 }
704
705 source_hint = remote_hint[1];
706 } else {
707 source_hint = remote_hint[0];
708 }
709
710 if (ai != NULL) {
711
712 if (source_hint == AF_INET && local_hint == AF_INET)
713 fprintf(stderr, "%s: warning: both local and remote addresses are IPv4\n", argv[0]);
714
715 if (source_hint == AF_INET6 && local_hint == AF_INET6)
716 fprintf(stderr, "%s: warning: both local and remote addresses are IPv6\n", argv[0]);
717
718 tmp = xntop(ai->ai_addr);
719 debug("resolved to %s\n", tmp);
720 free(tmp);
721
722 freeaddrinfo(ai);
723 }
724
725 if (source_host != NULL) {
726 debug("resolving %s\n", source_host);
727
728 ai = resolve_host(source_host, 0, source_hint);
729
730 if (ai == NULL && !force) {
731 fprintf(stderr, "%s: unable to resolve host %s\n", argv[0], source_host);
732 exit(1);
733 }
734
735 tmp = xntop(ai->ai_addr);
736 debug("resolved to %s\n", tmp);
737 free(tmp);
738
739 freeaddrinfo(ai);
740 }
741
742 /* Resolve local address for bind(). In case of NULL address resolve_host() will
743 * return INADDR_ANY or in6addr_any, so we can bind either way. */
744
745 debug("resolving local address %s\n", (local_host != NULL) ? local_host : "default");
746
747 ai = resolve_host(local_host, local_port, local_hint);
748
749 if (ai == NULL) {
750 fprintf(stderr, "%s: unable to resolve host %s\n", argv[0], local_host);
751 exit(1);
752 }
753
754 tmp = xntop(ai->ai_addr);
755 debug("resolved to %s\n", tmp);
756 free(tmp);
757
758 /* Now that we know that hosts are resolvable, dump some debugging information. */
759
760 debug("local: %s,%d; ", (local_host != NULL) ? local_host : "default", local_port);
761 debug("remote: %s,%d; ", remote_host, remote_port);
762
763 if (source_map != NULL)
764 debug("source: mapped\n");
765 else
766 debug("source: %s\n", (source_host != NULL) ? source_host : "default");
767
768 /* Now bind. */
769
770 listen_fd = socket(ai->ai_family, ai->ai_socktype, 0);
771
772 if (listen_fd == -1) {
773 perror("socket");
774 exit(1);
775 }
776
777 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &jeden, sizeof(jeden)) == -1) {
778 perror("setsockopt");
779 exit(1);
780 }
781
782 for (ai_ptr = ai; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
783 if (bind(listen_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen) == -1 && ai_ptr->ai_next == NULL) {
784 perror("bind");
785 exit(1);
786 }
787 }
788
789 if (listen(listen_fd, 100) == -1) {
790 perror("listen");
791 exit(1);
792 }
793
794 freeaddrinfo(ai);
795 ai = NULL;
796
797 /* Daemonize. */
798
799 if (detach) {
800 int i, ret;
801
802 signal(SIGHUP, sighup);
803
804 for (i = 0; i < 3; i++)
805 close(i);
806
807 ret = fork();
808
809 if (ret == -1) {
810 perror("fork");
811 exit(1);
812 }
813
814 if (ret)
815 exit(0);
816 }
817
818 /* Store process id if requested. */
819
820 if (pid_file != NULL) {
821 FILE *f = fopen(pid_file, "w");
822
823 if (!f)
824 debug("warning: cannot write to pidfile (%s)\n", strerror(errno));
825 else {
826 fprintf(f, "%d", getpid());
827 fclose(f);
828 }
829 }
830
831 /* Change user and group id if requested. */
832
833 if (pw != NULL) {
834 if ((setgid(pw->pw_gid) == -1) || (setuid(pw->pw_uid) == -1)) {
835 perror("setuid/setgid");
836 exit(1);
837 }
838 }
839
840 setsid();
841 signal(SIGCHLD, sigchld);
842 signal(SIGTERM, sigterm);
843 signal(SIGINT, sigterm);
844 signal(SIGHUP, sighup);
845
846 for (;;) {
847 int ret;
848 fd_set rds;
849 int client_fd;
850 char *client_addr;
851 int client_port;
852 struct sockaddr sa;
853 unsigned int sa_len = sizeof(sa);
854
855 FD_ZERO(&rds);
856 FD_SET(listen_fd, &rds);
857
858 if (select(listen_fd + 1, &rds, NULL, NULL, NULL) == -1) {
859 if (errno == EINTR)
860 continue;
861
862 perror("select");
863 break;
864 }
865
866 client_fd = accept(listen_fd, &sa, &sa_len);
867
868 if (client_fd == -1) {
869 perror("accept");
870 break;
871 }
872
873 client_addr = xntop(&sa);
874
875 client_port = (sa.sa_family == AF_INET) ? ((struct sockaddr_in*) &sa)->sin_port :
876 ((struct sockaddr_in6*) &sa)->sin6_port;
877
878 debug("<%d> connection from %s,%d", client_fd, client_addr, ntohs(client_port));
879
880 if (conn_limit && (conn_count >= conn_limit)) {
881 debug(" -- rejected due to limit.\n");
882 shutdown(client_fd, 2);
883 close(client_fd);
884 continue;
885 }
886
887 if (conn_limit) {
888 conn_count++;
889 debug(" (no. %d)", conn_count);
890 }
891
892 fflush(stdout);
893
894 if ((ret = fork()) == -1) {
895 debug(" -- fork() failed.\n");
896 shutdown(client_fd, 2);
897 close(client_fd);
898 free(client_addr);
899 continue;
900 }
901
902 if (!ret) {
903 signal(SIGHUP, SIG_IGN);
904 close(listen_fd);
905 debug("\n");
906 make_tunnel(client_fd, client_addr);
907 free(client_addr);
908 debug("<%d> connection closed\n", client_fd);
909 exit(0);
910 }
911
912 close(client_fd);
913 free(client_addr);
914
915 if (single_connection) {
916 shutdown(listen_fd, 2);
917 close(listen_fd);
918 exit(0);
919 }
920
921 }
922
923 close(listen_fd);
924
925 exit(1);
926 }
927