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