📄 sockd.c
字号:
#include <pwd.h>#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/signal.h>#include <syslog.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <netdb.h>#include <stdio.h>#include <ctype.h>#include <errno.h>#if (defined(sun) && !defined(SOLARIS)) || defined(sgi)#include <strings.h>#else#include <string.h>#endif#include "socks.h"#include <fcntl.h>#if defined(AIX)#include <sys/mode.h>#endif#if defined(sgi) && defined(SYSTYPE_SVR4)#include <sys/stat.h>#endif#include "ident.h"#define IDENTD_TIMEOUT 15 /* 15 seconds */static int use_identd = 0;#define STREQ(a, b) (strcmp(a, b) == 0)char socks_cmd[] = "connect";static char *sockd_conf = SOCKD_CONF;static char server_version[] = "4.1";static unsigned short socks_port;static unsigned short socks_client_port;extern char *socks_porttoserv();extern char *socks_saddrtoname();extern void socks_mkargs();extern int socks_GetAddr();extern int socks_GetQuad();extern long socks_GetPort();extern int socks_check_user();#define NAMELEN 128char socks_src_name[NAMELEN], socks_src_user[NAMELEN];char socks_real_user[NAMELEN];char socks_dst_name[NAMELEN], socks_dst_serv[NAMELEN];static char log_msg[1024];#ifdef DEBUGstatic char buf[1024];#endifstatic struct config *cfPtr, **cfEntries = NULL;static int cfNtries = 0;#ifdef MULTIHOMED_SERVERstatic struct config *rtPtr, **rtEntries = NULL;static int rtNtries = 0;#endif /* MULTIHOMED_SERVER */#define BAD_ID_STR "#BAD_ID:"#define NO_IDENTD_STR "#NO_IDENTD:"#ifdef NOT_THROUGH_INETDstatic char bad_id_cmd[1024];static char no_identd_cmd[1024];void rereadConfig();void reapChild();/* void killChildren(); */void dumpconf();#endif /* #ifdef NOT_THROUGH_INETD */static u_int32 from_in = 0L, from_out = 0L;/*** Current version for response messages*/int Version = 0;void die(){ syslog(LOG_HIGH, "timed-out -- %s", log_msg); exit(1);}#ifdef FOR_PSmain(argc, argv, envp)int argc;char *argv[];char *envp[];#else /* FOR_PS not defined */main(argc, argv)int argc;char *argv[];#endif /* #ifdef FOR_PS */{ char c; int inp, in, out, nindex=0; int i, n, len = sizeof(struct sockaddr_in); struct sockaddr_in sin, from, dstsin; int fromlen = sizeof(struct sockaddr_in); Socks_t dst; int one = 1; struct servent *sp; int permit;#ifdef NOT_THROUGH_INETD/* int pid;*/ pid_t pid; struct passwd *pw; sigset_t mask; int devnull; char pidstr[32]; int pidf, pidlen;#endif#if defined(FOR_PS) && !defined(SYSV)#define MAXUSERENVIRON 100 char *UserEnviron[MAXUSERENVIRON+1]; /* saved user environment */ extern char **environ; char ps_buf[1024]; char **Argv = NULL; /* pointer to argument vector */ char *LastArgv = NULL; /* end of argv */#define newstr(s) strcpy(malloc(strlen(s) + 1), s) for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++) UserEnviron[i] = newstr(envp[i]); UserEnviron[i] = NULL; environ = UserEnviron; /* ** Save start and extent of argv for setproctitle. */ Argv = argv; if (i > 0) LastArgv = envp[i - 1] + strlen(envp[i - 1]); else LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);#endif /* FOR_PS && !SYSV *//* if started by root, change the uid to nobody. */#ifdef NOT_THROUGH_INETD/* if (getuid() == 0) { if((pw = getpwnam("nobody")) == (struct passwd *)0) { fprintf(stderr, "Terminated: User nobody not in password file\n"); exit(1); } if (setuid(pw->pw_uid) < 0) { fprintf(stderr, "Terminated: Can't change uid to nobody\n"); exit(1); } }*/#endif /* ifdef NOT_THROUGH_INETD */ socks_port = htons(SOCKS_DEF_PORT); bzero((char *)&sin, sizeof(sin)); bzero((char *)&from, sizeof(from)); bzero((char *)&dstsin, sizeof(dstsin)); if (argc >= 2) { if (strcmp(argv[1],"-ver") == 0) {#ifdef MULTIHOMED_SERVER# ifdef NOT_THROUGH_INETD printf(" CSTC multi-homed, stand-alone SOCKS proxy server version %s.\n", CSTC_RELEASE);# else printf(" CSTC multi-homed, inetd-controlled SOCKS proxy server version %s.\n", CSTC_RELEASE);# endif#else /* MULTIHOMED_SERVER not defined */# ifdef NOT_THROUGH_INETD printf(" CSTC single-homed, stand-alone SOCKS proxy server version %s.\n", CSTC_RELEASE);# else printf(" CSTC single-homed, inetd-controlled SOCKS proxy server version %s.\n", CSTC_RELEASE);# endif#endif /* #ifdef MULTIHOMED_SERVER */#if defined(SUPPORT_RCMD) printf(" Supports clients that use Rrcmd().\n");#else /* SUPPORT_RCMD not defined */ printf(" Does not support clients that use Rrcmd().\n");#endif /* #if defined(SUPPORT_RCMD) */ exit(1); } else if (strcmp(argv[1], "-i") == 0) use_identd = 1; else if (strcmp(argv[1], "-I") == 0) use_identd = 2; /* strict use of identd */ else ; } strcpy(socks_real_user,"unknown"); if ((sp = getservbyname("socks", "tcp")) != NULL) socks_port = sp->s_port;#ifndef LOG_DAEMON (void) openlog("sockd", LOG_PID);#else (void) openlog("sockd", LOG_PID, SYSLOG_FAC);#endif#ifdef NOT_THROUGH_INETD if ((pid = fork()) == -1) { syslog(LOG_HIGH, "starup could not fork (%m)!"); exit(1); } if (pid) exit(0); /* we are backgrounded now */ syslog(LOG_LOW, "sockd server starting"); (void) setsid(); (void) chdir("/"); devnull = open("/dev/null", O_RDWR, 0); if (devnull != -1) { (void) dup2(devnull, 0); (void) dup2(devnull, 1); (void) dup2(devnull, 2); if (devnull > 2) (void) close(devnull); } /* read the configuration (for non-inetd, once for all future children) */ if (!readConfig()) { syslog(LOG_HIGH, "Terminate"); exit(1); }#ifdef MULTIHOMED_SERVER /* read the route configuration (for non-inetd, once for all future children) */ if (!readRoute()) { syslog(LOG_HIGH, "Terminate"); exit(1); }#endif /* MULTIHOMED_SERVER */ sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_UNBLOCK, &mask, NULL); /* signal(SIGTERM, killChildren); */ signal(SIGHUP, rereadConfig); signal(SIGCHLD, reapChild); signal(SIGUSR1, dumpconf); inp = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_port = socks_port; sin.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(inp, &sin, sizeof(sin)) < 0) { syslog(LOG_HIGH, "error -- main bind() %m"); exit(1); } if (listen(inp, MAX_CLIENTS) < 0) { syslog(LOG_HIGH, "error -- main listen() %m"); exit(1); }/* Put our process id in /tmp/sockd.pid */#define PID_FILE "/tmp/sockd.pid" if ((pidf = open(PID_FILE, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) { syslog(LOG_HIGH, "Cannot create/access %s", PID_FILE); } else { sprintf(pidstr, "%d\n", getpid()); if (write(pidf, pidstr, strlen(pidstr)) < 0) syslog(LOG_HIGH, "Cannot write to /%s", PID_FILE); close(pidf); } /* parent stays within this loop */ for (;;) { int pid; if ((in = accept(inp, &sin, &len)) < 0) { if (errno == EINTR) continue; /* caught SIGCHLD */ syslog(LOG_HIGH, "error -- main accept() %m"); exit(1); } if ((pid = fork()) == 0) break; /* child */ if (pid == -1) syslog(LOG_HIGH, "fork failed - %m"); /* parent stays in loop */ close(in); } /* in child now */ signal(SIGHUP, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGTERM, SIG_DFL); closelog(); close(inp);#ifndef LOG_DAEMON (void) openlog("sockd", LOG_PID);#else (void) openlog("sockd", LOG_PID, SYSLOG_FAC);#endif /* LOG_DAEMON */#else in = dup(0);#endif /* NOT_THROUGH_INETD */ if (getpeername(in, (struct sockaddr *)&from, &fromlen) < 0) { syslog(LOG_HIGH, "error -- unable to get client address."); exit(1); } socks_client_port = ntohs(from.sin_port);#ifdef DEBUG syslog(LOG_LOW, "socks_client_port=%u", socks_client_port);#endif /* #ifdef DEBUG */ socks_saddrtoname(&from.sin_addr, socks_src_name, sizeof(socks_src_name)); if (socks_GetDst(in, &dst) < 0) { syslog(LOG_HIGH, "Error in socks_GetDst: %m; from host %s", socks_src_name); exit(1); } if (dst.version != SOCKS_VERSION) { syslog(LOG_HIGH, "error -- wrong version (0x%2x) from host %s.", dst.version, socks_src_name); exit(1); } if (dst.cmd != SOCKS_CONNECT && dst.cmd != SOCKS_BIND) { syslog(LOG_HIGH, "error -- undefined command (0x%2x) from host %s", dst.cmd, socks_src_name); exit(1); } dstsin.sin_family = AF_INET; dstsin.sin_addr.s_addr = dst.host; dstsin.sin_port = dst.port; while (read(in, &c, 1) == 1) if (c == '\0') break; else { if (nindex < sizeof(socks_src_user) - 1) socks_src_user[nindex++] = c; } socks_src_user[nindex] = '\0'; if (dstsin.sin_addr.s_addr == 0) strcpy(socks_dst_name, "Unspecified.Host"); else socks_saddrtoname(&dstsin.sin_addr, socks_dst_name, sizeof(socks_dst_name)); socks_porttoserv(dstsin.sin_port, socks_dst_serv, sizeof(socks_dst_serv)); permit = Validate(&from, &dstsin, in); if (dst.cmd == SOCKS_CONNECT) { strcpy(socks_cmd, "connect"); sprintf(log_msg, "Connect from %s(%s)@%s to %s (%s)", socks_src_user, socks_real_user, socks_src_name, socks_dst_name, socks_dst_serv);#ifdef FOR_PS sprintf(ps_buf, "%s: %s(c) to %s", socks_src_user, socks_dst_serv, socks_dst_name); setproctitle(ps_buf, Argv, LastArgv);#endif /* #ifdef FOR_PS */ } else { strcpy(socks_cmd, "bind"); sprintf(log_msg, "Bind from %s(%s)@%s for %s", socks_src_user, socks_real_user, socks_src_name, socks_dst_name);#ifdef FOR_PS sprintf(ps_buf, "%s: %s(b) to %s", socks_src_user, socks_dst_serv, socks_dst_name); setproctitle(ps_buf, Argv, LastArgv);#endif /* #ifdef FOR_PS */ } if (permit == 1) ; else if (permit == 0) { syslog(LOG_LOW, "refused -- %s", log_msg); exit(1); } else if (permit == -1) { syslog(LOG_LOW, "cannot connect to identd on %s", socks_src_name); } else if (permit == -2) { syslog(LOG_LOW, "refused -- %s", log_msg); syslog(LOG_LOW, "cannot connect to identd on %s", socks_src_name); dst.cmd = SOCKS_NO_IDENTD; socks_SendDst(in, &dst); exit(1); } else if (permit == -3) { syslog(LOG_LOW, "refused -- %s", log_msg); syslog(LOG_LOW, "*Alert*: real user is %s, not %s", socks_real_user, socks_src_user); dst.cmd = SOCKS_BAD_ID; socks_SendDst(in, &dst); exit(1); } else { syslog(LOG_HIGH, "refused -- %s", log_msg); syslog(LOG_HIGH, "Unexpected result from Validate"); exit(1); }#ifdef DEBUG strcpy(buf, inet_ntoa(from.sin_addr)); syslog(LOG_LOW,"USER:%s, SRC:%s, DST:%s, PORT:%u", socks_src_user, buf, inet_ntoa(dstsin.sin_addr), ntohs(dstsin.sin_port));#endif /* DEBUG */ /* ** Kill a connecting off if bind or connect takes too ** long to complete */ signal(SIGALRM, die); /*alarm(60*5);*/ /* 5 minutes */ alarm(60*2); if (dst.cmd == SOCKS_CONNECT) { DoConnect(in, &dst); } if (dst.cmd == SOCKS_BIND) { DoNewBind(in, &dst); }}socks_fail(str, in, ndst)char *str;int in;Socks_t *ndst;{ syslog(LOG_LOW, "failed -- %s. Error code: %s %m", log_msg, str); ndst->cmd = SOCKS_FAIL; socks_SendDst(in, ndst); exit(1);}/*** Actually connect a socket to the outside world,*/DoConnect(in, dst)int in;Socks_t *dst;{ int out; struct sockaddr_in sin; Socks_t ndst; int outport = IPPORT_RESERVED - 1; int turnon = 1; bzero((char *)&sin, sizeof(sin));#if defined(SO_OOBINLINE) setsockopt(in, SOL_SOCKET, SO_OOBINLINE, &turnon, sizeof(turnon));#endif#if defined(SUPPORT_RCMD)#ifdef DEBUG syslog(LOG_LOW, "DoConnect(): client port=%u", socks_client_port);#endif /* #ifdef DEBUG */ if ((socks_client_port < IPPORT_RESERVED) && (socks_client_port >= IPPORT_RESERVED/2)) { if ((out = rresvport(&outport)) < 0) socks_fail("rresvport()", in, &ndst);#if !defined(SCO) && !defined(ISC)#if defined(hpux) ioctl(out, FIOSSAIOOWN, getpid());#else /* hpux not defined */ fcntl(out, F_SETOWN, getpid());#endif /* #if defined(hpux) */#endif /* #if !defined(SCO) && !defined(ISC) */ } else if ((out = socket(AF_INET, SOCK_STREAM, 0)) < 0) socks_fail("socket()", in, &ndst);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -