1 /*
2 main.c:
3 $Id: main.c,v 1.29 2017/09/06 13:35:01 bulkstream Exp $
4
5 Copyright (C) 2001-2010 Tomo.M (author).
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. Neither the name of the author nor the names of its contributors
18 may be used to endorse or promote products derived from this software
19 without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 */
34
35 #include <sys/stat.h>
36 #include "srelay.h"
37
38 /* prototypes */
39 void show_version __P((void));
40 void usage __P((void));
41 int serv_loop __P((void));
42 int validate_access __P((CL_INFO *));
43
44 char *config = CONFIG;
45 char *ident = "srelay";
46 char *pidfile = PIDFILE;
47 char *pwdfile = NULL;
48 char *localpwd = NULL;
49 char *bindtodevice = NULL;
50 pid_t master_pid;
51
52 #if USE_THREAD
53 pthread_t main_thread;
54 int max_thread;
55 int threading;
56 #endif
57
58 int same_interface = 0;
59
60 #ifdef HAVE_LIBWRAP
61 int use_tcpwrap = 0;
62 # include <tcpd.h>
63 # ifdef LINUX
64 int allow_severity = LOG_AUTH|LOG_INFO;
65 int deny_severity = LOG_AUTH|LOG_NOTICE;
66 # endif /* LINUX */
67 extern int hosts_ctl __P((char *, char *, char *, char *));
68 #endif /* HAVE_LIBWRAP */
69
70 int max_child;
71 int cur_child;
72
73 int fg; /* foreground operation */
74 int inetd_mode = 0; /* inetd mode */
75 int bind_restrict = 1; /* socks bind port is restricted */
76
77 /* authentication method priority table */
78 int method_num;
79 char method_tab[MAX_AUTH_METH+1];
80
81 int verbosity = 0;
82
show_version()83 void show_version()
84 {
85 fprintf(stderr, "%s\n", version);
86 }
87
usage()88 void usage()
89 {
90 show_version();
91 fprintf(stderr, "usage: %s [options]\n",
92 ident);
93 fprintf(stderr, "options:\n"
94 "\t-c file\tconfig file\n"
95 "\t-i i/f\tlisten interface IP[:PORT]\n"
96 #ifdef SO_BINDTODEVICE
97 "\t-J i/f\toutbound interface name\n"
98 #endif
99 "\t-m num\tmax child/thread\n"
100 "\t-o min\tidle timeout minutes\n"
101 "\t-p file\tpid file\n"
102 "\t-a np\tauth methods n: no, p:pass\n"
103 "\t-u file\tsrelay password file\n"
104 "\t-U file\tsrelay local user base file\n"
105 "\t-f\trun into foreground\n"
106 "\t-r\tresolve client name in log\n"
107 "\t-s\tforce logging to syslog\n"
108 "\t-t\tdisable threading\n"
109 "\t-b\tavoid BIND port restriction\n"
110 "\t-g\tuse the same interface for outbound as inbound\n"
111 #ifdef HAVE_LIBWRAP
112 "\t-w\tuse tcp_wrapper access control\n"
113 #endif /* HAVE_LIBWRAP */
114 "\t-I\tinetd mode\n"
115 "\t-q\twill be quiet\n"
116 "\t-v\tincrease verbosity\n"
117 "\t-V\tshow version and exit\n"
118 "\t-h\tshow this help and exit\n");
119 exit(1);
120 }
121
signal_setup()122 void signal_setup()
123 {
124
125 setsignal(SIGHUP, reload);
126 if (!isatty(fileno(stdin))) {
127 setsignal(SIGINT, SIG_IGN);
128 }
129 setsignal(SIGQUIT, SIG_IGN);
130 setsignal(SIGILL, SIG_IGN);
131 setsignal(SIGTRAP, SIG_IGN);
132 setsignal(SIGABRT, SIG_IGN);
133 #ifdef SIGEMT
134 setsignal(SIGEMT, SIG_IGN);
135 #endif
136 setsignal(SIGFPE, SIG_IGN);
137 setsignal(SIGBUS, SIG_IGN);
138 setsignal(SIGSEGV, SIG_IGN);
139 setsignal(SIGSYS, SIG_IGN);
140 setsignal(SIGPIPE, SIG_IGN);
141 setsignal(SIGALRM, SIG_IGN);
142 setsignal(SIGTERM, cleanup);
143 setsignal(SIGUSR1, SIG_IGN);
144 setsignal(SIGUSR2, SIG_IGN);
145 #ifdef SIGPOLL
146 setsignal(SIGPOLL, SIG_IGN);
147 #endif
148 setsignal(SIGVTALRM, SIG_IGN);
149 setsignal(SIGPROF, SIG_IGN);
150 setsignal(SIGXCPU, SIG_IGN);
151 setsignal(SIGXFSZ, SIG_IGN);
152
153 }
154
validate_access(CL_INFO * client)155 int validate_access(CL_INFO *client)
156 {
157 int stat = 0;
158 #ifdef HAVE_LIBWRAP
159 int i;
160
161 if ( use_tcpwrap ) {
162 /* proc ident pattern */
163 stat = hosts_ctl(ident, client->name, client->addr, STRING_UNKNOWN);
164 /* IP.PORT pattern */
165 for (i = 0; i < serv_sock_ind; i++) {
166 if (str_serv_sock[i] != NULL && str_serv_sock[i][0] != 0) {
167 stat |= hosts_ctl(str_serv_sock[i],
168 client->name, client->addr, STRING_UNKNOWN);
169 }
170 }
171 } else {
172 #endif /* HAVE_LIBWRAP */
173 stat = 1; /* allow access un-conditionaly */
174 #ifdef HAVE_LIBWRAP
175 }
176 #endif /* HAVE_LIBWRAP */
177
178 if (stat < 1) {
179 msg_out(warn, "%s[%s] access denied.", client->name, client->addr);
180 }
181
182 return stat;
183 }
184
185 #ifdef USE_THREAD
186 pthread_mutex_t mutex_select;
187 #endif
188
serv_loop()189 int serv_loop()
190 {
191
192 SOCKS_STATE state;
193 SOCK_INFO si;
194 CL_INFO client;
195
196 int cs;
197 fd_set readable;
198 int i, n, len;
199 int error;
200 pid_t pid;
201
202 memset(&state, 0, sizeof(state));
203 memset(&si, 0, sizeof(si));
204 memset(&client, 0, sizeof(client));
205 state.si = &si;
206
207 #ifdef USE_THREAD
208 if (threading) {
209 blocksignal(SIGHUP);
210 }
211 #endif
212
213 for (;;) {
214 readable = allsock;
215
216 MUTEX_LOCK(mutex_select);
217 n = select(maxsock+1, &readable, 0, 0, 0);
218 if (n <= 0) {
219 if (n < 0 && errno != EINTR) {
220 msg_out(warn, "select: %m");
221 }
222 MUTEX_UNLOCK(mutex_select);
223 continue;
224 }
225
226 #ifdef USE_THREAD
227 if ( ! threading ) {
228 #endif
229 /* handle any queued signal flags */
230 if (FD_ISSET(sig_queue[0], &readable)) {
231 if (ioctl(sig_queue[0], FIONREAD, &i) != 0) {
232 msg_out(crit, "ioctl: %m");
233 exit(-1);
234 }
235 while (--i >= 0) {
236 char c;
237 if (read(sig_queue[0], &c, 1) != 1) {
238 msg_out(crit, "read: %m");
239 exit(-1);
240 }
241 switch(c) {
242 case 'H': /* sighup */
243 reload();
244 break;
245 case 'C': /* sigchld */
246 reapchild();
247 break;
248 case 'T': /* sigterm */
249 cleanup();
250 break;
251 default:
252 break;
253 }
254 }
255 }
256 #ifdef USE_THREAD
257 }
258 #endif
259
260 for ( i = 0; i < serv_sock_ind; i++ ) {
261 if (FD_ISSET(serv_sock[i], &readable)) {
262 n--;
263 break;
264 }
265 }
266 if ( n < 0 || i >= serv_sock_ind ) {
267 MUTEX_UNLOCK(mutex_select);
268 continue;
269 }
270
271 len = SS_LEN;
272 cs = accept(serv_sock[i], &si.prc.addr.sa, (socklen_t *)&len);
273 si.prc.len = len;
274 if (cs < 0) {
275 if (errno == EINTR
276 #ifdef SOLARIS
277 || errno == EPROTO
278 #endif
279 || errno == EWOULDBLOCK
280 || errno == ECONNABORTED) {
281 ; /* ignore */
282 } else {
283 /* real accept error */
284 msg_out(warn, "accept: %m");
285 }
286 MUTEX_UNLOCK(mutex_select);
287 continue;
288 }
289 MUTEX_UNLOCK(mutex_select);
290
291 #ifdef USE_THREAD
292 if ( !threading ) {
293 #endif
294 if (max_child > 0 && cur_child >= max_child) {
295 msg_out(warn, "child: cur %d; exeedeing max(%d)",
296 cur_child, max_child);
297 close(cs);
298 continue;
299 }
300 #ifdef USE_THREAD
301 }
302 #endif
303
304 /* get downstream-side socket name */
305 len = SS_LEN;
306 getsockname(cs, &si.myc.addr.sa, (socklen_t *)&len);
307 si.myc.len = len;
308
309 error = getnameinfo(&si.prc.addr.sa, si.prc.len,
310 client.addr, sizeof(client.addr),
311 NULL, 0,
312 NI_NUMERICHOST);
313 if (resolv_client) {
314 error = getnameinfo(&si.prc.addr.sa, si.prc.len,
315 client.name, sizeof(client.name),
316 NULL, 0, 0);
317 msg_out(norm, "%s[%s] connected", client.name, client.addr);
318 } else {
319 msg_out(norm, "%s connected", client.addr);
320 strncpy(client.name, client.addr, sizeof(client.name));
321 }
322
323 i = validate_access(&client);
324 if (i < 1) {
325 /* access denied */
326 close(cs);
327 continue;
328 }
329
330 set_blocking(cs);
331 state.s = cs;
332
333 #ifdef USE_THREAD
334 if (!threading ) {
335 #endif
336 blocksignal(SIGHUP);
337 blocksignal(SIGCHLD);
338 pid = fork();
339 switch (pid) {
340 case -1: /* fork child failed */
341 break;
342 case 0: /* i am child */
343 for ( i = 0; i < serv_sock_ind; i++ ) {
344 close(serv_sock[i]);
345 }
346 setsignal(SIGCHLD, SIG_DFL);
347 setsignal(SIGHUP, SIG_DFL);
348 releasesignal(SIGCHLD);
349 releasesignal(SIGHUP);
350 error = proto_socks(&state);
351 if ( error == -1 ) {
352 close(state.s); /* may already be closed */
353 exit(1);
354 }
355 relay(&state);
356 exit(0);
357 default: /* may be parent */
358 proclist_add(pid);
359 break;
360 }
361 close(state.s);
362 releasesignal(SIGHUP);
363 releasesignal(SIGCHLD);
364 #ifdef USE_THREAD
365 } else {
366 error = proto_socks(&state);
367 if ( error == -1 ) {
368 close(state.s); /* may already be closed */
369 /* udp may be dynamically allocated */
370 if (state.sr.udp != NULL)
371 free(state.sr.udp);
372 if (state.prx != NULL) {
373 free(state.prx);
374 state.prx = NULL;
375 }
376 continue;
377 }
378 relay(&state);
379 }
380 #endif
381 }
382 }
383
inetd_service(int cs)384 int inetd_service(int cs)
385 {
386 SOCKS_STATE state;
387 SOCK_INFO si;
388 CL_INFO client;
389 int len;
390 int error;
391
392 memset(&state, 0, sizeof(state));
393 memset(&si, 0, sizeof(si));
394 state.si = &si;
395
396 signal_setup();
397
398 /* get downstream-side socket name */
399 len = SS_LEN;
400 getsockname(cs, &si.myc.addr.sa, (socklen_t *)&len);
401 si.myc.len = len;
402
403 /* get downstream-side peer name */
404 len = SS_LEN;
405 getpeername(cs, &si.prc.addr.sa, (socklen_t *)&len);
406 si.prc.len = len;
407
408 error = getnameinfo(&si.prc.addr.sa, si.prc.len,
409 client.addr, sizeof(client.addr),
410 NULL, 0,
411 NI_NUMERICHOST);
412 if (resolv_client) {
413 error = getnameinfo(&si.prc.addr.sa, si.prc.len,
414 client.name, sizeof(client.name),
415 NULL, 0, 0);
416 msg_out(norm, "%s[%s] connected", client.name, client.addr);
417 } else {
418 msg_out(norm, "%s connected", client.addr);
419 strncpy(client.name, client.addr, sizeof(client.name));
420 }
421
422 set_blocking(cs);
423 state.s = cs;
424
425 error = proto_socks(&state);
426 if (error == -1) {
427 msg_out(warn, "socks proto error");
428 close(state.s);
429 if (state.sr.udp != NULL)
430 free(state.sr.udp);
431 return(-1);
432 }
433 /* start relaying */
434 relay(&state);
435 close(cs);
436 return(0);
437 }
438
main(int ac,char ** av)439 int main(int ac, char **av)
440 {
441 int ch, i=0;
442 char *p;
443 pid_t pid;
444 FILE *fp;
445 uid_t uid;
446 #ifdef USE_THREAD
447 pthread_t tid;
448 pthread_attr_t attr;
449 struct rlimit rl;
450 rlim_t max_fd = (rlim_t)MAX_FD;
451 rlim_t save_fd = 0;
452 #endif
453
454 #ifdef USE_THREAD
455 threading = 1;
456 max_thread = MAX_THREAD;
457 #endif
458
459 max_child = MAX_CHILD;
460 cur_child = 0;
461
462 /* create service socket table (malloc) */
463 if (serv_init(NULL) < 0) {
464 msg_out(crit, "cannot malloc: %m\n");
465 exit(-1);
466 }
467
468 proxy_tbl = NULL;
469 num_routes = 0;
470
471 method_num = 0;
472 method_tab[0] = '\0';
473
474 uid = getuid();
475
476 openlog(ident, LOG_PID | LOG_NDELAY, SYSLOGFAC);
477
478 while((ch = getopt(ac, av, "a:c:i:J:m:o:p:u:U:frstbwgIqvVh?")) != -1) {
479 switch (ch) {
480 case 'a':
481 if (optarg != NULL) {
482 if (strchr(optarg, 'n') != NULL) {
483 /* no-auth resets any other options */
484 method_num = 0; /* reset auth methods */
485 break;
486 }
487
488 for (p=optarg, i=0; method_num < MAX_AUTH_METH && i < MAX_AUTH_METH; p++, i++) {
489 if (*p == '\0')
490 break;
491 switch (*p) {
492 case 'p':
493 if (memchr(method_tab, 'p', method_num) == NULL) {
494 method_tab[method_num] = S5AUSRPAS;
495 method_num++;
496 }
497 break;
498 default:
499 /* un-supported/invalid method */
500 break;
501 }
502 }
503 }
504 break;
505
506 case 'b':
507 bind_restrict = 0;
508 break;
509
510 case 'c':
511 if (optarg != NULL) {
512 config = strdup(optarg);
513 }
514 break;
515
516 case 'u':
517 if (optarg != NULL) {
518 pwdfile = strdup(optarg);
519 }
520 break;
521
522 case 'U':
523 if (optarg != NULL) {
524 localpwd = strdup(optarg);
525 }
526 break;
527
528 case 'i':
529 if (optarg != NULL) {
530 if (serv_init(optarg) < 0) {
531 msg_out(warn, "cannot init server socket(-i %s): %m\n", optarg);
532 break;
533 }
534 }
535 break;
536
537 #ifdef SO_BINDTODEVICE
538 case 'J':
539 if (optarg != NULL) {
540 bindtodevice = strdup(optarg);
541 }
542 break;
543 #endif
544
545 case 'o':
546 if (optarg != NULL) {
547 idle_timeout = atol(optarg);
548 }
549 break;
550
551 case 'p':
552 if (optarg != NULL) {
553 pidfile = strdup(optarg);
554 }
555 break;
556
557 case 'm':
558 if (optarg != NULL) {
559 #ifdef USE_THREAD
560 max_thread = atoi(optarg);
561 #endif
562 max_child = atoi(optarg);
563 }
564 break;
565
566 case 't':
567 #ifdef USE_THREAD
568 threading = 0; /* threading disabled. */
569 #endif
570 break;
571
572 case 'g':
573 same_interface = 1;
574 break;
575
576 case 'f':
577 fg = 1;
578 break;
579
580 case 'r':
581 resolv_client = 1;
582 break;
583
584 case 's':
585 forcesyslog = 1;
586 break;
587
588 case 'w':
589 #ifdef HAVE_LIBWRAP
590 use_tcpwrap = 1;
591 #endif /* HAVE_LIBWRAP */
592 break;
593
594 case 'I':
595 inetd_mode = 1;
596 break;
597
598 case 'q':
599 be_quiet = 1;
600 break;
601
602 case 'v':
603 verbosity++;
604 break;
605
606 case 'V':
607 show_version();
608 exit(1);
609
610 case 'h':
611 case '?':
612 default:
613 usage();
614 }
615 }
616
617 ac -= optind;
618 av += optind;
619
620 if ((fp = fopen(config, "r")) != NULL) {
621 if (readconf(fp) != 0) {
622 /* readconf error */
623 exit(1);
624 }
625 fclose(fp);
626 }
627
628 if ( method_num > 0
629 && uid != 0
630 && memchr(method_tab, 'p', method_num) != NULL
631 && localpwd == NULL) {
632 /* process does not started by root */
633 msg_out(warn, "uid == %d (!=0),"
634 "user/pass auth may not work.\n", uid);
635 }
636
637 if (inetd_mode) {
638 /* close all server socket if opened */
639 close_all_serv();
640 /* assuming that STDIN_FILENO handles bi-directional
641 */
642 exit(inetd_service(STDIN_FILENO));
643 /* not reached */
644 }
645
646 if (serv_sock_ind == 0) { /* no valid ifs yet */
647 if (serv_init(":") < 0) { /* use default */
648 /* fatal */
649 msg_out(crit, "cannot open server socket\n");
650 exit(1);
651 }
652 }
653
654 #ifdef USE_THREAD
655 if ( ! threading ) {
656 #endif
657 if (queue_init() != 0) {
658 msg_out(crit, "cannot init signal queue\n");
659 exit(1);
660 }
661 #ifdef USE_THREAD
662 }
663 #endif
664
665 /* try changing working directory */
666 if ( chdir(WORKDIR0) != 0 )
667 if ( chdir(WORKDIR1) != 0 )
668 msg_out(norm, "giving up chdir to workdir");
669
670 if (!fg) {
671 /* force stdin/out/err allocate to /dev/null */
672 fclose(stdin);
673 fp = fopen("/dev/null", "w+");
674 if (fileno(fp) != STDIN_FILENO) {
675 msg_out(crit, "fopen: %m");
676 exit(1);
677 }
678 if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) {
679 msg_out(crit, "dup2-1: %m");
680 exit(1);
681 }
682 if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
683 msg_out(crit, "dup2-2: %m");
684 exit(1);
685 }
686
687 switch(fork()) {
688 case -1:
689 msg_out(crit, "fork: %m");
690 exit(1);
691 case 0:
692 /* child */
693 pid = setsid();
694 if (pid == -1) {
695 msg_out(crit, "setsid: %m");
696 exit(1);
697 }
698 break;
699 default:
700 /* parent */
701 exit(0);
702 }
703 }
704
705 master_pid = getpid();
706 umask(S_IWGRP|S_IWOTH);
707 if ((fp = fopen(pidfile, "w")) != NULL) {
708 fprintf(fp, "%u\n", (unsigned)master_pid);
709 fchown(fileno(fp), PROCUID, PROCGID);
710 fclose(fp);
711 } else {
712 msg_out(warn, "cannot open pidfile %s", pidfile);
713 }
714
715 signal_setup();
716
717 #ifdef USE_THREAD
718 if ( threading ) {
719 if (max_thread <= 0 || max_thread > THREAD_LIMIT) {
720 max_thread = THREAD_LIMIT;
721 }
722 /* resource limit is problem in threadig (e.g. Solaris:=64)*/
723 memset((caddr_t)&rl, 0, sizeof rl);
724 if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
725 msg_out(warn, "getrlimit: %m");
726 else
727 save_fd = rl.rlim_cur;
728 if (rl.rlim_cur < (rlim_t)max_fd)
729 rl.rlim_cur = max_fd; /* willing to fix to max_fd */
730 if ( rl.rlim_cur != save_fd ) /* if rlim_cur is changed */
731 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
732 msg_out(warn, "cannot set rlimit(max_fd)");
733
734 setregid(-1, PROCGID);
735 setreuid(-1, PROCUID);
736
737 pthread_mutex_init(&mutex_select, NULL);
738 pthread_attr_init(&attr);
739 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
740
741 msg_out(norm, "Starting: MAX_TH(%d)", max_thread);
742 for (i=0; i<max_thread; i++) {
743 if (pthread_create(&tid, &attr,
744 (void *)&serv_loop, (void *)NULL) != 0)
745 exit(1);
746 }
747 main_thread = pthread_self(); /* store main thread ID */
748 for (;;) {
749 pause();
750 }
751 } else {
752 #endif
753 setsignal(SIGCHLD, reapchild);
754 setregid(-1, PROCGID);
755 setreuid(-1, PROCUID);
756 msg_out(norm, "Starting: MAX_CH(%d)", max_child);
757 serv_loop();
758 #ifdef USE_THREAD
759 }
760 #endif
761 return(0);
762 }
763