📄 sockd.c
字号:
* initially successful, should make sure there is * always enough descriptors available. */ case EMFILE: /* FALLTHROUGH */ default: SERR(client); }#if HAVE_LINUX_BUGS /* * yes, linux manages to lose the descriptor flags, workaround * might be insufficient. */ if (fcntl(client, F_SETFL, fcntl(l->s, F_GETFL, 0)) != 0) swarn("tried to work around linux bug via fcntl()");#endif /* HAVE_LINUX_BUGS */ ++config.stat.accepted;#if NEED_ACCEPTLOCK if (config.option.serverc > 1) socks_unlock(l->lock);#endif slog(LOG_DEBUG, "got accept(): %s", sockaddr2string(&from, accepted, sizeof(accepted))); if (send_client(negchild->s, client) == 0) { --negchild->freec; ++config.stat.negotiate.sendt; } else switch (errno) { case EMFILE: case ENFILE: break; /* child is ok, we are not. */ default: removechild(negchild->pid); }#if HAVE_SENDMSG_DEADLOCK socks_unlock(negchild->lock);#endif /* HAVE_SENDMSG_DEADLOCK */ close(client); } } } /* NOTREACHED */}intpidismother(pid) pid_t pid;{ int i; for (i = 0; i < config.option.serverc; ++i) if (config.state.motherpidv[i] == pid) return i + 1; return 0;}static voidusage(code) int code;{ fprintf(code == 0 ? stdout : stderr, "%s: usage: %s [-DLNdfhlnv]\n" "\t -D : run in daemon mode\n" "\t -L : shows the license for this program\n" "\t -N <number> : fork of <number> servers (default: 1)\n" "\t -d : enable debugging\n" "\t -f <filename> : use <filename> as configuration file\n" "\t -h : print this information\n" "\t -l : linebuffer output\n" "\t -n : disable TCP keep-alive\n" "\t -v : print version info\n", __progname, __progname); exit(code);}static voidshowversion(void){ printf("%s: %s v%s\n", __progname, PACKAGE, VERSION); exit(EXIT_SUCCESS);}static voidshowlicense(void){ printf("%s: %s v%s\n%s\n", __progname, PACKAGE, VERSION,"\/*\n\ * Copyright (c) 1997, 1998, 1999\n\ * Inferno Nettverk A/S, Norway. All rights reserved.\n\ *\n\ * Redistribution and use in source and binary forms, with or without\n\ * modification, are permitted provided that the following conditions\n\ * are met:\n\ * 1. The above copyright notice, this list of conditions and the following\n\ * disclaimer must appear in all copies of the software, derivative works\n\ * or modified versions, and any portions thereof, aswell as in all\n\ * supporting documentation.\n\ * 2. All advertising materials mentioning features or use of this software\n\ * must display the following acknowledgement:\n\ * This product includes software developed by\n\ * Inferno Nettverk A/S, Norway.\n\ * 3. The name of the author may not be used to endorse or promote products\n\ * derived from this software without specific prior written permission.\n\ *\n\ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n\ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n\ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \n\ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n\ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n\ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n\ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n\ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \n\ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n\ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ *\n\ * Inferno Nettverk A/S requests users of this software to return to\n\ * \n\ * Software Distribution Coordinator or sdc@inet.no\n\ * Inferno Nettverk A/S\n\ * Oslo Research Park\n\ * Gaustadal閑n 21\n\ * N-0349 Oslo\n\ * Norway\n\ * \n\ * any improvements or extensions that they make and grant Inferno Nettverk A/S\n\ * the rights to redistribute these changes.\n\ *\n\ */"); exit(EXIT_SUCCESS);}/* ARGSUSED */ /* need envp if no HAVE_SETPROCTITLE */static voidserverinit(argc, argv, envp) int argc; char *argv[]; char *envp[];{ const char *function = "serverinit()"; uid_t euid; int ch, i;#if !HAVE_PROGNAME if (argv[0] != NULL) if ((__progname = strrchr(argv[0], '/')) == NULL) __progname = argv[0]; else ++__progname;#endif /* !HAVE_PROGNAME */#if !HAVE_SETPROCTITLE if (initsetproctitle(argc, argv, envp) == -1) serr(EXIT_FAILURE, "malloc");#endif /* !HAVE_SETPROCTITLE*/ config.state.addchild = 1; config.state.euid = geteuid(); config.state.type = CHILD_MOTHER; config.option.serverc = 1; /* ourselves. ;-) */ while ((ch = getopt(argc, argv, "DLN:df:hlnvw:")) != -1) { switch (ch) { case 'D': config.option.daemon = 1; break; case 'L': showlicense(); /* NOTREACHED */ case 'N': if ((config.option.serverc = atoi(optarg)) < 1) serrx(1, "%s: illegal value for -%c: %d", function, ch, config.option.serverc); break; case 'd': ++config.option.debug; break; case 'f':#if !HAVE_SETPROCTITLE /* let it point outside argv for replacement setproctitle(). */ if ((config.option.configfile = strdup(optarg)) == NULL) serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);#else config.option.configfile = optarg;#endif /* !HAVE_SETPROCTITLE */ break; case 'h': usage(0); /* NOTREACHED */ case 'l': config.option.lbuf = 1; break; case 'n': config.option.keepalive = 0; break; case 'v': showversion(); /* NOTREACHED */ case 'w': config.option.sleep = atoi(optarg); break; default: usage(1); } } if (config.option.daemon) if (daemon(1, 0) != 0) serr(EXIT_FAILURE, "daemon()"); config.state.pid = getpid(); if ((config.state.motherpidv = (pid_t *)malloc(sizeof(*config.state.motherpidv) * config.option.serverc)) == NULL) serrx(EXIT_FAILURE, "%s: %s", function, NOMEM); *config.state.motherpidv = config.state.pid; /* main server. */ if (config.option.configfile == NULL) config.option.configfile = SOCKD_CONFIGFILE; genericinit(); checksettings(); socks_seteuid(&euid, config.uid.privileged); for (i = 0; i < config.internalc; ++i) { int flags; struct listenaddress_t *l = &config.internalv[i]; if ((l->s = socket(AF_INET, SOCK_STREAM, 0)) == -1) serr(EXIT_FAILURE, "%s: socket(SOCK_STREAM)", function); setsockoptions(l->s); ch = 1; if (setsockopt(l->s, SOL_SOCKET, SO_REUSEADDR, &ch, sizeof(ch)) != 0) swarn("%s: setsockopt(SO_REUSEADDR)", function); /* LINTED pointer casts may be troublesome */ if (sockd_bind(l->s, (struct sockaddr *)&l->addr, 0) != 0) { char badbind[MAXSOCKADDRSTRING]; /* LINTED pointer casts may be troublesome */ serr(EXIT_FAILURE, "%s: bind(%s)", function, sockaddr2string((struct sockaddr *)&l->addr, badbind, sizeof(badbind))); } if (listen(l->s, SOCKD_MAXCLIENTQUE) == -1) serr(EXIT_FAILURE, "%s: listen(%d)", function, SOCKD_MAXCLIENTQUE); if ((flags = fcntl(l->s, F_GETFL, 0)) == -1 || fcntl(l->s, F_SETFL, flags | O_NONBLOCK) == -1) serr(EXIT_FAILURE, "%s: fcntl()", function);#if NEED_ACCEPTLOCK if (config.option.serverc > 1) if ((l->lock = socks_mklock(SOCKS_LOCKFILE)) == -1) serr(EXIT_FAILURE, "%s: socks_mklock()", function);#endif } socks_reseteuid(config.uid.privileged, euid);}static voidchecksettings(void){ const char *function = "checksettings()"; int i; uid_t euid; /* * Check arguments and settings, do they make sense? */ if (config.internalc == 0) serrx(EXIT_FAILURE, "%s: no internal address given", function); if (config.externalc == 0) serrx(EXIT_FAILURE, "%s: no external address given", function); for (i = 0; i < config.externalc; ++i) { int s; if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) switch (errno) { case EMFILE: case ENFILE: case ENOBUFS: break; /* assume this is temporary, e.g. after sighup. */ default: serrx(EXIT_FAILURE, "%s: socket()", function); } else { char addrstring[MAXSOCKADDRSTRING]; if (bind(s, (struct sockaddr *)&config.externalv[i], sizeof(config.externalv[i])) != 0) serrx(EXIT_FAILURE, "%s: can't bind external address: %s", function, sockaddr2string((struct sockaddr *)&config.externalv[i], addrstring, sizeof(addrstring))); close(s); } } if (config.methodc == 0) swarnx("%s: no methods enabled (total block)", function); if (!config.uid.privileged_isset) serrx(EXIT_FAILURE, "%s: privileged user not set", function); socks_seteuid(&euid, config.uid.privileged); socks_reseteuid(config.uid.privileged, euid); if (!config.uid.unprivileged_isset) serrx(EXIT_FAILURE, "%s: unprivileged user not set", function); socks_seteuid(&euid, config.uid.unprivileged); socks_reseteuid(config.uid.unprivileged, euid);#if HAVE_LIBWRAP if (!config.uid.libwrap_isset) serrx(EXIT_FAILURE, "%s: libwrap user not set", function); socks_seteuid(&euid, config.uid.libwrap); socks_reseteuid(config.uid.libwrap, euid);#endif /* HAVE_LIBWRAP */}/* ARGSUSED */static voidsiginfo(sig) int sig;{ unsigned long seconds, days, hours, minutes; size_t clients; clients = 0; clients += childcheck(-CHILD_NEGOTIATE); clients += childcheck(-CHILD_REQUEST); clients += childcheck(-CHILD_IO); clients -= childcheck(CHILD_NEGOTIATE); clients -= childcheck(CHILD_REQUEST); clients -= childcheck(CHILD_IO); seconds = difftime(time(NULL), config.stat.boot); if (seconds >= 3600 * 24) { days = seconds / (3600 * 24); seconds -= days * 3600 * 24; } else days = 0; if (seconds >= 3600) { hours = seconds / 3600; seconds -= hours * 3600; } else hours = 0; if (seconds >= 60) { minutes = seconds / 60; seconds -= minutes * 60; } else minutes = 0; slog(LOG_INFO, "%s v%s up %lu day%s, %lu:%.2lu, a: %lu, c: %lu", PACKAGE, VERSION, days, days == 1 ? "" : "s", hours, minutes, (unsigned long)config.stat.accepted, (unsigned long)clients); slog(LOG_INFO, "negotiators (%d): a: %lu, h: %lu, c: %lu", childcheck(-CHILD_NEGOTIATE) / SOCKD_NEGOTIATEMAX, (unsigned long)config.stat.negotiate.sendt, (unsigned long)config.stat.negotiate.received, (unsigned long)childcheck(-CHILD_NEGOTIATE) - childcheck(CHILD_NEGOTIATE)); slog(LOG_INFO, "requests (%d): a: %lu, h: %lu, c: %lu", childcheck(-CHILD_REQUEST) / SOCKD_REQUESTMAX, (unsigned long)config.stat.request.sendt, (unsigned long)config.stat.request.received, (unsigned long)childcheck(-CHILD_REQUEST) - childcheck(CHILD_REQUEST)); slog(LOG_INFO, "iorelayers (%d): a: %lu, h: %lu, c: %lu", childcheck(-CHILD_IO) / SOCKD_IOMAX, (unsigned long)config.stat.io.sendt, (unsigned long)config.stat.io.sendt, (unsigned long)childcheck(-CHILD_IO) - childcheck(CHILD_IO)); if (*config.state.motherpidv == config.state.pid) /* main mother */ sigserverbroadcast(sig); sigchildbroadcast(sig, CHILD_NEGOTIATE | CHILD_REQUEST | CHILD_IO);}/* ARGSUSED */static voidsighup(sig) int sig;{ const char *function = "sighup()"; uid_t euid; int p; slog(LOG_INFO, function); resetconfig(); socks_seteuid(&euid, config.state.euid); genericinit(); socks_reseteuid(config.state.euid, euid); checksettings(); /* LINTED assignment in conditional context */ if ((p = pidismother(config.state.pid))) { if (p == 1) { /* main mother. */ showconfig(&config); sigserverbroadcast(sig); } sigchildbroadcast(sig, CHILD_NEGOTIATE | CHILD_REQUEST | CHILD_IO); }}/* ARGSUSED */static voidsigchld(sig) int sig;{ const char *function = "sigchld()"; static time_t deathtime; static int deaths; int status; pid_t pid; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { int i; /* * No child should normally die, but try to cope with it happening. */ /* LINTED assignment in conditional context */ if ((i = pidismother(pid))) config.state.motherpidv[i - 1] = 0; else ; /* assume relay child. */ ++deaths; } /* * If we get alot of childdeaths in a short time, assume something * is wrong. */ if (deathtime == 0) time(&deathtime); if (difftime(time(NULL), deathtime) > 60) { /* enough time passed; reset. */ deaths = 0; time(&deathtime); } if (deaths >= 10) { if (deaths == 10) { /* log once. */ slog(LOG_ERR, "%s: %d childdeaths in %.0fs; locking count for a while", function, deaths, difftime(time(NULL), deathtime)); config.state.addchild = 0; } time(&deathtime); /* once the ball starts rolling... */ alarm(60); } else config.state.addchild = 1; /* can try to add a new one. */}/* ARGSUSED */static voidsigalrm(sig) int sig;{ config.state.addchild = 1;}voidsigserverbroadcast(sig) int sig;{ int i; SASSERTX(*config.state.motherpidv == config.state.pid); for (i = 1; i < config.option.serverc; ++i) if (config.state.motherpidv[i] != 0) kill(config.state.motherpidv[i], sig);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -