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

代理服务器

开发平台:

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: config.c,v 1.119 1999/12/20 13:07:41 karls Exp $";
  46. __BEGIN_DECLS
  47. static int
  48. addrisinlist __P((const struct in_addr *addr, const struct in_addr *mask,
  49.   const struct in_addr **list));
  50. /*
  51.  * Compares "addr" bitwise anded with "mask" against each element in
  52.  * "list" bitwise anded with "mask".  "list" is NULL terminated.
  53.  * Returns:
  54.  * If "list" contains a element matching "addr" and "mask": true
  55.  * else: false
  56.  */
  57. static int
  58. addrareeq __P((const struct in_addr *addr, const struct in_addr *mask,
  59. const struct in_addr *against));
  60. /*
  61.  * Compares "addr" bitwise anded with "mask" against "against" bitwise
  62.  * anded with "mask".
  63.  * Returns:
  64.  * If "against" matches "addr" and "mask": true
  65.  * else: false
  66.  */
  67. static int
  68. hostisinlist __P((const char *host, const char **list));
  69. /*
  70.  * Compares "host" against each element in "list", which is NULL
  71.  * terminated.
  72.  * Note that if "host" starts with a dot, it will match "list" if the
  73.  * last part of "list" matches the part after the dot in "host".
  74.  * Returns:
  75.  * If "list" contains a element matching "host": true
  76.  * else: false
  77.  */
  78. static int
  79. hostareeq __P((const char *domain, const char *remotedomain));
  80. /*
  81.  * Compares the rulegiven domain "domain" against "remotedomain".
  82.  * Note that if "domain" starts with a dot, it will match
  83.  * "remotedomain" if the last part of "remotedomain" matches
  84.  * the part after the dot in "domain".
  85.  * Returns:
  86.  * on match: true
  87.  * else: false
  88.  */
  89. __END_DECLS
  90. void
  91. genericinit(void)
  92. {
  93. const char *function = "genericinit()";
  94. int i;
  95. if (!config.state.init) {
  96. #if !HAVE_SETPROCTITLE
  97. /* create a backup to avoid setproctitle replacement overwriting it. */
  98. if ((__progname = strdup(__progname)) == NULL)
  99. serrx(EXIT_FAILURE, "%s: %s", function, NOMEM);
  100. #endif /* !HAVE_SETPROCTITLE */
  101. }
  102. if (readconfig(config.option.configfile) != 0)
  103. #if SOCKS_SERVER
  104. exit(EXIT_FAILURE);
  105. #else
  106. return;
  107. #endif
  108. initlog();
  109. #if !HAVE_NO_RESOLVESTUFF
  110. res_init();
  111. #endif /* !HAVE_NO_RESOLVSTUFF */
  112. switch (config.resolveprotocol) {
  113. case RESOLVEPROTOCOL_TCP:
  114. #if !HAVE_NO_RESOLVESTUFF
  115. _res.options |= RES_USEVC;
  116. #else /* HAVE_NO_RESOLVESTUFF */
  117. SERRX(config.resolveprotocol);
  118. #endif  /* HAVE_NO_RESOLVESTUFF */
  119. break;
  120. case RESOLVEPROTOCOL_UDP:
  121. case RESOLVEPROTOCOL_FAKE:
  122. break;
  123. default:
  124. SERRX(config.resolveprotocol);
  125. }
  126. if (!config.state.init)
  127. if (config.option.lbuf)
  128. for (i = 0; i < config.log.fpc; ++i)
  129. if (setvbuf(config.log.fpv[i], NULL, _IOLBF, 0) != 0)
  130. swarn("%s: setvbuf(_IOLBF)", function);
  131. config.state.init = 1;
  132. }
  133. int
  134. addressmatch(rule, address, protocol, alias)
  135. const struct ruleaddress_t *rule;
  136. const struct sockshost_t *address;
  137. int protocol;
  138. int alias;
  139. {
  140. const char *function = "addressmatch()";
  141. struct hostent *hostent;
  142. in_port_t ruleport;
  143. int matched, doresolve;
  144. /* test port first since we have all info needed for that locally. */
  145. switch (protocol) {
  146. case SOCKS_TCP:
  147. ruleport = rule->port.tcp;
  148. break;
  149. case SOCKS_UDP:
  150. ruleport = rule->port.udp;
  151. break;
  152. default:
  153. SERRX(protocol);
  154. }
  155. switch (rule->operator) {
  156. case none:
  157. break;
  158. case eq:
  159. if (address->port == ruleport)
  160. break;
  161. return 0;
  162. case neq:
  163. if (address->port != ruleport)
  164. break;
  165. return 0;
  166. case ge:
  167. if (ntohs(address->port) >= ntohs(ruleport))
  168. break;
  169. return 0;
  170. case le:
  171. if (ntohs(address->port) <= ntohs(ruleport))
  172. break;
  173. return 0;
  174. case gt:
  175. if (ntohs(address->port) > ntohs(ruleport))
  176. break;
  177. return 0;
  178. case lt:
  179. if (ntohs(address->port) < ntohs(ruleport))
  180. break;
  181. return 0;
  182. case range:
  183. if (ntohs(address->port) >= ntohs(ruleport)
  184. &&  ntohs(address->port) <= ntohs(rule->portend))
  185. break;
  186. return 0;
  187. default:
  188. SERRX(rule->operator);
  189. }
  190. /* only needed for client really... */
  191. switch (config.resolveprotocol) {
  192. case RESOLVEPROTOCOL_TCP:
  193. case RESOLVEPROTOCOL_UDP:
  194. doresolve = 1;
  195. break;
  196. case RESOLVEPROTOCOL_FAKE:
  197. doresolve = 0;
  198. break;
  199. default:
  200. SERRX(config.resolveprotocol);
  201. }
  202. /*
  203.  * The hard work begins.
  204.  */
  205. matched = 0;
  206. if (rule->atype == SOCKS_ADDR_IPV4 && address->atype == SOCKS_ADDR_DOMAIN) {
  207. /*
  208.  * match(rule.ipaddress, address.hostname)
  209.  * resolve address to ipaddress(es) and try to match each
  210.  * resolved ipaddress against rule.
  211.  * rule is in address->ipaddress(es)
  212.  */
  213. if (!doresolve)
  214. return 0;
  215. /* LINTED pointer casts may be troublesome */
  216. if ((hostent = gethostbyname(address->addr.domain)) == NULL) {
  217. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  218. function, address->addr.domain, hstrerror(h_errno));
  219. return 0;
  220. }
  221. if (addrisinlist(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
  222. (const struct in_addr **)hostent->h_addr_list))
  223. matched = 1;
  224. }
  225. else if (rule->atype == SOCKS_ADDR_IPV4
  226. && address->atype == SOCKS_ADDR_IPV4) {
  227. /*
  228.  * match(rule.ipaddress, address.ipaddress)
  229.  * try first a simple comparison, address against rule.
  230.  */
  231. if (addrareeq(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
  232. &address->addr.ipv4))
  233. matched = 1;
  234. else {
  235. /*
  236.  * Didn't match.  If alias is set, try to resolve address
  237.  * to hostname(s), the hostname back to ipaddress(es) and
  238.  * then match those ipaddress(es) against rule.
  239.  * rule is in address->hostname(s)->ipaddress(es)
  240.  */
  241. if (!doresolve)
  242. return 0;
  243. if (alias) {
  244. char *nexthost;
  245. int i;
  246. /* LINTED pointer casts may be troublesome */
  247. if ((hostent = gethostbyaddr((const char *)&address->addr.ipv4,
  248. sizeof(address->addr.ipv4), AF_INET)) == NULL) {
  249. slog(LOG_DEBUG, "%s: %s: %s",
  250. function, inet_ntoa(address->addr.ipv4), hstrerror(h_errno));
  251. return 0;
  252. }
  253. if ((hostent = hostentdup(hostent)) == NULL) {
  254. swarnx("%s: hostentdup()", function);
  255. return 0;
  256. }
  257. nexthost = hostent->h_name;
  258. i = 0;
  259. do {
  260. struct hostent *iphostent;
  261. /* iphostent = address->hostname(s)->ipaddress(es) */
  262. if ((iphostent = gethostbyname(nexthost)) == NULL) {
  263. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  264. function, nexthost, hstrerror(h_errno));
  265. continue;
  266. }
  267. /* rule is in address->hostname(s)->ipaddress(es) */
  268. if (addrisinlist(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
  269. (const struct in_addr **)iphostent->h_addr_list)) {
  270. matched = 1;
  271. break;
  272. }
  273. } while (hostent->h_aliases != NULL
  274. && (nexthost = hostent->h_aliases[i++]) != NULL);
  275. hostentfree(hostent);
  276. }
  277. if (!matched)
  278. return 0;
  279. }
  280. }
  281. else if (rule->atype == SOCKS_ADDR_DOMAIN
  282. && address->atype == SOCKS_ADDR_DOMAIN) {
  283. /*
  284.  * match(rule.hostname, address.hostname)
  285.  * Try simple match first.
  286.  *
  287.  * If no go and rule is a hostname rather than a domain,
  288.  * resolve both rule and address to ipaddress(es) and compare
  289.  * each ipaddress of resolved rule against each ipaddress of
  290.  * resolved address.
  291.  * rule->ipaddress(es) is in address->ipaddress(es)
  292.  *
  293.  */
  294. if (hostareeq(rule->addr.domain, address->addr.domain))
  295. matched = 1;
  296. else if (doresolve && *rule->addr.domain != '.') {
  297. struct hostent *addresshostent;
  298. struct in_addr mask;
  299. int i;
  300. if ((hostent = gethostbyname(rule->addr.domain)) == NULL) {
  301. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  302. function, rule->addr.domain, hstrerror(h_errno));
  303. return 0;
  304. }
  305. if ((hostent = hostentdup(hostent)) == NULL) {
  306. swarnx("%s: hostentdup()", function);
  307. return 0;
  308. }
  309. if ((addresshostent = gethostbyname(address->addr.domain)) == NULL) {
  310. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  311. function, address->addr.domain, hstrerror(h_errno));
  312. hostentfree(hostent);
  313. return 0;
  314. }
  315. /*
  316.  * rule->ipaddress(es) is in address->ipaddress(es)
  317.  */
  318. for (i = 0, mask.s_addr = htonl(0xffffffff);
  319. hostent->h_addr_list != NULL && hostent->h_addr_list[i] != NULL;
  320. ++i) {
  321. /* LINTED pointer casts may be troublesome */
  322. if (addrisinlist((const struct in_addr *)hostent->h_addr_list[i],
  323. &mask, (const struct in_addr **)addresshostent->h_addr_list)) {
  324. matched = 1;
  325. break;
  326. }
  327. }
  328. hostentfree(hostent);
  329. }
  330. if (!matched)
  331. return 0;
  332. }
  333. else if (rule->atype == SOCKS_ADDR_DOMAIN
  334. && address->atype == SOCKS_ADDR_IPV4) {
  335. /*
  336.  * match(rule.hostname, address.ipaddress)
  337.  * If rule is not a domain, try resolving rule to ipaddress(es)
  338.  * and match against address.
  339.  * address is in rule->ipaddress
  340.  *
  341.  * If no match, resolve address to hostname(s) and match each
  342.  * against rule.
  343.  * rule is in address->hostname
  344.  *
  345.  * If still no match and alias is set, resolve all ipaddresses
  346.  * of all hostname(s) resolved from address back to hostname(s)
  347.  * and match them against rule.
  348.  * rule is in address->hostname->ipaddress->hostname
  349.  */
  350. if (!doresolve)
  351. return 0;
  352. if (*rule->addr.domain != '.') {
  353. /* address is in rule->ipaddress */
  354. struct in_addr mask;
  355. if ((hostent = gethostbyname(rule->addr.domain)) == NULL) {
  356. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  357. function, rule->addr.domain, hstrerror(h_errno));
  358. return 0;
  359. }
  360. mask.s_addr = htonl(0xffffffff);
  361. if (addrisinlist(&address->addr.ipv4, &mask,
  362. (const struct in_addr **)hostent->h_addr_list))
  363. matched = 1;
  364. }
  365. if (!matched) {
  366. /* rule is in address->hostname */
  367. /* LINTED pointer casts may be troublesome */
  368. if ((hostent = gethostbyaddr((const char *)&address->addr.ipv4,
  369. sizeof(address->addr.ipv4), AF_INET)) == NULL) {
  370. slog(LOG_DEBUG, "%s: gethostbyaddr(%s): %s",
  371. function, inet_ntoa(address->addr.ipv4), hstrerror(h_errno));
  372. return 0;
  373. }
  374. if (hostareeq(rule->addr.domain, hostent->h_name)
  375. ||  hostisinlist(rule->addr.domain, (const char **)hostent->h_aliases))
  376. matched = 1;
  377. }
  378. if (!matched && alias) {
  379. /*
  380.  * rule is in address->hostname->ipaddress->hostname.
  381.  * hostent is already address->hostname due to above.
  382.  */
  383. char *nexthost;
  384. int i;
  385. if ((hostent = hostentdup(hostent)) == NULL) {
  386. swarnx("%s: hostentdup()", function);
  387. return 0;
  388. }
  389. nexthost = hostent->h_name;
  390. i = 0;
  391. do {
  392. int ii;
  393. struct hostent *host;
  394. /* host; address->hostname->ipaddress */
  395. if ((host = gethostbyname(nexthost)) == NULL) {
  396. slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
  397. function, nexthost, hstrerror(h_errno));
  398. continue;
  399. }
  400. if ((host = hostentdup(host)) == NULL) {
  401. swarnx("%s: hostentdup()", function);
  402. break;
  403. }
  404. /* LINTED pointer casts may be troublesome */
  405. for (ii = 0;
  406. host->h_addr_list != NULL && host->h_addr_list[ii] != NULL;
  407. ++ii) {
  408. struct hostent *ip;
  409. /* ip; address->hostname->ipaddress->hostname */
  410. if ((ip = gethostbyaddr(host->h_addr_list[ii],
  411. sizeof(struct in_addr), AF_INET)) == NULL) {
  412. /* LINTED pointer casts may be troublesome */
  413. slog(LOG_DEBUG, "%s: gethostbyaddr(%s): %s",
  414. function, inet_ntoa(*(struct in_addr *)host->h_addr_list[ii]),
  415. hstrerror(h_errno));
  416. continue;
  417. }
  418. if (hostareeq(rule->addr.domain, ip->h_name)
  419. ||  hostisinlist(rule->addr.domain,
  420. (const char **)ip->h_aliases)) {
  421. matched = 1;
  422. break;
  423. }
  424. }
  425. hostentfree(host);
  426. } while (!matched && hostent->h_aliases != NULL
  427. && (nexthost = hostent->h_aliases[i++]) != NULL);
  428. hostentfree(hostent);
  429. }
  430. if (!matched)
  431. return 0;
  432. }
  433. else
  434. SERRX(0);
  435. return matched;
  436. }
  437. static int
  438. addrisinlist(addr, mask, list)
  439. const struct in_addr *addr;
  440. const struct in_addr *mask;
  441. const struct in_addr **list;
  442. {
  443. if (list == NULL)
  444. return 0;
  445. while (*list != NULL)
  446. if (addrareeq(addr, mask, *list))
  447. return 1;
  448. else
  449. ++list;
  450. return 0;
  451. }
  452. static int
  453. addrareeq(addr, mask, against)
  454. const struct in_addr *addr;
  455. const struct in_addr *mask;
  456. const struct in_addr *against;
  457. {
  458. if ((addr->s_addr & mask->s_addr) == (against->s_addr & mask->s_addr))
  459. return 1;
  460. return 0;
  461. }
  462. static int
  463. hostisinlist(host, list)
  464. const char *host;
  465. const char **list;
  466. {
  467. if (list == NULL)
  468. return 0;
  469. while (*list != NULL)
  470. if (hostareeq(host, *list))
  471. return 1;
  472. else
  473. ++list;
  474. return 0;
  475. }
  476. static int
  477. hostareeq(domain, remotedomain)
  478. const char *domain;
  479. const char *remotedomain;
  480. {
  481. const int domainlen = strlen(domain);
  482. const int remotedomainlen = strlen(remotedomain);
  483. if (*domain == '.') { /* match everything ending in domain */
  484. if (domainlen - 1 > remotedomainlen)
  485. return 0; /* address to compare against too short, can't match. */
  486. return strcasecmp(domain + 1,
  487. remotedomain + (remotedomainlen - (domainlen - 1))) == 0;
  488. }
  489. else /* need exact match. */
  490. return strcasecmp(domain, remotedomain) == 0;
  491. }
  492. #if SOCKS_CLIENT
  493. struct route_t *
  494. addroute(newroute)
  495. const struct route_t *newroute;
  496. {
  497. const char *function = "addroute()";
  498. static const struct serverstate_t state;
  499. struct route_t *route;
  500. if ((route = (struct route_t *)malloc(sizeof(*route))) == NULL)
  501. serrx(1, "%s: %s", function, NOMEM);
  502. *route = *newroute;
  503. /* check gateway. */
  504. /* if no command set, set all. */
  505. if (memcmp(&state.command, &route->gw.state.command, sizeof(state.command))
  506. == 0)
  507. memset(&route->gw.state.command, UCHAR_MAX,
  508. sizeof(route->gw.state.command));
  509. /* if no protocol set, set all. */
  510. if (memcmp(&state.protocol, &route->gw.state.protocol,
  511. sizeof(state.protocol)) == 0)
  512. memset(&route->gw.state.protocol, UCHAR_MAX,
  513. sizeof(route->gw.state.protocol));
  514. /* if no proxyprotocol set, set all except msproxy. */
  515. if (memcmp(&state.proxyprotocol, &route->gw.state.proxyprotocol,
  516. sizeof(state.proxyprotocol)) == 0) {
  517. memset(&route->gw.state.proxyprotocol, UCHAR_MAX,
  518. sizeof(route->gw.state.proxyprotocol));
  519. route->gw.state.proxyprotocol.msproxy_v2 = 0;
  520. }
  521. /* if no method set, set all we support. */
  522. if (route->gw.state.methodc == 0) {
  523. int *methodv = route->gw.state.methodv;
  524. int *methodc = &route->gw.state.methodc;
  525. methodv[(*methodc)++] = AUTHMETHOD_NONE;
  526. methodv[(*methodc)++] = AUTHMETHOD_UNAME;
  527. }
  528. if (config.route == NULL) {
  529. config.route = route;
  530. config.route->number = 1;
  531. }
  532. else {
  533. /* append rule to the end of list. */
  534. struct route_t *lastroute;
  535. lastroute = config.route;
  536. while (lastroute->next != NULL)
  537. lastroute = lastroute->next;
  538. route->number = lastroute->number + 1;
  539. lastroute->next = route;
  540. }
  541. route->next = NULL;
  542. return route;
  543. }
  544. void
  545. showroute(route)
  546. const struct route_t *route;
  547. {
  548. char hstring[MAXSOCKSHOSTSTRING];
  549. char addr[MAXRULEADDRSTRING];
  550. slog(LOG_INFO, "route #%d", route->number);
  551. slog(LOG_INFO, "src: %s",
  552. ruleaddress2string(&route->src, addr, sizeof(addr)));
  553. slog(LOG_INFO, "dst: %s",
  554. ruleaddress2string(&route->dst, addr, sizeof(addr)));
  555. slog(LOG_INFO, "gateway: %s",
  556. sockshost2string(&route->gw.host, hstring, sizeof(hstring)));
  557. showstate(&route->gw.state);
  558. }
  559. struct route_t *
  560. socks_getroute(req, src, dst)
  561. const struct request_t *req;
  562. const struct sockshost_t *src;
  563. const struct sockshost_t *dst;
  564. {
  565. struct route_t *route;
  566. int protocol;
  567. #if SOCKS_CLIENT
  568. clientinit();
  569. #endif
  570. for (route = config.route; route != NULL; route = route->next) {
  571. if (route->state.bad)
  572. continue; /* XXX code to retry and remove bad status when ok. */
  573. switch (req->version) {
  574. case SOCKS_V4:
  575. if (!route->gw.state.proxyprotocol.socks_v4)
  576. continue;
  577. switch (req->host.atype) {
  578. case SOCKS_ADDR_IPV4:
  579. break;
  580. case SOCKS_ADDR_IPV6:
  581. case SOCKS_ADDR_DOMAIN:
  582. continue; /* not failure, just checking. */
  583. default:
  584. SERRX(req->host.atype); /* failure, nothing else exists. */
  585. }
  586. break;
  587. case SOCKS_V5:
  588. if (!route->gw.state.proxyprotocol.socks_v5)
  589. continue;
  590. switch (req->host.atype) {
  591. case SOCKS_ADDR_IPV4:
  592. case SOCKS_ADDR_IPV6:
  593. case SOCKS_ADDR_DOMAIN:
  594. break;
  595. default:
  596. SERRX(req->host.atype); /* failure, nothing else exists. */
  597. }
  598. break;
  599. case MSPROXY_V2:
  600. if (!route->gw.state.proxyprotocol.msproxy_v2)
  601. continue;
  602. break;
  603. default:
  604. SERRX(req->version);
  605. }
  606. switch (req->command) {
  607. case SOCKS_BIND:
  608. if (!route->gw.state.command.bind)
  609. continue;
  610. if (req->host.atype == SOCKS_ADDR_IPV4
  611. &&  req->host.addr.ipv4.s_addr == htonl(0))
  612. if (req->version == MSPROXY_V2)
  613. ; /* supports binding wildcard */
  614. else if (!route->gw.state.extension.bind)
  615. continue;
  616. break;
  617. case SOCKS_CONNECT:
  618. if (!route->gw.state.command.connect)
  619. continue;
  620. break;
  621. case SOCKS_UDPASSOCIATE:
  622. if (!route->gw.state.command.udpassociate)
  623. continue;
  624. break;
  625. default:
  626. SERRX(req->command);
  627. }
  628. /* server supports protocol? */
  629. switch (req->command) {
  630. case SOCKS_BIND:
  631. case SOCKS_CONNECT:
  632. if (!route->gw.state.protocol.tcp)
  633. continue;
  634. protocol = SOCKS_TCP;
  635. break;
  636. case SOCKS_UDPASSOCIATE:
  637. if (!route->gw.state.protocol.udp)
  638. continue;
  639. protocol = SOCKS_UDP;
  640. break;
  641. default:
  642. SERRX(req->command);
  643. }
  644. if (src != NULL)
  645. if (!addressmatch(&route->src, src, protocol, 0))
  646. continue;
  647. if (dst != NULL)
  648. if (!addressmatch(&route->dst, dst, protocol, 0))
  649. continue;
  650. if (route->state.direct)
  651. return NULL; /* don't use any route, connect directly. */
  652. break; /* all matched */
  653. }
  654. return route;
  655. }
  656. struct route_t *
  657. socks_connectroute(s, packet, src, dst)
  658. int s;
  659. struct socks_t *packet;
  660. const struct sockshost_t *src;
  661. const struct sockshost_t *dst;
  662. {
  663. const char *function = "socks_connectroute()";
  664. int sdup, current_s, errno_s;
  665. struct route_t *route;
  666. /*
  667.  * This is a little tricky since we attempt to support trying
  668.  * more than one socksserver.  If the first one fails, we try
  669.  * the next, etc.  Ofcourse, if connect() on one socket fails,
  670.  * that socket can no longer be used, so we need to be able to
  671.  * copy/dup the original socket as much as possible.  Later,
  672.  * if it turned out a connection failed and we had to use a
  673.  * different socket than the orignal 's', we try to dup the
  674.  * differently numbered socket to 's' and hope the best.
  675.  *
  676.  * sdup: copy of the original socket.  Need to create this
  677.  * before the first connectattempt since the connectattempt
  678.  *    could prevent us from doing it later, depending on failure
  679.  * reason.
  680.  *
  681.  * current_s: socket to use for next connection attempt.  For the
  682.  * first attempt this is 's'.
  683.  */
  684. errno = 0; /* let caller differentiate between missing route and not.*/
  685. current_s = s;
  686. sdup = -1;
  687. while ((route = socks_getroute(&packet->req, src, dst)) != NULL) {
  688. char hstring[MAXSOCKSHOSTSTRING];
  689. /* inside loop since if no route, no need for it. */
  690. if (sdup == -1)
  691. sdup = socketoptdup(s);
  692. if (current_s == -1)
  693. if ((current_s = socketoptdup(sdup == -1 ? s : sdup)) == -1)
  694. return NULL;
  695. slog(LOG_DEBUG, "%s: trying route #%d (%s)",
  696. function, route->number,
  697. sockshost2string(&route->gw.host, hstring, sizeof(hstring)));
  698. if (socks_connect(current_s, &route->gw.host) == 0)
  699. break;
  700. else
  701. /*
  702.  * Check whether the error indicates bad socksserver or
  703.  * something else.
  704.  */
  705. if (errno == EINPROGRESS) {
  706. SASSERTX(current_s == s);
  707. break;
  708. }
  709. else if (errno == EADDRINUSE) {
  710. /* see Rbind() for explanation. */
  711. SASSERTX(current_s == s);
  712. route = NULL;
  713. break;
  714. }
  715. else {
  716. swarn("%s: socks_connect(%s)",
  717. function, sockshost2string(&route->gw.host, hstring,
  718. sizeof(hstring)));
  719. socks_badroute(route);
  720. close(current_s);
  721. current_s = -1;
  722. }
  723. }
  724. errno_s = errno;
  725. if (sdup != -1)
  726. close(sdup);
  727. if (current_s != s && current_s != -1) {
  728. /* created a new socket for connect, need to make it same descriptor #. */
  729. if (dup2(current_s, s) == -1) {
  730. close(current_s);
  731. return NULL;
  732. }
  733. close(current_s);
  734. #if SOCKS_SERVER && HAVE_LIBWRAP
  735. if ((current_s = fcntl(s, F_GETFD, 0)) == -1
  736. || fcntl(s, F_SETFD, current_s | FD_CLOEXEC) == -1)
  737. swarn("%s: fcntl(F_GETFD/F_SETFD)", function);
  738. #endif
  739. }
  740. if (route != NULL) {
  741. static int init;
  742. packet->gw = route->gw;
  743. /* need to set up misc. crap for msproxy stuff. */
  744. if (!init && route->gw.state.proxyprotocol.msproxy_v2) {
  745. if (msproxy_init() != 0)
  746. ; /* yes, then what? */
  747. init = 1;
  748. }
  749. }
  750. errno = errno_s;
  751. return route;
  752. }
  753. void
  754. socks_badroute(route)
  755. struct route_t *route;
  756. {
  757. const char *function = "socks_badroute()";
  758. slog(LOG_DEBUG, "%s: badrouting route #%d", function, route->number);
  759. route->state.bad = 1;
  760. }
  761. struct request_t *
  762. socks_requestpolish(req, src, dst)
  763. struct request_t *req;
  764. const struct sockshost_t *src;
  765. const struct sockshost_t *dst;
  766. {
  767. const char *function = "socks_requestpolish()";
  768. unsigned char version;
  769. if (socks_getroute(req, src, dst) != NULL)
  770. return req;
  771. switch (req->command) {
  772. case SOCKS_BIND:
  773. case SOCKS_CONNECT:
  774. break;
  775. case SOCKS_UDPASSOCIATE:
  776. SERRX(req->command); /* currently not implemented, shouldn't happen. */
  777. /* NOTREACHED */
  778. default:
  779. SERRX(req->command);
  780. }
  781. /* unsupported version? */
  782. switch (req->version) {
  783. case SOCKS_V4:
  784. req->version = SOCKS_V5;
  785. break;
  786. case SOCKS_V5:
  787. req->version = SOCKS_V4;
  788. break;
  789. }
  790. if (socks_getroute(req, src, dst) != NULL)
  791. return req;
  792. SASSERTX(req->version != MSPROXY_V2); /* never gets set outside function. */
  793. version = req->version;
  794. req->version = MSPROXY_V2;
  795. if (socks_getroute(req, src, dst) != NULL)
  796. return req;
  797. req->version = version;
  798. switch (req->command) {
  799. case SOCKS_BIND:
  800. if (req->host.addr.ipv4.s_addr == htonl(0)) {
  801. const in_port_t originalport = req->host.port;
  802. const int originalversion = req->version;
  803. /* attempting to use bind extension, can we retry without it? */
  804. /* LINTED pointer casts may be troublesome */
  805. if (ADDRISBOUND(config.state.lastconnect)) {
  806. fakesockaddr2sockshost(&config.state.lastconnect, &req->host);
  807. /*
  808.  * v4 and v5 differ in how portnumber is treated
  809.  * so we need to be a little smarter than just returning
  810.  * the result of the next socks_requestpolish()
  811.  * while we still have the original portnumber.
  812.  */
  813. switch (req->version) {
  814. case SOCKS_V4:
  815. /* LINTED pointer casts may be troublesome */
  816. req->host.port = ((struct sockaddr_in *)
  817. &config.state.lastconnect)->sin_port;
  818. break;
  819. case SOCKS_V5:
  820. /* only wants ip address. */
  821. req->host.port = originalport;
  822. break;
  823. default:
  824. SERRX(req->version);
  825. }
  826. if (socks_requestpolish(req, src, dst) == NULL)
  827. return NULL;
  828. /*
  829.  * else, it may be that socks_requestpolish() was
  830.  * forced to change req.version to succeed, we then
  831.  * need to change req->host.port due to difference in
  832.  * v4 and v5 semantics.
  833. */
  834. if (req->version != originalversion) { /* version changed. */
  835. /* currently it can only change from 4 to 5, or 5 to 4. */
  836. switch (req->version) {
  837. case SOCKS_V4:
  838. /* LINTED pointer casts may be troublesome */
  839. req->host.port = ((struct sockaddr_in *)
  840. &config.state.lastconnect)->sin_port;
  841. break;
  842. case SOCKS_V5:
  843. req->host.port = originalport;
  844. break;
  845. default:
  846. SERRX(req->version);
  847. }
  848. }
  849. return socks_requestpolish(req, src, dst);
  850. }
  851. else
  852. slog(LOG_DEBUG,
  853. "%s: couldn't find route for bind, try enabling bind extension?",
  854. function);
  855. }
  856. break;
  857. }
  858. return NULL;
  859. }
  860. #endif /* SOCKS_CLIENT */
  861. void
  862. showstate(state)
  863. const struct serverstate_t *state;
  864. {
  865. int i;
  866. char buf[1024];
  867. size_t bufused;
  868. bufused = snprintf(buf, sizeof(buf), "command(s): ");
  869. if (state->command.bind)
  870. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  871. SOCKS_BINDs);
  872. if (state->command.bindreply)
  873. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  874. SOCKS_BINDREPLYs);
  875. if (state->command.connect)
  876. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  877. SOCKS_CONNECTs);
  878. if (state->command.udpassociate)
  879. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  880. SOCKS_UDPASSOCIATEs);
  881. if (state->command.udpreply)
  882. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  883. SOCKS_UDPREPLYs);
  884. slog(LOG_INFO, buf);
  885. bufused = snprintf(buf, sizeof(buf), "extension(s): ");
  886. if (state->extension.bind)
  887. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "bind");
  888. slog(LOG_INFO, buf);
  889. bufused = snprintf(buf, sizeof(buf), "protocol(s): ");
  890. if (state->protocol.tcp)
  891. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  892. PROTOCOL_TCPs);
  893. if (state->protocol.udp)
  894. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  895. PROTOCOL_UDPs);
  896. slog(LOG_INFO, buf);
  897. bufused = snprintf(buf, sizeof(buf), "method(s): ");
  898. for (i = 0; i < state->methodc; ++i)
  899. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ",
  900. method2string(state->methodv[i]));
  901. slog(LOG_INFO, buf);
  902. bufused = snprintf(buf, sizeof(buf), "proxyprotocol(s): ");
  903. if (state->proxyprotocol.socks_v4)
  904. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "socks v4, ");
  905. if (state->proxyprotocol.socks_v5)
  906. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "socks v5, ");
  907. if (state->proxyprotocol.msproxy_v2)
  908. bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "msproxy v2");
  909. slog(LOG_INFO, buf);
  910. }