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

代理服务器

开发平台:

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_negotiate.c,v 1.65 1999/12/22 09:29:26 karls Exp $";
  46. __BEGIN_DECLS
  47. static int
  48. send_negotiate __P((const struct sockd_mother_t *mother,
  49.   const struct sockd_negotiate_t *neg));
  50. /*
  51.  * Sends "neg" to "s".  Also ack's that we have freed a slot to "s".
  52.  * Returns:
  53.  * On success: 0
  54.  * On failure: -1
  55.  * If some other problem prevented success: > 0
  56.  */
  57. static int
  58. recv_negotiate __P((const struct sockd_mother_t *mother));
  59. /*
  60.  * Tries to receive a client from mother "s".
  61.  * Returns:
  62.  * On success: 0
  63.  * If a error happened to connection with "s": -1
  64.  * If some other problem prevented success: > 0
  65.  */
  66. static void
  67. delete_negotiate __P((const struct sockd_mother_t *mother,
  68.  struct sockd_negotiate_t *neg));
  69. /*
  70.  * Frees any state occupied by "neg", including closing any
  71.  * descriptors and sending a ack that we have deleted a "negotiate"
  72.  * object to "mother".
  73.  */
  74. static int
  75. neg_fillset __P((fd_set *set));
  76. /*
  77.  * Sets all descriptors in our list in the set "set".
  78.  * Returns the highest descriptor in our list, or -1 if we don't
  79.  * have any descriptors open currently.
  80.  */
  81. static void
  82. neg_clearset __P((struct sockd_negotiate_t *neg, fd_set *set));
  83. /*
  84.  * Clears all filedescriptors in "neg" from "set".
  85.  */
  86. static struct sockd_negotiate_t *
  87. neg_getset __P((fd_set *set));
  88. /*
  89.  * Goes through our list until it finds a negotiate object where atleast
  90.  * one of the descriptors is set.
  91.  * Returns:
  92.  * On success: pointer to the found object.
  93.  * On failure: NULL.
  94.  */
  95. static int
  96. allocated __P((void));
  97. /*
  98.  * Returns the number of allocated (active) objects.
  99.  */
  100. static int
  101. completed __P((void));
  102. /*
  103.  * Returns the number of objects completed and ready to be sent currently.
  104.  */
  105. static int
  106. allocated __P((void));
  107. /*
  108.  * Returns the number of objects currently allocated for use.
  109.  */
  110. static void
  111. proctitleupdate __P((void));
  112. /*
  113.  * Updates the title of this process.
  114.  */
  115. static struct timeval *
  116. neg_gettimeout __P((struct timeval *timeout));
  117. /*
  118.  * Fills in "timeout" with time til the first clients connection
  119.  * expires.
  120.  * Returns:
  121.  * If there is a timeout: pointer to filled in "timeout".
  122.  * If there is no timeout: NULL.
  123.  */
  124. static struct sockd_negotiate_t *
  125. neg_gettimedout __P((void));
  126. /*
  127.  * Scans all clients for one that has timed out according to config
  128.  * settings.
  129.  * Returns:
  130.  * If timed out client found: pointer to it.
  131.  * Else: NULL.
  132.  */
  133. static void
  134. siginfo __P((int sig));
  135. /*
  136.  * Print information about our current connections.
  137.  */
  138. __END_DECLS
  139. static struct sockd_negotiate_t negv[SOCKD_NEGOTIATEMAX];
  140. static int negc = ELEMENTS(negv);
  141. void
  142. run_negotiate(mother)
  143. struct sockd_mother_t *mother;
  144. {
  145. const char *function = "run_negotiate()";
  146. struct sigaction sigact;
  147. sigemptyset(&sigact.sa_mask);
  148. sigact.sa_flags = SA_RESTART;
  149. sigact.sa_handler = siginfo;
  150. #if HAVE_SIGNAL_SIGINFO
  151. if (sigaction(SIGINFO, &sigact, NULL) != 0)
  152. serr(EXIT_FAILURE, "%s: sigaction(SIGINFO)", function);
  153. #endif  /* HAVE_SIGNAL_SIGINFO */
  154. /* same handler, for systems without SIGINFO. */
  155. if (sigaction(SIGUSR1, &sigact, NULL) != 0)
  156. serr(EXIT_FAILURE, "%s: sigaction(SIGINFO)", function);
  157. proctitleupdate();
  158. /* CONSTCOND */
  159. while (1) {
  160. fd_set rset, wsetmem, *wset = NULL;
  161. int fdbits, p;
  162. struct sockd_negotiate_t *neg;
  163. struct timeval timeout;
  164. fdbits = neg_fillset(&rset);
  165. FD_SET(mother->s, &rset);
  166. fdbits = MAX(fdbits, mother->s);
  167. /* if we have a completed request check whether we can send to mother. */
  168. if (completed() > 0) {
  169. FD_ZERO(&wsetmem);
  170. FD_SET(mother->s, &wsetmem);
  171. wset = &wsetmem;
  172. }
  173. ++fdbits;
  174. switch (selectn(fdbits, &rset, wset, NULL, neg_gettimeout(&timeout))) {
  175. case -1:
  176. SERR(-1);
  177. /* NOTREACHED */
  178. case 0: {
  179. const char *reason = "negotiation timed out";
  180. if ((neg = neg_gettimedout()) == NULL)
  181. continue; /* should only be possible if sighup received. */
  182. iolog(&neg->rule, &neg->state, OPERATION_ABORT, &neg->src,
  183. &neg->dst, reason, strlen(reason));
  184. delete_negotiate(mother, neg);
  185. continue;
  186. }
  187. }
  188. if (FD_ISSET(mother->s, &rset)) {
  189. if (recv_negotiate(mother) == -1)
  190. sockdexit(-EXIT_FAILURE);
  191. FD_CLR(mother->s, &rset);
  192. }
  193. while ((neg = neg_getset(&rset)) != NULL) {
  194. neg_clearset(neg, &rset);
  195. if ((p = recv_request(neg->s, &neg->req, &neg->negstate)) <= 0) {
  196. const char *reason = NULL; /* init or gcc complains. */
  197. switch (p) {
  198. case 0:
  199. reason = "eof from client";
  200. break;
  201. case -1:
  202. switch (errno) {
  203. case 0:
  204. reason = *neg->negstate.emsg == NUL ?
  205. "socks protocol error" : neg->negstate.emsg;
  206. break;
  207. case EINTR:
  208. case EAGAIN:
  209. #if EAGAIN != EWOULDBLOCK
  210. case EWOULDBLOCK:
  211. #endif
  212. continue; /* ok, retry. */
  213. default:
  214. reason = strerror(errno);
  215. }
  216. }
  217. iolog(&neg->rule, &neg->state, OPERATION_ABORT, &neg->src,
  218. &neg->dst, reason, strlen(reason));
  219. delete_negotiate(mother, neg);
  220. }
  221. else if (wset != NULL && FD_ISSET(mother->s, wset)) {
  222. /* read a complete request, send to mother. */
  223. switch (send_negotiate(mother, neg)) {
  224. case -1:
  225. sockdexit(-EXIT_FAILURE);
  226. /* NOTREACHED */
  227. case 0:
  228. delete_negotiate(mother, neg); /* sent to mother ok. */
  229. break;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. static int
  236. send_negotiate(mother, neg)
  237. const struct sockd_mother_t *mother;
  238. const struct sockd_negotiate_t *neg;
  239. {
  240. const char *function = "send_negotiate()";
  241. struct iovec iovec[1];
  242. struct sockd_request_t req;
  243. int fdsendt, w;
  244. struct msghdr msg;
  245. CMSG_AALLOC(sizeof(int));
  246. #if HAVE_SENDMSG_DEADLOCK
  247. if (socks_lock(mother->lock, F_WRLCK, 0) != 0)
  248. return 1;
  249. #endif /* HAVE_SENDMSG_DEADLOCK */
  250. /* copy needed fields from negotiate */
  251. /* LINTED pointer casts may be troublesome */
  252. sockshost2sockaddr(&neg->src, (struct sockaddr *)&req.from);
  253. req.req = neg->req;
  254. req.rule = neg->rule;
  255. req.state = neg->state;
  256. req.state.command = req.req.command;
  257. req.state.version = req.req.version;
  258. /* LINTED pointer casts may be troublesome */
  259. sockshost2sockaddr(&neg->dst, (struct sockaddr *)&req.to);
  260. iovec[0].iov_base = &req;
  261. iovec[0].iov_len = sizeof(req);
  262. fdsendt = 0;
  263. CMSG_ADDOBJECT(neg->s, sizeof(neg->s) * fdsendt++);
  264. msg.msg_iov = iovec;
  265. msg.msg_iovlen = ELEMENTS(iovec);
  266. msg.msg_name = NULL;
  267. msg.msg_namelen = 0;
  268. CMSG_SETHDR_SEND(sizeof(int) * fdsendt);
  269. slog(LOG_DEBUG, "sending request to mother");
  270. if ((w = sendmsg(mother->s, &msg, 0)) != sizeof(req))
  271. switch (errno) {
  272. case EAGAIN:
  273. case ENOBUFS:
  274. w = 1; /* temporal error. */
  275. break;
  276. default:
  277. swarn("%s: sendmsg(): %d of %d", function, w, sizeof(req));
  278. }
  279. #if HAVE_SENDMSG_DEADLOCK
  280. socks_unlock(mother->lock);
  281. #endif /* HAVE_SENDMSG_DEADLOCK */
  282. return w == sizeof(req) ? 0 : w;
  283. }
  284. static int
  285. recv_negotiate(mother)
  286. const struct sockd_mother_t *mother;
  287. {
  288. const char *function = "recv_negotiate()";
  289. struct sockd_negotiate_t *neg;
  290. struct iovec iovec[1];
  291. struct sockaddr addr;
  292. socklen_t len;
  293. unsigned char command;
  294. int permit, i, r, fdexpect, fdreceived;
  295. struct msghdr msg;
  296. CMSG_AALLOC(sizeof(int));
  297. iovec[0].iov_base = &command;
  298. iovec[0].iov_len = sizeof(command);
  299. msg.msg_iov = iovec;
  300. msg.msg_iovlen = ELEMENTS(iovec);
  301. msg.msg_name = NULL;
  302. msg.msg_namelen = 0;
  303. CMSG_SETHDR_RECV(sizeof(cmsgmem));
  304. if ((r = recvmsgn(mother->s, &msg, 0, sizeof(command))) != sizeof(command)) {
  305. switch (r) {
  306. case -1:
  307. swarn("%s: recvmsg() from mother", function);
  308. break;
  309. case 0:
  310. slog(LOG_DEBUG, "%s: recvmsg(): mother closed connection",
  311. function);
  312. break;
  313. default:
  314. swarnx("%s: recvmsg(): unexpected %d/%d bytes from mother",
  315. function, r, sizeof(command));
  316. }
  317. return -1;
  318. }
  319. fdexpect = 1; /* constant */
  320. SASSERTX(command == SOCKD_NEWREQUEST);
  321. /* find a free slot. */
  322. for (i = 0, neg = NULL; i < negc; ++i)
  323. if (!negv[i].allocated) {
  324. neg = &negv[i];
  325. break;
  326. }
  327. if (neg == NULL)
  328. SERRX(allocated());
  329. #if !HAVE_DEFECT_RECVMSG
  330. SASSERT(CMSG_GETLEN(msg) == sizeof(int) * fdexpect);
  331. #endif
  332. fdreceived = 0;
  333. CMSG_GETOBJECT(neg->s, sizeof(neg->s) * fdreceived++);
  334. /* get local and remote address. */
  335. len = sizeof(addr);
  336. if (getpeername(neg->s, &addr, &len) != 0) {
  337. swarn("%s: getpeername()", function);
  338. return 1;
  339. }
  340. sockaddr2sockshost(&addr, &neg->src);
  341. len = sizeof(addr);
  342. if (getsockname(neg->s, &addr, &len) != 0) {
  343. swarn("%s: getsockname()", function);
  344. return 1;
  345. }
  346. sockaddr2sockshost(&addr, &neg->dst);
  347. neg->state.command = SOCKS_ACCEPT;
  348. neg->state.protocol = SOCKS_TCP;
  349. neg->state.version = SOCKS_V5; /* anything valid. */
  350. neg->state.auth.method = AUTHMETHOD_NONE;
  351. /* pointer fixup */
  352. neg->req.auth = &neg->state.auth;
  353. permit = rulespermit(neg->s, &neg->rule, &neg->state, &neg->src, &neg->dst);
  354. iolog(&neg->rule, &neg->state, OPERATION_ACCEPT, &neg->src, &neg->dst,
  355. NULL, 0);
  356. neg->allocated = 1;
  357. if (!permit) {
  358. delete_negotiate(mother, neg);
  359. return 0;
  360. }
  361. time(&neg->state.time.negotiate_start);
  362. proctitleupdate();
  363. return 0;
  364. }
  365. static void
  366. delete_negotiate(mother, neg)
  367. const struct sockd_mother_t *mother;
  368. struct sockd_negotiate_t *neg;
  369. {
  370. const char *function = "delete_negotiate()";
  371. static const struct sockd_negotiate_t neginit;
  372. const char command = SOCKD_FREESLOT;
  373. SASSERTX(neg->allocated);
  374. close(neg->s);
  375. *neg = neginit;
  376. /* ack we have freed a slot. */
  377. if (writen(mother->ack, &command, sizeof(command)) != sizeof(command))
  378. swarn("%s: writen()", function);
  379. proctitleupdate();
  380. }
  381. static int
  382. neg_fillset(set)
  383. fd_set *set;
  384. {
  385. int i, max;
  386. FD_ZERO(set);
  387. for (i = 0, max = -1; i < negc; ++i)
  388. if (negv[i].allocated) {
  389. negv[i].ignore = 0;
  390. FD_SET(negv[i].s, set);
  391. max = MAX(max, negv[i].s);
  392. }
  393. return max;
  394. }
  395. static void
  396. neg_clearset(neg, set)
  397. struct sockd_negotiate_t *neg;
  398. fd_set *set;
  399. {
  400. FD_CLR(neg->s, set);
  401. neg->ignore = 1;
  402. }
  403. static struct sockd_negotiate_t *
  404. neg_getset(set)
  405. fd_set *set;
  406. {
  407. int i;
  408. for (i = 0; i < negc; ++i)
  409. if (negv[i].allocated) {
  410. if (negv[i].ignore)
  411. continue;
  412. if (negv[i].negstate.complete)
  413. return &negv[i];
  414. if (FD_ISSET(negv[i].s, set))
  415. return &negv[i];
  416. }
  417. return NULL;
  418. }
  419. static int
  420. allocated(void)
  421. {
  422. int i, alloc;
  423. for (i = 0, alloc = 0; i < negc; ++i)
  424. if (negv[i].allocated)
  425. ++alloc;
  426. return alloc;
  427. }
  428. static int
  429. completed(void)
  430. {
  431. int i, completec;
  432. for (i = 0, completec = 0; i < negc; ++i)
  433. if (negv[i].allocated && negv[i].negstate.complete)
  434. ++completec;
  435. return completec;
  436. }
  437. static void
  438. proctitleupdate(void)
  439. {
  440. setproctitle("negotiator: %d/%d", allocated(), SOCKD_NEGOTIATEMAX);
  441. }
  442. static struct timeval *
  443. neg_gettimeout(timeout)
  444. struct timeval *timeout;
  445. {
  446. time_t timenow;
  447. int i;
  448. if (config.timeout.negotiate == 0 || (allocated() == completed()))
  449. return NULL;
  450. timeout->tv_sec = config.timeout.negotiate;
  451. timeout->tv_usec = 0;
  452. time(&timenow);
  453. for (i = 0; i < negc; ++i)
  454. if (!negv[i].allocated)
  455. continue;
  456. else
  457. timeout->tv_sec = MAX(0, MIN(timeout->tv_sec,
  458. difftime(config.timeout.negotiate,
  459. (time_t)difftime(timenow, negv[i].state.time.negotiate_start))));
  460. return timeout;
  461. }
  462. static struct sockd_negotiate_t *
  463. neg_gettimedout(void)
  464. {
  465. int i;
  466. time_t timenow;
  467. if (config.timeout.negotiate == 0)
  468. return NULL;
  469. time(&timenow);
  470. for (i = 0; i < negc; ++i) {
  471. if (!negv[i].allocated)
  472. continue;
  473. if (negv[i].ignore)
  474. continue;
  475. else
  476. if (difftime(timenow, negv[i].state.time.negotiate_start)
  477. >= config.timeout.negotiate)
  478. return &negv[i];
  479. }
  480. return NULL;
  481. }
  482. /* ARGSUSED */
  483. static void
  484. siginfo(sig)
  485. int sig;
  486. {
  487. int i;
  488. time_t timenow;
  489. time(&timenow);
  490. for (i = 0; i < negc; ++i)
  491. if (!negv[i].allocated)
  492. continue;
  493. else {
  494. char srcstring[MAXSOCKSHOSTSTRING];
  495. slog(LOG_INFO, "%s: negotiating for %.0fs",
  496. sockshost2string(&negv[i].src, srcstring, sizeof(srcstring)),
  497. difftime(timenow, negv[i].state.time.negotiate_start));
  498. }
  499. }