sockd.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:26k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1997, 1998, 1999
  3.  *      Inferno Nettverk A/S, Norway.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. The above copyright notice, this list of conditions and the following
  9.  *    disclaimer must appear in all copies of the software, derivative works
  10.  *    or modified versions, and any portions thereof, aswell as in all
  11.  *    supporting documentation.
  12.  * 2. All advertising materials mentioning features or use of this software
  13.  *    must display the following acknowledgement:
  14.  *      This product includes software developed by
  15.  *      Inferno Nettverk A/S, Norway.
  16.  * 3. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * Inferno Nettverk A/S requests users of this software to return to
  31.  *
  32.  *  Software Distribution Coordinator  or  sdc@inet.no
  33.  *  Inferno Nettverk A/S
  34.  *  Oslo Research Park
  35.  *  Gaustadal閑n 21
  36.  *  N-0349 Oslo
  37.  *  Norway
  38.  *
  39.  * any improvements or extensions that they make and grant Inferno Nettverk A/S
  40.  * the rights to redistribute these changes.
  41.  *
  42.  */
  43. #include "common.h"
  44. static const char rcsid[] =
  45. "$Id: sockd.c,v 1.248 1999/12/20 13:07:42 karls Exp $";
  46. /*
  47.  * signal handlers
  48.     */
  49. __BEGIN_DECLS
  50. static void
  51. checksettings __P((void));
  52. static void
  53. siginfo __P((int sig));
  54. static void
  55. sigchld __P((int sig));
  56. static void
  57. sigalrm __P((int sig));
  58. static void
  59. sighup __P((int sig));
  60. static void
  61. sigserverbroadcast __P((int sig));
  62. /*
  63.  * Broadcasts "sig" to all other servers.
  64.  *
  65.  */
  66. static void
  67. serverinit __P((int argc, char *argv[], char *envp[]));
  68. /*
  69.  * Initialises options/config.  "argc" and "argv" should be
  70.  * the arguments passed to main().
  71.  * Exits on failure.
  72.  */
  73. static void
  74. usage __P((int code));
  75. /*
  76.  * print usage.
  77.  */
  78. static void
  79. showversion __P((void));
  80. /*
  81.  * show versioninfo and exits.
  82.  */
  83. static void
  84. showlicense __P((void));
  85. /*
  86.  * shows license and exits.
  87.  */
  88. #if DIAGNOSTIC && HAVE_MALLOC_OPTIONS
  89. extern char *malloc_options;
  90. #endif  /* DIAGNOSTIC && HAVE_MALLOC_OPTIONS */
  91. #if HAVE_PROGNAME
  92. extern char *__progname;
  93. #else
  94. char *__progname = "sockd"; /* default. */
  95. #endif  /* HAVE_PROGNAME */
  96. extern char *optarg;
  97. __END_DECLS
  98. int
  99. #if HAVE_SETPROCTITLE
  100. main(argc, argv)
  101. #else
  102. main(argc, argv, envp)
  103. #endif /* HAVE_SETPROCTITLE */
  104. int argc;
  105. char *argv[];
  106. #if !HAVE_SETPROCTITLE
  107. char    *envp[];
  108. #endif  /* HAVE_SETPROCTITLE */
  109. {
  110. struct sigaction sigact;
  111. int p, maxfd, dforchild;
  112. FILE *fp;
  113. #if HAVE_SETPROCTITLE
  114. char *envp[] = { NULL }; /* dummy. */
  115. #endif /* HAVE_SETPROCTITLE */
  116. const int exitsignalv[] = {
  117. SIGINT, SIGQUIT, SIGBUS, SIGSEGV, SIGTERM
  118. };
  119. const size_t exitsignalc = ELEMENTS(exitsignalv);
  120. const int ignoresignalv[] = {
  121. SIGPIPE
  122. };
  123. const size_t ignoresignalc = ELEMENTS(ignoresignalv);
  124. #if DIAGNOSTIC && HAVE_MALLOC_OPTIONS
  125. malloc_options = "AJ";
  126. #endif  /* DIAGNOSTIC && HAVE_MALLOC_OPTIONS */
  127. serverinit(argc, argv, envp);
  128. showconfig(&config);
  129. socks_seteuid(NULL, config.uid.unprivileged);
  130. /* for chroot and needing every descriptor we can get. */
  131. dforchild = config.log.type & LOGTYPE_SYSLOG ? -1 : 0; /* syslog takes one */
  132. for (p = 0, maxfd = getdtablesize(); p < maxfd; ++p) {
  133. int i;
  134. /* don't close config/log files. */
  135. if (socks_logmatch((size_t)p, &config.log))
  136. continue;
  137. ++dforchild; /* descriptor will be usable by child. */
  138. /* sockets we listen on. */
  139. for (i = 0; i < config.internalc; ++i) {
  140. if (p == config.internalv[i].s)
  141. break;
  142. #if NEED_ACCEPTLOCK
  143. if (config.option.serverc > 1)
  144. if (p == config.internalv[i].lock)
  145. break;
  146. #endif
  147. }
  148. if (i < config.internalc)
  149. continue;
  150. close(p);
  151. }
  152. initlog(); /* for syslog. */
  153. /*
  154.  * Check system limits against what we need.
  155.  * Enough descriptors for each childprocess?  +2 for mother connections.
  156.  */
  157. /* CONSTCOND */
  158. maxfd = MAX(SOCKD_NEGOTIATEMAX,
  159. MAX(SOCKD_REQUESTMAX, SOCKD_IOMAX * FDPASS_MAX)) + 2;
  160. if (dforchild < maxfd) {
  161. struct rlimit rlimit;
  162. rlimit.rlim_cur = maxfd;
  163. rlimit.rlim_max = maxfd;
  164. if (setrlimit(RLIMIT_OFILE, &rlimit) != 0) {
  165. if (errno != EPERM)
  166. serr(EXIT_FAILURE, "setrlimit(RLIMIT_OFILE, %d)", rlimit.rlim_max);
  167. else if (getdtablesize() < SOCKD_NEGOTIATEMAX + 2)
  168. serr(EXIT_FAILURE,
  169. "%d descriptors configured for negotiation, %d available",
  170. SOCKD_NEGOTIATEMAX + 2, getdtablesize());
  171. else if (getdtablesize() < SOCKD_REQUESTMAX + 2)
  172. serr(EXIT_FAILURE,
  173. "%d descriptors configured for requestcompletion, %d available",
  174. SOCKD_REQUESTMAX + 2, getdtablesize());
  175. else if (getdtablesize() < SOCKD_IOMAX * FDPASS_MAX + 2)
  176. serr(EXIT_FAILURE,
  177. "%d descriptors configured for i/o, %d available",
  178. SOCKD_IOMAX * FDPASS_MAX + 2, getdtablesize());
  179. else
  180. SERRX(getdtablesize());
  181. }
  182. }
  183. /* set up signalhandlers. */
  184. sigemptyset(&sigact.sa_mask);
  185. sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP;
  186. sigact.sa_handler = siginfo;
  187. #if HAVE_SIGNAL_SIGINFO
  188. if (sigaction(SIGINFO, &sigact, NULL) != 0) {
  189. swarn("sigaction(SIGINFO)");
  190. return EXIT_FAILURE;
  191. }
  192. #endif  /* HAVE_SIGNAL_SIGINFO */
  193. /* same handler, for systems without SIGINFO. */
  194. if (sigaction(SIGUSR1, &sigact, NULL) != 0) {
  195. swarn("sigaction(SIGUSR1)");
  196. return EXIT_FAILURE;
  197. }
  198. sigact.sa_handler = sighup;
  199. if (sigaction(SIGHUP, &sigact, NULL) != 0) {
  200. swarn("sigaction(SIGHUP)");
  201. return EXIT_FAILURE;
  202. }
  203. sigact.sa_handler = sigchld;
  204. if (sigaction(SIGCHLD, &sigact, NULL) != 0) {
  205. swarn("sigaction(SIGCHLD)");
  206. return EXIT_FAILURE;
  207. }
  208. sigact.sa_handler = sockdexit;
  209. for (p = 0; (size_t)p < exitsignalc; ++p)
  210. if (sigaction(exitsignalv[p], &sigact, NULL) != 0)
  211. swarn("sigaction(%d)", exitsignalv[p]);
  212. sigact.sa_handler = SIG_IGN;
  213. for (p = 0; (size_t)p < ignoresignalc; ++p)
  214. if (sigaction(ignoresignalv[p], &sigact, NULL) != 0)
  215. swarn("sigaction(%d)", ignoresignalv[p]);
  216. sigact.sa_flags = 0; /* want to be interrupted. */
  217. sigact.sa_handler = sigalrm;
  218. if (sigaction(SIGALRM, &sigact, NULL) != 0) {
  219. swarn("sigaction(SIGALRM)");
  220. return EXIT_FAILURE;
  221. }
  222. socks_seteuid(NULL, config.uid.privileged);
  223. if ((fp = fopen(SOCKD_PIDFILE, "w")) == NULL)
  224. swarn("open(%s)", SOCKD_PIDFILE);
  225. socks_seteuid(NULL, config.uid.unprivileged);
  226. if (fp != NULL) {
  227. if (fprintf(fp, "%lun", (unsigned long)config.state.pid) == EOF)
  228. swarn("fprintf(%s)", SOCKD_PIDFILE);
  229. fclose(fp);
  230. }
  231. time(&config.stat.boot);
  232. /* fork of requested number of servers.  Start at one 'cause we are "it".  */
  233. for (p = 1; p < config.option.serverc; ++p) {
  234. pid_t pid;
  235. if ((pid = fork()) == -1)
  236. swarn("fork()");
  237. else if (pid == 0) {
  238. config.state.pid = getpid();
  239. break;
  240. }
  241. else
  242. config.state.motherpidv[p] = pid;
  243. }
  244. if (childcheck(CHILD_NEGOTIATE) <= 0
  245. ||  childcheck(CHILD_REQUEST) <= 0
  246. ||  childcheck(CHILD_IO) <= 0)
  247. serr(EXIT_FAILURE, "childcheck() failed");
  248. slog(LOG_INFO, "%s/server v%s running", PACKAGE, VERSION);
  249. /*
  250.  * main loop; accept new connections and handle our children.
  251.  */
  252. /* CONSTCOND */
  253. while (1) {
  254. int client;
  255. struct sockd_child_t *child;
  256. fd_set rset;
  257. int rbits;
  258. rbits = fillset(&rset);
  259. ++rbits;
  260. switch ((p = select(rbits, &rset, NULL, NULL, NULL))) {
  261. case 0:
  262. SERR(p);
  263. /* NOTREACHED */
  264. case -1:
  265. if (errno == EINTR)
  266. continue;
  267. SERR(p);
  268. /* NOTREACHED */
  269. }
  270. /*
  271.  * handle our children.
  272.  */
  273. /* first, get ack of free slots. */
  274. while ((child = getset(SOCKD_FREESLOT, &rset)) != NULL) {
  275. char command;
  276. int childisbad = 0;
  277. if ((p = readn(child->ack, &command, sizeof(command)))
  278. != sizeof(command)) {
  279. swarn("readn(child->ack) from %schild %lu failed",
  280. childtype2string(child->type), (unsigned long)child->pid);
  281. childisbad = 1;
  282. }
  283. else {
  284. SASSERTX(command == SOCKD_FREESLOT);
  285. ++child->freec;
  286. }
  287. clearset(SOCKD_FREESLOT, child, &rset);
  288. if (childisbad)
  289. removechild(child->pid);
  290. }
  291. /* next, get new requests. */
  292. while ((child = getset(SOCKD_NEWREQUEST, &rset)) != NULL) {
  293. int childisbad = 0;
  294. #if DIAGNOSTIC
  295. int freed = freedescriptors(config.option.debug ? "start" : NULL);
  296. #endif
  297. switch (child->type) {
  298. /*
  299.  * in the order a packet travels between children;
  300.  * negotiate -> request -> io.
  301.  */
  302. case CHILD_NEGOTIATE: {
  303. int flags;
  304. struct sockd_request_t req;
  305. struct sockd_child_t *reqchild;
  306. if ((reqchild = nextchild(CHILD_REQUEST)) == NULL)
  307. break; /* no child to accept a new request. */
  308. SASSERTX(reqchild->freec > 0);
  309. /* receive request from negotiator child... */
  310. if ((p = recv_req(child->s, &req)) != 0) {
  311. childisbad = 1;
  312. break;
  313. }
  314. ++config.stat.negotiate.received;
  315. /* set descriptor to blocking for request... */
  316. if ((flags = fcntl(req.s, F_GETFL, 0)) == -1
  317. ||  fcntl(req.s, F_SETFL, flags & ~O_NONBLOCK) == -1)
  318. swarn("%s: fcntl()");
  319. /* and send it to a request child. */
  320. if ((p = send_req(reqchild->s, &req)) == 0) {
  321. --reqchild->freec;
  322. ++config.stat.request.sendt;
  323. }
  324. else {
  325. clearset(SOCKD_NEWREQUEST, child, &rset);
  326. childisbad = 1;
  327. child = reqchild;
  328. }
  329. close(req.s);
  330. break;
  331. }
  332. case CHILD_REQUEST: {
  333. struct sockd_io_t io;
  334. struct sockd_child_t *iochild;
  335. if ((iochild = nextchild(CHILD_IO)) == NULL)
  336. break; /* no child to accept new io. */
  337. SASSERTX(iochild->freec > 0);
  338. /* get io from request child ... */
  339. if ((p = recv_io(child->s, &io)) != 0) {
  340. childisbad = 1;
  341. break;
  342. }
  343. ++config.stat.request.received;
  344. /* and send it to a io child. */
  345. if ((p = send_io(iochild->s, &io)) == 0) {
  346. --iochild->freec;
  347. ++config.stat.io.sendt;
  348. }
  349. else {
  350. clearset(SOCKD_NEWREQUEST, child, &rset);
  351. childisbad = 1;
  352. child = iochild;
  353. }
  354. close_iodescriptors(&io);
  355. break;
  356. }
  357. case CHILD_IO:
  358. /*
  359.  * the only thing a iochild should return is a ack each time
  360.  * it finishes with a io, that is handled in loop above.
  361.  */
  362. break;
  363. }
  364. #if DIAGNOSTIC
  365. SASSERTX(freed == freedescriptors(config.option.debug ? "end" : NULL));
  366. #endif
  367. clearset(SOCKD_NEWREQUEST, child, &rset);
  368. if (childisbad) /* error/eof from child. */
  369. switch (errno) {
  370. case EMFILE:
  371. case ENFILE:
  372. break; /* child is ok, we are not. */
  373. default:
  374. removechild(child->pid);
  375. }
  376. }
  377. /* handled our children.  Is there a new connection pending? */
  378. for (p = 0; p < config.internalc; ++p) {
  379. char accepted[MAXSOCKADDRSTRING];
  380. if (FD_ISSET(config.internalv[p].s, &rset)) {
  381. const struct listenaddress_t *l = &config.internalv[p];
  382. struct sockd_child_t *negchild;
  383. struct sockaddr from;
  384. socklen_t len;
  385. if ((negchild = nextchild(CHILD_NEGOTIATE)) == NULL)
  386. break;  /* no free negotiator children, don't accept(). */
  387. #if NEED_ACCEPTLOCK
  388. if (config.option.serverc > 1)
  389. if (socks_lock(l->lock, F_WRLCK, 0) != 0)
  390. continue;
  391. #endif
  392. #if HAVE_SENDMSG_DEADLOCK
  393. if (socks_lock(negchild->lock, F_WRLCK, 0) != 0) {
  394. #if NEED_ACCEPTLOCK
  395. if (config.option.serverc > 1)
  396. socks_unlock(l->lock);
  397. #endif /* NEED_ACCEPTLOCK */
  398. continue;
  399. }
  400. #endif /* HAVE_SENDMSG_DEADLOCK */
  401. len = sizeof(from);
  402. if ((client = acceptn(l->s, &from, &len)) == -1)
  403. switch (errno) {
  404. #ifdef EPROTO
  405. case EPROTO: /* overloaded SVR4 error */
  406. #endif
  407. case EWOULDBLOCK: /* BSD */
  408. case ECONNABORTED: /* POSIX */
  409. /* rest appears to be linux stuff according to apache src. */
  410. #ifdef ECONNRESET
  411. case ECONNRESET:
  412. #endif
  413. #ifdef ETIMEDOUT
  414. case ETIMEDOUT:
  415. #endif
  416. #ifdef EHOSTUNREACH
  417. case EHOSTUNREACH:
  418. #endif
  419. #ifdef ENETUNREACH
  420. case ENETUNREACH:
  421. #endif
  422. #if NEED_ACCEPTLOCK
  423. if (config.option.serverc > 1)
  424. socks_unlock(l->lock);
  425. #endif /* NEED_ACCEPTLOCK */
  426. #if HAVE_SENDMSG_DEADLOCK
  427. socks_unlock(negchild->lock);
  428. #endif /* HAVE_SENDMSG_DEADLOCK */
  429. continue; /* connection aborted/failed. */
  430. case ENFILE:
  431. continue;
  432. /*
  433.  * this should never happen since childcheck(), if
  434.  * initially successful, should make sure there is
  435.  * always enough descriptors available.
  436.  */
  437. case EMFILE:
  438. /* FALLTHROUGH */
  439. default:
  440. SERR(client);
  441. }
  442. #if HAVE_LINUX_BUGS
  443. /*
  444.  * yes, linux manages to lose the descriptor flags, workaround
  445.  * might be insufficient.
  446.  */
  447. if (fcntl(client, F_SETFL, fcntl(l->s, F_GETFL, 0)) != 0)
  448. swarn("tried to work around linux bug via fcntl()");
  449. #endif /* HAVE_LINUX_BUGS */
  450. ++config.stat.accepted;
  451. #if NEED_ACCEPTLOCK
  452. if (config.option.serverc > 1)
  453. socks_unlock(l->lock);
  454. #endif
  455. slog(LOG_DEBUG, "got accept(): %s",
  456. sockaddr2string(&from, accepted, sizeof(accepted)));
  457. if (send_client(negchild->s, client) == 0) {
  458. --negchild->freec;
  459. ++config.stat.negotiate.sendt;
  460. }
  461. else
  462. switch (errno) {
  463. case EMFILE:
  464. case ENFILE:
  465. break; /* child is ok, we are not. */
  466. default:
  467. removechild(negchild->pid);
  468. }
  469. #if HAVE_SENDMSG_DEADLOCK
  470. socks_unlock(negchild->lock);
  471. #endif /* HAVE_SENDMSG_DEADLOCK */
  472. close(client);
  473. }
  474. }
  475. }
  476. /* NOTREACHED */
  477. }
  478. int
  479. pidismother(pid)
  480. pid_t pid;
  481. {
  482. int i;
  483. for (i = 0; i < config.option.serverc; ++i)
  484. if (config.state.motherpidv[i] == pid)
  485. return i + 1;
  486. return 0;
  487. }
  488. static void
  489. usage(code)
  490. int code;
  491. {
  492. fprintf(code == 0 ? stdout : stderr,
  493. "%s: usage: %s [-DLNdfhlnv]n"
  494. "t -D             : run in daemon moden"
  495. "t -L             : shows the license for this programn"
  496.    "t -N <number>    : fork of <number> servers (default: 1)n"
  497. "t -d             : enable debuggingn"
  498. "t -f <filename>  : use <filename> as configuration filen"
  499. "t -h             : print this informationn"
  500. "t -l             : linebuffer outputn"
  501.    "t -n             : disable TCP keep-aliven"
  502. "t -v             : print version infon",
  503. __progname, __progname);
  504. exit(code);
  505. }
  506. static void
  507. showversion(void)
  508. {
  509. printf("%s: %s v%sn", __progname, PACKAGE, VERSION);
  510. exit(EXIT_SUCCESS);
  511. }
  512. static void
  513. showlicense(void)
  514. {
  515. printf("%s: %s v%sn%sn", __progname, PACKAGE, VERSION,
  516. "
  517. /*n
  518.  * Copyright (c) 1997, 1998, 1999n
  519.  *      Inferno Nettverk A/S, Norway.  All rights reserved.n
  520.  *n
  521.  * Redistribution and use in source and binary forms, with or withoutn
  522.  * modification, are permitted provided that the following conditionsn
  523.  * are met:n
  524.  * 1. The above copyright notice, this list of conditions and the followingn
  525.  *    disclaimer must appear in all copies of the software, derivative worksn
  526.  *    or modified versions, and any portions thereof, aswell as in alln
  527.  *    supporting documentation.n
  528.  * 2. All advertising materials mentioning features or use of this softwaren
  529.  *    must display the following acknowledgement:n
  530.  *      This product includes software developed byn
  531.  *      Inferno Nettverk A/S, Norway.n
  532.  * 3. The name of the author may not be used to endorse or promote productsn
  533.  *    derived from this software without specific prior written permission.n
  534.  *n
  535.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ORn
  536.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIESn
  537.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. n
  538.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,n
  539.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUTn
  540.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,n
  541.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANYn
  542.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT n
  543.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFn
  544.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.n
  545.  *n
  546.  * Inferno Nettverk A/S requests users of this software to return ton
  547.  * n
  548.  *  Software Distribution Coordinator  or  sdc@inet.non
  549.  *  Inferno Nettverk A/Sn
  550.  *  Oslo Research Parkn
  551.  *  Gaustadal閑n 21n
  552.  *  N-0349 Oslon
  553.  *  Norwayn
  554.  * n
  555.  * any improvements or extensions that they make and grant Inferno Nettverk A/Sn
  556.  * the rights to redistribute these changes.n
  557.  *n
  558.  */");
  559. exit(EXIT_SUCCESS);
  560. }
  561. /* ARGSUSED */ /* need envp if no HAVE_SETPROCTITLE */
  562. static void
  563. serverinit(argc, argv, envp)
  564. int argc;
  565. char *argv[];
  566. char *envp[];
  567. {
  568. const char *function = "serverinit()";
  569. uid_t euid;
  570. int ch, i;
  571. #if !HAVE_PROGNAME
  572. if (argv[0] != NULL)
  573. if ((__progname = strrchr(argv[0], '/')) == NULL)
  574. __progname = argv[0];
  575. else
  576. ++__progname;
  577. #endif  /* !HAVE_PROGNAME */
  578. #if !HAVE_SETPROCTITLE
  579. if (initsetproctitle(argc, argv, envp) == -1)
  580. serr(EXIT_FAILURE, "malloc");
  581. #endif  /* !HAVE_SETPROCTITLE*/
  582. config.state.addchild = 1;
  583. config.state.euid = geteuid();
  584. config.state.type = CHILD_MOTHER;
  585. config.option.serverc = 1; /* ourselves. ;-) */
  586. while ((ch = getopt(argc, argv, "DLN:df:hlnvw:")) != -1) {
  587. switch (ch) {
  588. case 'D':
  589. config.option.daemon = 1;
  590. break;
  591. case 'L':
  592. showlicense();
  593. /* NOTREACHED */
  594. case 'N':
  595. if ((config.option.serverc = atoi(optarg)) < 1)
  596. serrx(1, "%s: illegal value for -%c: %d",
  597. function, ch, config.option.serverc);
  598. break;
  599. case 'd':
  600. ++config.option.debug;
  601. break;
  602. case 'f':
  603. #if !HAVE_SETPROCTITLE
  604. /* let it point outside argv for replacement setproctitle(). */
  605. if ((config.option.configfile = strdup(optarg)) == NULL)
  606. serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);
  607. #else
  608. config.option.configfile = optarg;
  609. #endif /* !HAVE_SETPROCTITLE */
  610. break;
  611. case 'h':
  612. usage(0);
  613. /* NOTREACHED */
  614. case 'l':
  615. config.option.lbuf = 1;
  616. break;
  617. case 'n':
  618. config.option.keepalive = 0;
  619. break;
  620. case 'v':
  621. showversion();
  622. /* NOTREACHED */
  623. case 'w':
  624. config.option.sleep = atoi(optarg);
  625. break;
  626. default:
  627. usage(1);
  628. }
  629. }
  630. if (config.option.daemon)
  631. if (daemon(1, 0) != 0)
  632. serr(EXIT_FAILURE, "daemon()");
  633. config.state.pid = getpid();
  634. if ((config.state.motherpidv
  635. = (pid_t *)malloc(sizeof(*config.state.motherpidv) * config.option.serverc))
  636. == NULL)
  637. serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);
  638. *config.state.motherpidv = config.state.pid; /* main server. */
  639. if (config.option.configfile == NULL)
  640. config.option.configfile = SOCKD_CONFIGFILE;
  641. genericinit();
  642. checksettings();
  643. socks_seteuid(&euid, config.uid.privileged);
  644. for (i = 0; i < config.internalc; ++i) {
  645. int flags;
  646. struct listenaddress_t *l = &config.internalv[i];
  647. if ((l->s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  648. serr(EXIT_FAILURE, "%s: socket(SOCK_STREAM)", function);
  649. setsockoptions(l->s);
  650. ch = 1;
  651. if (setsockopt(l->s, SOL_SOCKET, SO_REUSEADDR, &ch, sizeof(ch))
  652. != 0)
  653. swarn("%s: setsockopt(SO_REUSEADDR)", function);
  654. /* LINTED pointer casts may be troublesome */
  655. if (sockd_bind(l->s, (struct sockaddr *)&l->addr, 0) != 0) {
  656. char badbind[MAXSOCKADDRSTRING];
  657. /* LINTED pointer casts may be troublesome */
  658. serr(EXIT_FAILURE, "%s: bind(%s)",
  659. function, sockaddr2string((struct sockaddr *)&l->addr, badbind,
  660. sizeof(badbind)));
  661. }
  662. if (listen(l->s, SOCKD_MAXCLIENTQUE) == -1)
  663. serr(EXIT_FAILURE, "%s: listen(%d)", function, SOCKD_MAXCLIENTQUE);
  664. if ((flags = fcntl(l->s, F_GETFL, 0)) == -1
  665. ||  fcntl(l->s, F_SETFL, flags | O_NONBLOCK) == -1)
  666. serr(EXIT_FAILURE, "%s: fcntl()", function);
  667. #if NEED_ACCEPTLOCK
  668. if (config.option.serverc > 1)
  669. if ((l->lock = socks_mklock(SOCKS_LOCKFILE)) == -1)
  670. serr(EXIT_FAILURE, "%s: socks_mklock()", function);
  671. #endif
  672. }
  673. socks_reseteuid(config.uid.privileged, euid);
  674. }
  675. static void
  676. checksettings(void)
  677. {
  678. const char *function = "checksettings()";
  679. int i;
  680. uid_t euid;
  681. /*
  682.  * Check arguments and settings, do they make sense?
  683.  */
  684. if (config.internalc == 0)
  685. serrx(EXIT_FAILURE, "%s: no internal address given", function);
  686. if (config.externalc == 0)
  687. serrx(EXIT_FAILURE, "%s: no external address given", function);
  688. for (i = 0; i < config.externalc; ++i) {
  689. int s;
  690. if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  691. switch (errno) {
  692. case EMFILE:
  693. case ENFILE:
  694. case ENOBUFS:
  695. break; /* assume this is temporary, e.g. after sighup. */
  696. default:
  697. serrx(EXIT_FAILURE, "%s: socket()", function);
  698. }
  699. else {
  700. char addrstring[MAXSOCKADDRSTRING];
  701. if (bind(s, (struct sockaddr *)&config.externalv[i],
  702. sizeof(config.externalv[i])) != 0)
  703. serrx(EXIT_FAILURE, "%s: can't bind external address: %s",
  704. function, sockaddr2string((struct sockaddr *)&config.externalv[i],
  705. addrstring, sizeof(addrstring)));
  706. close(s);
  707. }
  708. }
  709. if (config.methodc == 0)
  710. swarnx("%s: no methods enabled (total block)", function);
  711. if (!config.uid.privileged_isset)
  712. serrx(EXIT_FAILURE, "%s: privileged user not set", function);
  713. socks_seteuid(&euid, config.uid.privileged);
  714. socks_reseteuid(config.uid.privileged, euid);
  715. if (!config.uid.unprivileged_isset)
  716. serrx(EXIT_FAILURE, "%s: unprivileged user not set", function);
  717. socks_seteuid(&euid, config.uid.unprivileged);
  718. socks_reseteuid(config.uid.unprivileged, euid);
  719. #if HAVE_LIBWRAP
  720. if (!config.uid.libwrap_isset)
  721. serrx(EXIT_FAILURE, "%s: libwrap user not set", function);
  722. socks_seteuid(&euid, config.uid.libwrap);
  723. socks_reseteuid(config.uid.libwrap, euid);
  724. #endif /* HAVE_LIBWRAP */
  725. }
  726. /* ARGSUSED */
  727. static void
  728. siginfo(sig)
  729. int sig;
  730. {
  731. unsigned long seconds, days, hours, minutes;
  732. size_t clients;
  733. clients = 0;
  734. clients += childcheck(-CHILD_NEGOTIATE);
  735. clients += childcheck(-CHILD_REQUEST);
  736. clients += childcheck(-CHILD_IO);
  737. clients -= childcheck(CHILD_NEGOTIATE);
  738. clients -= childcheck(CHILD_REQUEST);
  739. clients -= childcheck(CHILD_IO);
  740. seconds = difftime(time(NULL), config.stat.boot);
  741. if (seconds >= 3600 * 24) {
  742. days = seconds / (3600 * 24);
  743. seconds -= days * 3600 * 24;
  744. }
  745. else
  746. days = 0;
  747. if (seconds >= 3600) {
  748. hours = seconds / 3600;
  749. seconds -= hours * 3600;
  750. }
  751. else
  752. hours = 0;
  753. if (seconds >= 60) {
  754. minutes = seconds / 60;
  755. seconds -= minutes * 60;
  756. }
  757. else
  758. minutes = 0;
  759. slog(LOG_INFO, "%s v%s up %lu day%s, %lu:%.2lu, a: %lu, c: %lu",
  760. PACKAGE, VERSION, days, days == 1 ? "" : "s", hours, minutes,
  761. (unsigned long)config.stat.accepted, (unsigned long)clients);
  762. slog(LOG_INFO, "negotiators (%d): a: %lu, h: %lu, c: %lu",
  763. childcheck(-CHILD_NEGOTIATE) / SOCKD_NEGOTIATEMAX,
  764. (unsigned long)config.stat.negotiate.sendt,
  765. (unsigned long)config.stat.negotiate.received,
  766. (unsigned long)childcheck(-CHILD_NEGOTIATE) - childcheck(CHILD_NEGOTIATE));
  767. slog(LOG_INFO, "requests (%d): a: %lu, h: %lu, c: %lu",
  768. childcheck(-CHILD_REQUEST) / SOCKD_REQUESTMAX,
  769. (unsigned long)config.stat.request.sendt,
  770. (unsigned long)config.stat.request.received,
  771. (unsigned long)childcheck(-CHILD_REQUEST) - childcheck(CHILD_REQUEST));
  772. slog(LOG_INFO, "iorelayers (%d): a: %lu, h: %lu, c: %lu",
  773. childcheck(-CHILD_IO) / SOCKD_IOMAX,
  774. (unsigned long)config.stat.io.sendt, (unsigned long)config.stat.io.sendt,
  775. (unsigned long)childcheck(-CHILD_IO) - childcheck(CHILD_IO));
  776. if (*config.state.motherpidv == config.state.pid) /* main mother */
  777. sigserverbroadcast(sig);
  778. sigchildbroadcast(sig, CHILD_NEGOTIATE | CHILD_REQUEST | CHILD_IO);
  779. }
  780. /* ARGSUSED */
  781. static void
  782. sighup(sig)
  783. int sig;
  784. {
  785. const char *function = "sighup()";
  786. uid_t euid;
  787. int p;
  788. slog(LOG_INFO, function);
  789. resetconfig();
  790. socks_seteuid(&euid, config.state.euid);
  791. genericinit();
  792. socks_reseteuid(config.state.euid, euid);
  793. checksettings();
  794. /* LINTED assignment in conditional context */
  795. if ((p = pidismother(config.state.pid))) {
  796. if (p == 1) { /* main mother. */
  797. showconfig(&config);
  798. sigserverbroadcast(sig);
  799. }
  800. sigchildbroadcast(sig, CHILD_NEGOTIATE | CHILD_REQUEST | CHILD_IO);
  801. }
  802. }
  803. /* ARGSUSED */
  804. static void
  805. sigchld(sig)
  806. int sig;
  807. {
  808. const char *function = "sigchld()";
  809. static time_t deathtime;
  810. static int deaths;
  811. int status;
  812. pid_t pid;
  813. while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
  814. int i;
  815. /*
  816.  * No child should normally die, but try to cope with it happening.
  817.  */
  818. /* LINTED assignment in conditional context */
  819. if ((i = pidismother(pid)))
  820. config.state.motherpidv[i - 1] = 0;
  821. else
  822. ; /* assume relay child. */
  823. ++deaths;
  824. }
  825. /*
  826.  * If we get alot of childdeaths in a short time, assume something
  827.  * is wrong.
  828.  */
  829. if (deathtime == 0)
  830. time(&deathtime);
  831. if (difftime(time(NULL), deathtime) > 60) { /* enough time passed; reset. */
  832. deaths = 0;
  833. time(&deathtime);
  834. }
  835. if (deaths >= 10) {
  836. if (deaths == 10) { /* log once. */
  837. slog(LOG_ERR, "%s: %d childdeaths in %.0fs; locking count for a while",
  838. function, deaths, difftime(time(NULL), deathtime));
  839. config.state.addchild = 0;
  840. }
  841. time(&deathtime); /* once the ball starts rolling... */
  842. alarm(60);
  843. }
  844. else
  845. config.state.addchild = 1; /* can try to add a new one. */
  846. }
  847. /* ARGSUSED */
  848. static void
  849. sigalrm(sig)
  850. int sig;
  851. {
  852. config.state.addchild = 1;
  853. }
  854. void
  855. sigserverbroadcast(sig)
  856. int sig;
  857. {
  858. int i;
  859. SASSERTX(*config.state.motherpidv == config.state.pid);
  860. for (i = 1; i < config.option.serverc; ++i)
  861. if (config.state.motherpidv[i] != 0)
  862. kill(config.state.motherpidv[i], sig);
  863. }