📄 config.c
字号:
if (list == NULL) return 0; while (*list != NULL) if (hostareeq(host, *list)) return 1; else ++list; return 0;}static inthostareeq(domain, remotedomain) const char *domain; const char *remotedomain;{ const int domainlen = strlen(domain); const int remotedomainlen = strlen(remotedomain); if (*domain == '.') { /* match everything ending in domain */ if (domainlen - 1 > remotedomainlen) return 0; /* address to compare against too short, can't match. */ return strcasecmp(domain + 1, remotedomain + (remotedomainlen - (domainlen - 1))) == 0; } else /* need exact match. */ return strcasecmp(domain, remotedomain) == 0;}#if SOCKS_CLIENTstruct route_t *addroute(newroute) const struct route_t *newroute;{ const char *function = "addroute()"; static const struct serverstate_t state; struct route_t *route; if ((route = (struct route_t *)malloc(sizeof(*route))) == NULL) serrx(1, "%s: %s", function, NOMEM); *route = *newroute; /* check gateway. */ /* if no command set, set all. */ if (memcmp(&state.command, &route->gw.state.command, sizeof(state.command)) == 0) memset(&route->gw.state.command, UCHAR_MAX, sizeof(route->gw.state.command)); /* if no protocol set, set all. */ if (memcmp(&state.protocol, &route->gw.state.protocol, sizeof(state.protocol)) == 0) memset(&route->gw.state.protocol, UCHAR_MAX, sizeof(route->gw.state.protocol)); /* if no proxyprotocol set, set all except msproxy. */ if (memcmp(&state.proxyprotocol, &route->gw.state.proxyprotocol, sizeof(state.proxyprotocol)) == 0) { memset(&route->gw.state.proxyprotocol, UCHAR_MAX, sizeof(route->gw.state.proxyprotocol)); route->gw.state.proxyprotocol.msproxy_v2 = 0; } /* if no method set, set all we support. */ if (route->gw.state.methodc == 0) { int *methodv = route->gw.state.methodv; int *methodc = &route->gw.state.methodc; methodv[(*methodc)++] = AUTHMETHOD_NONE; methodv[(*methodc)++] = AUTHMETHOD_UNAME; } if (config.route == NULL) { config.route = route; config.route->number = 1; } else { /* append rule to the end of list. */ struct route_t *lastroute; lastroute = config.route; while (lastroute->next != NULL) lastroute = lastroute->next; route->number = lastroute->number + 1; lastroute->next = route; } route->next = NULL; return route;}voidshowroute(route) const struct route_t *route;{ char hstring[MAXSOCKSHOSTSTRING]; char addr[MAXRULEADDRSTRING]; slog(LOG_INFO, "route #%d", route->number); slog(LOG_INFO, "src: %s", ruleaddress2string(&route->src, addr, sizeof(addr))); slog(LOG_INFO, "dst: %s", ruleaddress2string(&route->dst, addr, sizeof(addr))); slog(LOG_INFO, "gateway: %s", sockshost2string(&route->gw.host, hstring, sizeof(hstring))); showstate(&route->gw.state);}struct route_t *socks_getroute(req, src, dst) const struct request_t *req; const struct sockshost_t *src; const struct sockshost_t *dst;{ struct route_t *route; int protocol;#if SOCKS_CLIENT clientinit();#endif for (route = config.route; route != NULL; route = route->next) { if (route->state.bad) continue; /* XXX code to retry and remove bad status when ok. */ switch (req->version) { case SOCKS_V4: if (!route->gw.state.proxyprotocol.socks_v4) continue; switch (req->host.atype) { case SOCKS_ADDR_IPV4: break; case SOCKS_ADDR_IPV6: case SOCKS_ADDR_DOMAIN: continue; /* not failure, just checking. */ default: SERRX(req->host.atype); /* failure, nothing else exists. */ } break; case SOCKS_V5: if (!route->gw.state.proxyprotocol.socks_v5) continue; switch (req->host.atype) { case SOCKS_ADDR_IPV4: case SOCKS_ADDR_IPV6: case SOCKS_ADDR_DOMAIN: break; default: SERRX(req->host.atype); /* failure, nothing else exists. */ } break; case MSPROXY_V2: if (!route->gw.state.proxyprotocol.msproxy_v2) continue; break; default: SERRX(req->version); } switch (req->command) { case SOCKS_BIND: if (!route->gw.state.command.bind) continue; if (req->host.atype == SOCKS_ADDR_IPV4 && req->host.addr.ipv4.s_addr == htonl(0)) if (req->version == MSPROXY_V2) ; /* supports binding wildcard */ else if (!route->gw.state.extension.bind) continue; break; case SOCKS_CONNECT: if (!route->gw.state.command.connect) continue; break; case SOCKS_UDPASSOCIATE: if (!route->gw.state.command.udpassociate) continue; break; default: SERRX(req->command); } /* server supports protocol? */ switch (req->command) { case SOCKS_BIND: case SOCKS_CONNECT: if (!route->gw.state.protocol.tcp) continue; protocol = SOCKS_TCP; break; case SOCKS_UDPASSOCIATE: if (!route->gw.state.protocol.udp) continue; protocol = SOCKS_UDP; break; default: SERRX(req->command); } if (src != NULL) if (!addressmatch(&route->src, src, protocol, 0)) continue; if (dst != NULL) if (!addressmatch(&route->dst, dst, protocol, 0)) continue; if (route->state.direct) return NULL; /* don't use any route, connect directly. */ break; /* all matched */ } return route;}struct route_t *socks_connectroute(s, packet, src, dst) int s; struct socks_t *packet; const struct sockshost_t *src; const struct sockshost_t *dst;{ const char *function = "socks_connectroute()"; int sdup, current_s, errno_s; struct route_t *route; /* * This is a little tricky since we attempt to support trying * more than one socksserver. If the first one fails, we try * the next, etc. Ofcourse, if connect() on one socket fails, * that socket can no longer be used, so we need to be able to * copy/dup the original socket as much as possible. Later, * if it turned out a connection failed and we had to use a * different socket than the orignal 's', we try to dup the * differently numbered socket to 's' and hope the best. * * sdup: copy of the original socket. Need to create this * before the first connectattempt since the connectattempt * could prevent us from doing it later, depending on failure * reason. * * current_s: socket to use for next connection attempt. For the * first attempt this is 's'. */ errno = 0; /* let caller differentiate between missing route and not.*/ current_s = s; sdup = -1; while ((route = socks_getroute(&packet->req, src, dst)) != NULL) { char hstring[MAXSOCKSHOSTSTRING]; /* inside loop since if no route, no need for it. */ if (sdup == -1) sdup = socketoptdup(s); if (current_s == -1) if ((current_s = socketoptdup(sdup == -1 ? s : sdup)) == -1) return NULL; slog(LOG_DEBUG, "%s: trying route #%d (%s)", function, route->number, sockshost2string(&route->gw.host, hstring, sizeof(hstring))); if (socks_connect(current_s, &route->gw.host) == 0) break; else /* * Check whether the error indicates bad socksserver or * something else. */ if (errno == EINPROGRESS) { SASSERTX(current_s == s); break; } else if (errno == EADDRINUSE) { /* see Rbind() for explanation. */ SASSERTX(current_s == s); route = NULL; break; } else { swarn("%s: socks_connect(%s)", function, sockshost2string(&route->gw.host, hstring, sizeof(hstring))); socks_badroute(route); close(current_s); current_s = -1; } } errno_s = errno; if (sdup != -1) close(sdup); if (current_s != s && current_s != -1) { /* created a new socket for connect, need to make it same descriptor #. */ if (dup2(current_s, s) == -1) { close(current_s); return NULL; } close(current_s);#if SOCKS_SERVER && HAVE_LIBWRAP if ((current_s = fcntl(s, F_GETFD, 0)) == -1 || fcntl(s, F_SETFD, current_s | FD_CLOEXEC) == -1) swarn("%s: fcntl(F_GETFD/F_SETFD)", function);#endif } if (route != NULL) { static int init; packet->gw = route->gw; /* need to set up misc. crap for msproxy stuff. */ if (!init && route->gw.state.proxyprotocol.msproxy_v2) { if (msproxy_init() != 0) ; /* yes, then what? */ init = 1; } } errno = errno_s; return route;}voidsocks_badroute(route) struct route_t *route;{ const char *function = "socks_badroute()"; slog(LOG_DEBUG, "%s: badrouting route #%d", function, route->number); route->state.bad = 1;}struct request_t *socks_requestpolish(req, src, dst) struct request_t *req; const struct sockshost_t *src; const struct sockshost_t *dst;{ const char *function = "socks_requestpolish()"; unsigned char version; if (socks_getroute(req, src, dst) != NULL) return req; switch (req->command) { case SOCKS_BIND: case SOCKS_CONNECT: break; case SOCKS_UDPASSOCIATE: SERRX(req->command); /* currently not implemented, shouldn't happen. */ /* NOTREACHED */ default: SERRX(req->command); } /* unsupported version? */ switch (req->version) { case SOCKS_V4: req->version = SOCKS_V5; break; case SOCKS_V5: req->version = SOCKS_V4; break; } if (socks_getroute(req, src, dst) != NULL) return req; SASSERTX(req->version != MSPROXY_V2); /* never gets set outside function. */ version = req->version; req->version = MSPROXY_V2; if (socks_getroute(req, src, dst) != NULL) return req; req->version = version; switch (req->command) { case SOCKS_BIND: if (req->host.addr.ipv4.s_addr == htonl(0)) { const in_port_t originalport = req->host.port; const int originalversion = req->version; /* attempting to use bind extension, can we retry without it? */ /* LINTED pointer casts may be troublesome */ if (ADDRISBOUND(config.state.lastconnect)) { fakesockaddr2sockshost(&config.state.lastconnect, &req->host); /* * v4 and v5 differ in how portnumber is treated * so we need to be a little smarter than just returning * the result of the next socks_requestpolish() * while we still have the original portnumber. */ switch (req->version) { case SOCKS_V4: /* LINTED pointer casts may be troublesome */ req->host.port = ((struct sockaddr_in *) &config.state.lastconnect)->sin_port; break; case SOCKS_V5: /* only wants ip address. */ req->host.port = originalport; break; default: SERRX(req->version); } if (socks_requestpolish(req, src, dst) == NULL) return NULL; /* * else, it may be that socks_requestpolish() was * forced to change req.version to succeed, we then * need to change req->host.port due to difference in * v4 and v5 semantics. */ if (req->version != originalversion) { /* version changed. */ /* currently it can only change from 4 to 5, or 5 to 4. */ switch (req->version) { case SOCKS_V4: /* LINTED pointer casts may be troublesome */ req->host.port = ((struct sockaddr_in *) &config.state.lastconnect)->sin_port; break; case SOCKS_V5: req->host.port = originalport; break; default: SERRX(req->version); } } return socks_requestpolish(req, src, dst); } else slog(LOG_DEBUG, "%s: couldn't find route for bind, try enabling bind extension?", function); } break; } return NULL;}#endif /* SOCKS_CLIENT */voidshowstate(state) const struct serverstate_t *state;{ int i; char buf[1024]; size_t bufused; bufused = snprintf(buf, sizeof(buf), "command(s): "); if (state->command.bind) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", SOCKS_BINDs); if (state->command.bindreply) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", SOCKS_BINDREPLYs); if (state->command.connect) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", SOCKS_CONNECTs); if (state->command.udpassociate) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", SOCKS_UDPASSOCIATEs); if (state->command.udpreply) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", SOCKS_UDPREPLYs); slog(LOG_INFO, buf); bufused = snprintf(buf, sizeof(buf), "extension(s): "); if (state->extension.bind) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "bind"); slog(LOG_INFO, buf); bufused = snprintf(buf, sizeof(buf), "protocol(s): "); if (state->protocol.tcp) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", PROTOCOL_TCPs); if (state->protocol.udp) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", PROTOCOL_UDPs); slog(LOG_INFO, buf); bufused = snprintf(buf, sizeof(buf), "method(s): "); for (i = 0; i < state->methodc; ++i) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", method2string(state->methodv[i])); slog(LOG_INFO, buf); bufused = snprintf(buf, sizeof(buf), "proxyprotocol(s): "); if (state->proxyprotocol.socks_v4) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "socks v4, "); if (state->proxyprotocol.socks_v5) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "socks v5, "); if (state->proxyprotocol.msproxy_v2) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "msproxy v2"); slog(LOG_INFO, buf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -