📄 serverconfig.c
字号:
strcheck(visdata = str2vis(data, count))); free(visdata); } else if (rule->log.iooperation) slog(LOG_INFO, "%s(%d): %s: %s -> %s (%lu)", rule->verdict == VERDICT_BLOCK ? VERDICT_BLOCKs : VERDICT_PASSs, rule->number, protocol2string(state->protocol), srcstring, dststring, (unsigned long)count); break; default: SERRX(operation); }}intrulespermit(s, match, state, src, dst) int s; struct rule_t *match; struct connectionstate_t *state; const struct sockshost_t *src; const struct sockshost_t *dst;{ const char *function = "rulespermit()"; static int init; static struct rule_t defrule; struct rule_t *rule; struct connectionstate_t ostate;#if HAVE_LIBWRAP struct request_info libwraprequest; libwrapinit(s, &libwraprequest);#else /* !HAVE_LIBWRAP */ void *libwraprequest = NULL;#endif /* make a somewhat sensible default rule for entries with no match. */ if (!init) { defrule.verdict = VERDICT_BLOCK; defrule.number = 0; defrule.src.atype = SOCKS_ADDR_IPV4; defrule.src.addr.ipv4.ip.s_addr = htonl(INADDR_ANY); defrule.src.addr.ipv4.mask.s_addr = htonl(0); defrule.src.port.tcp = htons(0); defrule.src.port.udp = htons(0); defrule.src.portend = htons(0); defrule.src.operator = none; defrule.dst = defrule.src; if (config.option.debug) { defrule.log.connect = 1; defrule.log.disconnect = 1; defrule.log.error = 1; defrule.log.iooperation = 1; } else { memset(&defrule.log, 0, sizeof(defrule.log)); defrule.log.connect = 1; } memset(&defrule.state.command, UCHAR_MAX, sizeof(defrule.state.command)); defrule.state.methodc = 0; memset(&defrule.state.protocol, UCHAR_MAX, sizeof(defrule.state.protocol)); memset(&defrule.state.proxyprotocol, UCHAR_MAX, sizeof(defrule.state.proxyprotocol));#if HAVE_LIBWRAP *defrule.libwrap = NUL;#endif /* HAVE_LIBWRAP */ init = 1; } /* what rulebase to use. XXX nicer way to do this. */ switch (state->command) { case SOCKS_ACCEPT: /* only set by negotiate children so must be clientrule. */ rule = config.crule; break; default: /* everyone else, socksrules. */ rule = config.srule; break; } /* let "state" be unchanged from original unless we actually get a match. */ for (ostate = *state; rule != NULL; rule = rule->next, *state = ostate) { char *name, *password; /* current rule covers desired command? */ switch (state->command) { case SOCKS_BIND: if (!rule->state.command.bind) continue; break; case SOCKS_CONNECT: if (!rule->state.command.connect) continue; break; case SOCKS_UDPASSOCIATE: if (!rule->state.command.udpassociate) continue; break; /* pseudo commands. */ case SOCKS_BINDREPLY: if (!rule->state.command.bindreply) continue; break; case SOCKS_UDPREPLY: if (!rule->state.command.udpreply) continue; break; /* client-rule commands. */ case SOCKS_ACCEPT: break; default: SERRX(state->command); } /* current rule covers desired protocol? */ switch (state->protocol) { case SOCKS_TCP: if (!rule->state.protocol.tcp) continue; break; case SOCKS_UDP: if (!rule->state.protocol.udp) continue; break; default: SERRX(state->protocol); } /* current rule covers desired version? */ switch (state->version) { case SOCKS_V4: if (!rule->state.proxyprotocol.socks_v4) continue; break; case SOCKS_V5: if (!rule->state.proxyprotocol.socks_v5) continue; break; default: SERRX(state->version); } /* current rule allows for selected authentication? */ if (!methodisset(state->auth.method, rule->state.methodv, (size_t)rule->state.methodc)) /* * There are some "extra" methods that are independent of * socks protocol negotiation and it's thus possible * to get a match on them even if above check failed. * Currently it's only rfc931. */#if HAVE_LIBWRAP if (methodisset(AUTHMETHOD_RFC931, rule->state.methodv, (size_t)rule->state.methodc)) { strncpy(state->auth.mdata.rfc931.name, eval_user(&libwraprequest), sizeof(state->auth.mdata.rfc931.name) - 1); if (state->auth.mdata.rfc931.name[ sizeof(state->auth.mdata.rfc931.name) - 1] != NUL) { slog(LOG_INFO, "%s: rfc931 name truncated", function); state->auth.mdata.rfc931.name[ sizeof(state->auth.mdata.rfc931.name) - 1] = NUL; } state->auth.method = AUTHMETHOD_RFC931; } else#endif /* HAVE_LIBWRAP */ continue; SASSERTX(methodisset(state->auth.method, rule->state.methodv, (size_t)rule->state.methodc)); switch (state->auth.method) { case AUTHMETHOD_UNAME: name = state->auth.mdata.uname.name; password = state->auth.mdata.uname.password; break; case AUTHMETHOD_RFC931: name = state->auth.mdata.rfc931.name; password = NULL; break; default: name = password = NULL; } if (name != NULL && rule->user != NULL) { const char *methodname; char srcstring[MAXSOCKSHOSTSTRING]; struct linkedname_t *ruleuser; /* * The rule->user names restricts access further, only names * appearing there and in the passwordfile are matched. * An alias for "everyone" is a name that is the same as the * name of the selected method. */ methodname = method2string(state->auth.method); ruleuser = rule->user; do { if (strcmp(methodname, ruleuser->name) == 0) break; /* all usernames "match" here. */ else if (string2method(name) >= 0) slog(LOG_INFO, "%s: suspicious username from %s: %s", function, sockshost2string(src, srcstring, sizeof(srcstring)), name); else if (strcmp(name, ruleuser->name) == 0) break; } while ((ruleuser = ruleuser->next) != NULL); if (ruleuser == NULL) continue; /* no match. */ if (!state->auth.matched) { /* may have been checked at lower level. */ /* all users must also be in passwordfile. */ if (passwordcheck(name, password) != 0) continue; state->auth.matched = 1; } } /* * This is a little tricky, but for some commands we may not * have all info at time of (preliminary) rulechecks. * What we want to do if there is no (complete) address given is * to see if there's any chance at all the rules will permit this * request when the address (later) becomes available. * We therefore continue to scan the rules until we either get * a pass (ignoring peer with missing info), or the default block * is triggered. */ if (src != NULL) { if (!addressmatch(&rule->src, src, state->protocol, 0)) continue; } else if (rule->verdict == VERDICT_BLOCK) continue; /* continue scan. */ if (dst != NULL) { if (!addressmatch(&rule->dst, dst, state->protocol, 0)) continue; } else if (rule->verdict == VERDICT_BLOCK) continue; /* continue scan. */ break; } if (rule == NULL) /* no rules matched; match default rule. */ rule = &defrule; *match = *rule; /* * got our rule, now check connection. Connectioncheck * requires the rule matched so needs to be delayed til here. */ if (!connectisok(&libwraprequest, match, state)) match->verdict = VERDICT_BLOCK; /* * specialcases that we delay til here to get correct addr/rule match, * even if we could have decided on the final answer before. */ switch (state->command) { case SOCKS_BIND: if (dst->atype == SOCKS_ADDR_IPV4 && dst->addr.ipv4.s_addr == htonl(0)) if (!config.extension.bind) { slog(LOG_DEBUG, "%s: client requested disabled extension: bind", function); match->verdict = VERDICT_BLOCK; } break; } return match->verdict == VERDICT_PASS;}static struct rule_t *addrule(newrule, rulebase) const struct rule_t *newrule; struct rule_t **rulebase;{ static const struct serverstate_t state; const char *function = "addrule()"; struct rule_t *rule; if ((rule = malloc(sizeof(*rule))) == NULL) serrx(1, "%s: %s", function, NOMEM); *rule = *newrule; /* try to set values not set to a sensible default. */ if (config.option.debug) { rule->log.connect = 1; rule->log.disconnect = 1; rule->log.error = 1; rule->log.iooperation = 1; } /* else; don't touch logging, no logging is ok. */ /* if no command set, set all. */ if (memcmp(&state.command, &rule->state.command, sizeof(state.command)) == 0) memset(&rule->state.command, UCHAR_MAX, sizeof(rule->state.command)); /* * If no method set, set all we support. This in practice * limits the methods we accept here to the globally set methods * (config.methodv), since they are checked before we get to * rulespesific checks. We can't just copy config.methodv * since it may not be set yet. */ if (rule->state.methodc == 0) { int *methodv = rule->state.methodv; int *methodc = &rule->state.methodc; if (rule->user == NULL) methodv[(*methodc)++] = AUTHMETHOD_NONE; methodv[(*methodc)++] = AUTHMETHOD_UNAME;#if HAVE_LIBWRAP methodv[(*methodc)++] = AUTHMETHOD_RFC931;#endif } /* if no protocol set, set all. */ if (memcmp(&state.protocol, &rule->state.protocol, sizeof(state.protocol)) == 0) memset(&rule->state.protocol, UCHAR_MAX, sizeof(rule->state.protocol)); /* if no proxyprotocol set, set all except msproxy. */ if (memcmp(&state.proxyprotocol, &rule->state.proxyprotocol, sizeof(state.proxyprotocol)) == 0) { memset(&rule->state.proxyprotocol, UCHAR_MAX, sizeof(rule->state.proxyprotocol)); rule->state.proxyprotocol.msproxy_v2 = 0; } if (*rulebase == NULL) { *rulebase = rule; (*rulebase)->number = 1; } else { struct rule_t *lastrule; /* append this rule to the end of our list. */ lastrule = *rulebase; while (lastrule->next != NULL) lastrule = lastrule->next; rule->number = lastrule->number + 1; lastrule->next = rule; } rule->next = NULL; return rule;}static voidcheckrule(rule) const struct rule_t *rule;{ if (rule->user != NULL) if (rule->state.methodc == 0) yyerror("rule restricts by name, but no username-based method given");}static voidshowuser(user) const struct linkedname_t *user;{ char buf[10240]; size_t bufused; bufused = snprintf(buf, sizeof(buf), "user: "); for (; user != NULL; user = user->next) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", user->name); if (bufused > sizeof("user: ")) slog(LOG_INFO, buf);}static voidshowlog(log) const struct log_t *log;{ char buf[1024]; size_t bufused; bufused = snprintf(buf, sizeof(buf), "log: "); if (log->connect) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", LOG_CONNECTs); if (log->disconnect) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", LOG_DISCONNECTs); if (log->data) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", LOG_DATAs); if (log->error) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", LOG_ERRORs); if (log->iooperation) bufused += snprintf(&buf[bufused], sizeof(buf) - bufused, "%s, ", LOG_IOOPERATIONs); slog(LOG_INFO, buf);}#if HAVE_LIBWRAPstatic voidlibwrapinit(s, request) int s; struct request_info *request;{ request_init(request, RQ_FILE, s, RQ_DAEMON, __progname, 0); fromhost(request);}#endif /* HAVE_LIBWRAP */static intconnectisok(request, rule, state)#if HAVE_LIBWRAP struct request_info *request;#else void *request;#endif const struct rule_t *rule; struct connectionstate_t *state;{#if HAVE_LIBWRAP /* do we need to involve libwrap for this rule? */ if (*rule->libwrap != NUL || config.srchost.nomismatch || config.srchost.nounknown) { const char *function = "connectisok()"; char libwrap[LIBWRAPBUF]; uid_t euid; int checkforname; socks_seteuid(&euid, config.uid.libwrap); /* libwrap modifies the passed buffer. */ SASSERTX(strlen(rule->libwrap) < sizeof(libwrap)); strcpy(libwrap, rule->libwrap); /* Wietse Venema says something along the lines of: */ if (setjmp(tcpd_buf) != 0) { socks_reseteuid(config.uid.libwrap, euid); swarnx("%s: failed libwrap line: %s", function, libwrap); return 0; /* something got screwed up. */ } process_options(libwrap, request); /* * check if we got a username and won't clobber anything by saving it. */ switch (state->auth.method) { case AUTHMETHOD_NONE: /* doesn't take any memory from rfc931. */ checkforname = 1; break; default: checkforname = 0; /* can't take it or should already have it. */ } if (checkforname) { /* XXX can't use eval_user() since it always does rfc931 lookup. */ if (*request->user != NUL) { strncpy(state->auth.mdata.rfc931.name, request->user, sizeof(state->auth.mdata.rfc931.name) - 1); if (state->auth.mdata.rfc931.name [sizeof(state->auth.mdata.rfc931.name) - 1] != NUL) { slog(LOG_DEBUG, "%s: rfc931 name too long, truncated", function); state->auth.mdata.rfc931.name [sizeof(state->auth.mdata.rfc931.name) - 1] = NUL; } } } if (config.srchost.nounknown) if (strcmp(eval_hostname(request->client), STRING_UNKNOWN) == 0) { slog(LOG_INFO, "%s: srchost unknown", eval_hostaddr(request->client)); socks_reseteuid(config.uid.libwrap, euid); return 0; } if (config.srchost.nomismatch) if (strcmp(eval_hostname(request->client), STRING_PARANOID) == 0) { slog(LOG_INFO, "%s: srchost ip/host mismatch", eval_hostaddr(request->client)); socks_reseteuid(config.uid.libwrap, euid); return 0; } socks_reseteuid(config.uid.libwrap, euid); }#else /* !HAVE_LIBWRAP */#endif /* !HAVE_LIBWRAP */ return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -