📄 proxy.c
字号:
/* get the response */ bufchain_fetch(&p->pending_input_data, data, 2); if (data[0] != 1) { plug_closing(p->plug, "Proxy error: SOCKS password " "subnegotiation contained wrong version number", PROXY_ERROR_GENERAL, 0); return 1; } if (data[1] != 0) { plug_closing(p->plug, "Proxy error: SOCKS proxy refused" " password authentication", PROXY_ERROR_GENERAL, 0); return 1; } bufchain_consume(&p->pending_input_data, 2); p->state = 2; /* now proceed as authenticated */ } if (p->state == 8) { int ret; ret = proxy_socks5_handlechap(p); if (ret) return ret; } if (p->state == 2) { /* request format: * version number (1 byte) = 5 * command code (1 byte) * 1 = CONNECT * 2 = BIND * 3 = UDP ASSOCIATE * reserved (1 byte) = 0x00 * address type (1 byte) * 1 = IPv4 * 3 = domainname (first byte has length, no terminating null) * 4 = IPv6 * dest. address (variable) * dest. port (2 bytes) [network order] */ char command[512]; int len; int type; type = sk_addrtype(p->remote_addr); if (type == ADDRTYPE_IPV4) { len = 10; /* 4 hdr + 4 addr + 2 trailer */ command[3] = 1; /* IPv4 */ sk_addrcopy(p->remote_addr, command+4); } else if (type == ADDRTYPE_IPV6) { len = 22; /* 4 hdr + 16 addr + 2 trailer */ command[3] = 4; /* IPv6 */ sk_addrcopy(p->remote_addr, command+4); } else { assert(type == ADDRTYPE_NAME); command[3] = 3; sk_getaddr(p->remote_addr, command+5, 256); command[4] = strlen(command+5); len = 7 + command[4]; /* 4 hdr, 1 len, N addr, 2 trailer */ } command[0] = 5; /* version 5 */ command[1] = 1; /* CONNECT command */ command[2] = 0x00; /* port */ command[len-2] = (char) (p->remote_port >> 8) & 0xff; command[len-1] = (char) p->remote_port & 0xff; sk_write(p->sub_socket, command, len); p->state = 3; return 1; } if (p->state == 3) { /* reply format: * version number (1 bytes) = 5 * reply code (1 byte) * 0 = succeeded * 1 = general SOCKS server failure * 2 = connection not allowed by ruleset * 3 = network unreachable * 4 = host unreachable * 5 = connection refused * 6 = TTL expired * 7 = command not supported * 8 = address type not supported * reserved (1 byte) = x00 * address type (1 byte) * 1 = IPv4 * 3 = domainname (first byte has length, no terminating null) * 4 = IPv6 * server bound address (variable) * server bound port (2 bytes) [network order] */ char data[5]; int len; /* First 5 bytes of packet are enough to tell its length. */ if (bufchain_size(&p->pending_input_data) < 5) return 1; /* not got anything yet */ /* get the response */ bufchain_fetch(&p->pending_input_data, data, 5); if (data[0] != 5) { plug_closing(p->plug, "Proxy error: SOCKS proxy returned wrong version number", PROXY_ERROR_GENERAL, 0); return 1; } if (data[1] != 0) { char buf[256]; strcpy(buf, "Proxy error: "); switch (data[1]) { case 1: strcat(buf, "General SOCKS server failure"); break; case 2: strcat(buf, "Connection not allowed by ruleset"); break; case 3: strcat(buf, "Network unreachable"); break; case 4: strcat(buf, "Host unreachable"); break; case 5: strcat(buf, "Connection refused"); break; case 6: strcat(buf, "TTL expired"); break; case 7: strcat(buf, "Command not supported"); break; case 8: strcat(buf, "Address type not supported"); break; default: sprintf(buf+strlen(buf), "Unrecognised SOCKS error code %d", data[1]); break; } plug_closing(p->plug, buf, PROXY_ERROR_GENERAL, 0); return 1; } /* * Eat the rest of the reply packet. */ len = 6; /* first 4 bytes, last 2 */ switch (data[3]) { case 1: len += 4; break; /* IPv4 address */ case 4: len += 16; break;/* IPv6 address */ case 3: len += (unsigned char)data[4]; break; /* domain name */ default: plug_closing(p->plug, "Proxy error: SOCKS proxy returned " "unrecognised address format", PROXY_ERROR_GENERAL, 0); return 1; } if (bufchain_size(&p->pending_input_data) < len) return 1; /* not got whole reply yet */ bufchain_consume(&p->pending_input_data, len); /* we're done */ proxy_activate(p); return 1; } if (p->state == 4) { /* TODO: Handle GSSAPI authentication */ plug_closing(p->plug, "Proxy error: We don't support GSSAPI authentication", PROXY_ERROR_GENERAL, 0); return 1; } if (p->state == 5) { if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { char userpwbuf[514]; int ulen, plen; ulen = strlen(p->cfg.proxy_username); if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; plen = strlen(p->cfg.proxy_password); if (plen > 255) plen = 255; if (plen < 1) plen = 1; userpwbuf[0] = 1; /* version number of subnegotiation */ userpwbuf[1] = ulen; memcpy(userpwbuf+2, p->cfg.proxy_username, ulen); userpwbuf[ulen+2] = plen; memcpy(userpwbuf+ulen+3, p->cfg.proxy_password, plen); sk_write(p->sub_socket, userpwbuf, ulen + plen + 3); p->state = 7; } else plug_closing(p->plug, "Proxy error: Server chose " "username/password authentication but we " "didn't offer it!", PROXY_ERROR_GENERAL, 0); return 1; } if (p->state == 6) { int ret; ret = proxy_socks5_selectchap(p); if (ret) return ret; } } plug_closing(p->plug, "Proxy error: Unexpected proxy error", PROXY_ERROR_UNEXPECTED, 0); return 1;}/* ---------------------------------------------------------------------- * `Telnet' proxy type. * * (This is for ad-hoc proxies where you connect to the proxy's * telnet port and send a command such as `connect host port'. The * command is configurable, since this proxy type is typically not * standardised or at all well-defined.) */char *format_telnet_command(SockAddr addr, int port, const Config *cfg){ char *ret = NULL; int retlen = 0, retsize = 0; int so = 0, eo = 0;#define ENSURE(n) do { \ if (retsize < retlen + n) { \ retsize = retlen + n + 512; \ ret = sresize(ret, retsize, char); \ } \} while (0) /* we need to escape \\, \%, \r, \n, \t, \x??, \0???, * %%, %host, %port, %user, and %pass */ while (cfg->proxy_telnet_command[eo] != 0) { /* scan forward until we hit end-of-line, * or an escape character (\ or %) */ while (cfg->proxy_telnet_command[eo] != 0 && cfg->proxy_telnet_command[eo] != '%' && cfg->proxy_telnet_command[eo] != '\\') eo++; /* if we hit eol, break out of our escaping loop */ if (cfg->proxy_telnet_command[eo] == 0) break; /* if there was any unescaped text before the escape * character, send that now */ if (eo != so) { ENSURE(eo - so); memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); retlen += eo - so; } so = eo++; /* if the escape character was the last character of * the line, we'll just stop and send it. */ if (cfg->proxy_telnet_command[eo] == 0) break; if (cfg->proxy_telnet_command[so] == '\\') { /* we recognize \\, \%, \r, \n, \t, \x??. * anything else, we just send unescaped (including the \). */ switch (cfg->proxy_telnet_command[eo]) { case '\\': ENSURE(1); ret[retlen++] = '\\'; eo++; break; case '%': ENSURE(1); ret[retlen++] = '%'; eo++; break; case 'r': ENSURE(1); ret[retlen++] = '\r'; eo++; break; case 'n': ENSURE(1); ret[retlen++] = '\n'; eo++; break; case 't': ENSURE(1); ret[retlen++] = '\t'; eo++; break; case 'x': case 'X': { /* escaped hexadecimal value (ie. \xff) */ unsigned char v = 0; int i = 0; for (;;) { eo++; if (cfg->proxy_telnet_command[eo] >= '0' && cfg->proxy_telnet_command[eo] <= '9') v += cfg->proxy_telnet_command[eo] - '0'; else if (cfg->proxy_telnet_command[eo] >= 'a' && cfg->proxy_telnet_command[eo] <= 'f') v += cfg->proxy_telnet_command[eo] - 'a' + 10; else if (cfg->proxy_telnet_command[eo] >= 'A' && cfg->proxy_telnet_command[eo] <= 'F') v += cfg->proxy_telnet_command[eo] - 'A' + 10; else { /* non hex character, so we abort and just * send the whole thing unescaped (including \x) */ ENSURE(1); ret[retlen++] = '\\'; eo = so + 1; break; } /* we only extract two hex characters */ if (i == 1) { ENSURE(1); ret[retlen++] = v; eo++; break; } i++; v <<= 4; } } break; default: ENSURE(2); memcpy(ret+retlen, cfg->proxy_telnet_command + so, 2); retlen += 2; eo++; break; } } else { /* % escape. we recognize %%, %host, %port, %user, %pass. * anything else, we just send unescaped (including the %). */ if (cfg->proxy_telnet_command[eo] == '%') { ENSURE(1); ret[retlen++] = '%'; eo++; } else if (strnicmp(cfg->proxy_telnet_command + eo, "host", 4) == 0) { char dest[512]; int destlen; sk_getaddr(addr, dest, lenof(dest)); destlen = strlen(dest); ENSURE(destlen); memcpy(ret+retlen, dest, destlen); retlen += destlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "port", 4) == 0) { char portstr[8], portlen; portlen = sprintf(portstr, "%i", port); ENSURE(portlen); memcpy(ret + retlen, portstr, portlen); retlen += portlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "user", 4) == 0) { int userlen = strlen(cfg->proxy_username); ENSURE(userlen); memcpy(ret+retlen, cfg->proxy_username, userlen); retlen += userlen; eo += 4; } else if (strnicmp(cfg->proxy_telnet_command + eo, "pass", 4) == 0) { int passlen = strlen(cfg->proxy_password); ENSURE(passlen); memcpy(ret+retlen, cfg->proxy_password, passlen); retlen += passlen; eo += 4; } else { /* we don't escape this, so send the % now, and * don't advance eo, so that we'll consider the * text immediately following the % as unescaped. */ ENSURE(1); ret[retlen++] = '%'; } } /* resume scanning for additional escapes after this one. */ so = eo; } /* if there is any unescaped text at the end of the line, send it */ if (eo != so) { ENSURE(eo - so); memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); retlen += eo - so; } ENSURE(1); ret[retlen] = '\0'; return ret;#undef ENSURE}int proxy_telnet_negotiate (Proxy_Socket p, int change){ if (p->state == PROXY_CHANGE_NEW) { char *formatted_cmd; formatted_cmd = format_telnet_command(p->remote_addr, p->remote_port, &p->cfg); sk_write(p->sub_socket, formatted_cmd, strlen(formatted_cmd)); sfree(formatted_cmd); p->state = 1; return 0; } if (change == PROXY_CHANGE_CLOSING) { /* if our proxy negotiation process involves closing and opening * new sockets, then we would want to intercept this closing * callback when we were expecting it. if we aren't anticipating * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ return plug_closing(p->plug, p->closing_error_msg, p->closing_error_code, p->closing_calling_back); } if (change == PROXY_CHANGE_SENT) { /* some (or all) of what we wrote to the proxy was sent. * we don't do anything new, however, until we receive the * proxy's response. we might want to set a timer so we can * timeout the proxy negotiation after a while... */ return 0; } if (change == PROXY_CHANGE_ACCEPTING) { /* we should _never_ see this, as we are using our socket to * connect to a proxy, not accepting inbound connections. * what should we do? close the socket with an appropriate * error message? */ return plug_accepting(p->plug, p->accepting_sock); } if (change == PROXY_CHANGE_RECEIVE) { /* we have received data from the underlying socket, which * we'll need to parse, process, and respond to appropriately. */ /* we're done */ proxy_activate(p); /* proxy activate will have dealt with * whatever is left of the buffer */ return 1; } plug_closing(p->plug, "Proxy error: Unexpected proxy error", PROXY_ERROR_UNEXPECTED, 0); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -