📄 proxy.c
字号:
off++; /* is that the only thing on this line? */ if (off <= 2) return off; /* if not, then there is the possibility that this header * continues onto the next line, if it starts with a space * or a tab. */ if (off + 1 < len && data[off+1] != ' ' && data[off+1] != '\t') return off; /* the line does continue, so we have to keep going * until we see an the header's "real" end of line. */ off++; } off++; } return -1;}int proxy_http_negotiate (Proxy_Socket p, int change){ if (p->state == PROXY_STATE_NEW) { /* we are just beginning the proxy negotiate process, * so we'll send off the initial bits of the request. * for this proxy method, it's just a simple HTTP * request */ char *buf, dest[512]; sk_getaddr(p->remote_addr, dest, lenof(dest)); buf = dupprintf("CONNECT %s:%i HTTP/1.1\r\nHost: %s:%i\r\n", dest, p->remote_port, dest, p->remote_port); sk_write(p->sub_socket, buf, strlen(buf)); sfree(buf); if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { char buf[sizeof(p->cfg.proxy_username)+sizeof(p->cfg.proxy_password)]; char buf2[sizeof(buf)*4/3 + 100]; int i, j, len; sprintf(buf, "%s:%s", p->cfg.proxy_username, p->cfg.proxy_password); len = strlen(buf); sprintf(buf2, "Proxy-Authorization: Basic "); for (i = 0, j = strlen(buf2); i < len; i += 3, j += 4) base64_encode_atom((unsigned char *)(buf+i), (len-i > 3 ? 3 : len-i), buf2+j); strcpy(buf2+j, "\r\n"); sk_write(p->sub_socket, buf2, strlen(buf2)); } sk_write(p->sub_socket, "\r\n", 2); 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. */ char *data, *datap; int len; int eol; if (p->state == 1) { int min_ver, maj_ver, status; /* get the status line */ len = bufchain_size(&p->pending_input_data); assert(len > 0); /* or we wouldn't be here */ data = snewn(len+1, char); bufchain_fetch(&p->pending_input_data, data, len); /* * We must NUL-terminate this data, because Windows * sscanf appears to require a NUL at the end of the * string because it strlens it _first_. Sigh. */ data[len] = '\0'; eol = get_line_end(data, len); if (eol < 0) { sfree(data); return 1; } status = -1; /* We can't rely on whether the %n incremented the sscanf return */ if (sscanf((char *)data, "HTTP/%i.%i %n", &maj_ver, &min_ver, &status) < 2 || status == -1) { plug_closing(p->plug, "Proxy error: HTTP response was absent", PROXY_ERROR_GENERAL, 0); sfree(data); return 1; } /* remove the status line from the input buffer. */ bufchain_consume(&p->pending_input_data, eol); if (data[status] != '2') { /* error */ char *buf; data[eol] = '\0'; while (eol > status && (data[eol-1] == '\r' || data[eol-1] == '\n')) data[--eol] = '\0'; buf = dupprintf("Proxy error: %s", data+status); plug_closing(p->plug, buf, PROXY_ERROR_GENERAL, 0); sfree(buf); sfree(data); return 1; } sfree(data); p->state = 2; } if (p->state == 2) { /* get headers. we're done when we get a * header of length 2, (ie. just "\r\n") */ len = bufchain_size(&p->pending_input_data); assert(len > 0); /* or we wouldn't be here */ data = snewn(len, char); datap = data; bufchain_fetch(&p->pending_input_data, data, len); eol = get_line_end(datap, len); if (eol < 0) { sfree(data); return 1; } while (eol > 2) { bufchain_consume(&p->pending_input_data, eol); datap += eol; len -= eol; eol = get_line_end(datap, len); } if (eol == 2) { /* we're done */ bufchain_consume(&p->pending_input_data, 2); proxy_activate(p); /* proxy activate will have dealt with * whatever is left of the buffer */ sfree(data); return 1; } sfree(data); return 1; } } plug_closing(p->plug, "Proxy error: unexpected proxy error", PROXY_ERROR_UNEXPECTED, 0); return 1;}/* ---------------------------------------------------------------------- * SOCKS proxy type. *//* SOCKS version 4 */int proxy_socks4_negotiate (Proxy_Socket p, int change){ if (p->state == PROXY_CHANGE_NEW) { /* request format: * version number (1 byte) = 4 * command code (1 byte) * 1 = CONNECT * 2 = BIND * dest. port (2 bytes) [network order] * dest. address (4 bytes) * user ID (variable length, null terminated string) */ int length, type, namelen; char *command, addr[4], hostname[512]; type = sk_addrtype(p->remote_addr); if (type == ADDRTYPE_IPV6) { plug_closing(p->plug, "Proxy error: SOCKS version 4 does" " not support IPv6", PROXY_ERROR_GENERAL, 0); return 1; } else if (type == ADDRTYPE_IPV4) { namelen = 0; sk_addrcopy(p->remote_addr, addr); } else { /* type == ADDRTYPE_NAME */ assert(type == ADDRTYPE_NAME); sk_getaddr(p->remote_addr, hostname, lenof(hostname)); namelen = strlen(hostname) + 1; /* include the NUL */ addr[0] = addr[1] = addr[2] = 0; addr[3] = 1; } length = strlen(p->cfg.proxy_username) + namelen + 9; command = snewn(length, char); strcpy(command + 8, p->cfg.proxy_username); command[0] = 4; /* version 4 */ command[1] = 1; /* CONNECT command */ /* port */ command[2] = (char) (p->remote_port >> 8) & 0xff; command[3] = (char) p->remote_port & 0xff; /* address */ memcpy(command + 4, addr, 4); /* hostname */ memcpy(command + 8 + strlen(p->cfg.proxy_username) + 1, hostname, namelen); sk_write(p->sub_socket, command, length); sfree(command); 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. */ if (p->state == 1) { /* response format: * version number (1 byte) = 4 * reply code (1 byte) * 90 = request granted * 91 = request rejected or failed * 92 = request rejected due to lack of IDENTD on client * 93 = request rejected due to difference in user ID * (what we sent vs. what IDENTD said) * dest. port (2 bytes) * dest. address (4 bytes) */ char data[8]; if (bufchain_size(&p->pending_input_data) < 8) return 1; /* not got anything yet */ /* get the response */ bufchain_fetch(&p->pending_input_data, data, 8); if (data[0] != 0) { plug_closing(p->plug, "Proxy error: SOCKS proxy responded with " "unexpected reply code version", PROXY_ERROR_GENERAL, 0); return 1; } if (data[1] != 90) { switch (data[1]) { case 92: plug_closing(p->plug, "Proxy error: SOCKS server wanted IDENTD on client", PROXY_ERROR_GENERAL, 0); break; case 93: plug_closing(p->plug, "Proxy error: Username and IDENTD on client don't agree", PROXY_ERROR_GENERAL, 0); break; case 91: default: plug_closing(p->plug, "Proxy error: Error while communicating with proxy", PROXY_ERROR_GENERAL, 0); break; } return 1; } bufchain_consume(&p->pending_input_data, 8); /* 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;}/* SOCKS version 5 */int proxy_socks5_negotiate (Proxy_Socket p, int change){ if (p->state == PROXY_CHANGE_NEW) { /* initial command: * version number (1 byte) = 5 * number of available authentication methods (1 byte) * available authentication methods (1 byte * previous value) * authentication methods: * 0x00 = no authentication * 0x01 = GSSAPI * 0x02 = username/password * 0x03 = CHAP */ char command[5]; int len; command[0] = 5; /* version 5 */ if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { command[2] = 0x00; /* no authentication */ len = 3; proxy_socks5_offerencryptedauth (command, &len); command[len++] = 0x02; /* username/password */ command[1] = len - 2; /* Number of methods supported */ } else { command[1] = 1; /* one methods supported: */ command[2] = 0x00; /* no authentication */ len = 3; } sk_write(p->sub_socket, command, len); 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. */ if (p->state == 1) { /* initial response: * version number (1 byte) = 5 * authentication method (1 byte) * authentication methods: * 0x00 = no authentication * 0x01 = GSSAPI * 0x02 = username/password * 0x03 = CHAP * 0xff = no acceptable methods */ char data[2]; if (bufchain_size(&p->pending_input_data) < 2) return 1; /* not got anything yet */ /* get the response */ bufchain_fetch(&p->pending_input_data, data, 2); if (data[0] != 5) { plug_closing(p->plug, "Proxy error: SOCKS proxy returned unexpected version", PROXY_ERROR_GENERAL, 0); return 1; } if (data[1] == 0x00) p->state = 2; /* no authentication needed */ else if (data[1] == 0x01) p->state = 4; /* GSSAPI authentication */ else if (data[1] == 0x02) p->state = 5; /* username/password authentication */ else if (data[1] == 0x03) p->state = 6; /* CHAP authentication */ else { plug_closing(p->plug, "Proxy error: SOCKS proxy did not accept our authentication", PROXY_ERROR_GENERAL, 0); return 1; } bufchain_consume(&p->pending_input_data, 2); } if (p->state == 7) { /* password authentication reply format: * version number (1 bytes) = 1 * reply code (1 byte) * 0 = succeeded * >0 = failed */ char data[2]; if (bufchain_size(&p->pending_input_data) < 2) return 1; /* not got anything yet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -