X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=proxy.c;h=f9f2cd62df8de99f521dc9588c89be35b5b22f38;hb=73e5b6db25f4f2e3b3a52744d0a8df5acc98ef4d;hp=0b6d9d5828c8d3fd93a0c9893cea4ec07f07f0f7;hpb=a1f3b7a358adaa7c2a98359cd0373aa823eeb14b;p=PuTTY.git diff --git a/proxy.c b/proxy.c index 0b6d9d58..f9f2cd62 100644 --- a/proxy.c +++ b/proxy.c @@ -65,6 +65,9 @@ void proxy_activate (Proxy_Socket p) */ if (p->pending_flush) sk_flush(p->sub_socket); + /* if we have a pending EOF to send, send it */ + if (p->pending_eof) sk_write_eof(p->sub_socket); + /* if the backend wanted the socket unfrozen, try to unfreeze. * our set_frozen handler will flush buffered receive data before * unfreezing the actual underlying socket. @@ -117,27 +120,26 @@ static int sk_proxy_write_oob (Socket s, const char *data, int len) return sk_write_oob(ps->sub_socket, data, len); } -static void sk_proxy_flush (Socket s) +static void sk_proxy_write_eof (Socket s) { Proxy_Socket ps = (Proxy_Socket) s; if (ps->state != PROXY_STATE_ACTIVE) { - ps->pending_flush = 1; + ps->pending_eof = 1; return; } - sk_flush(ps->sub_socket); + sk_write_eof(ps->sub_socket); } -static void sk_proxy_set_private_ptr (Socket s, void *ptr) +static void sk_proxy_flush (Socket s) { Proxy_Socket ps = (Proxy_Socket) s; - sk_set_private_ptr(ps->sub_socket, ptr); -} -static void * sk_proxy_get_private_ptr (Socket s) -{ - Proxy_Socket ps = (Proxy_Socket) s; - return sk_get_private_ptr(ps->sub_socket); + if (ps->state != PROXY_STATE_ACTIVE) { + ps->pending_flush = 1; + return; + } + sk_flush(ps->sub_socket); } static void sk_proxy_set_frozen (Socket s, int is_frozen) @@ -247,30 +249,41 @@ static void plug_proxy_sent (Plug p, int bufsize) plug_sent(ps->plug, bufsize); } -static int plug_proxy_accepting (Plug p, OSSocket sock) +static int plug_proxy_accepting(Plug p, + accept_fn_t constructor, accept_ctx_t ctx) { Proxy_Plug pp = (Proxy_Plug) p; Proxy_Socket ps = pp->proxy_socket; if (ps->state != PROXY_STATE_ACTIVE) { - ps->accepting_sock = sock; + ps->accepting_constructor = constructor; + ps->accepting_ctx = ctx; return ps->negotiate(ps, PROXY_CHANGE_ACCEPTING); } - return plug_accepting(ps->plug, sock); + return plug_accepting(ps->plug, constructor, ctx); } /* * This function can accept a NULL pointer as `addr', in which case * it will only check the host name. */ -static int proxy_for_destination (SockAddr addr, char *hostname, int port, - Conf *conf) +int proxy_for_destination (SockAddr addr, const char *hostname, + int port, Conf *conf) { int s = 0, e = 0; char hostip[64]; int hostip_len, hostname_len; const char *exclude_list; + /* + * Special local connections such as Unix-domain sockets + * unconditionally cannot be proxied, even in proxy-localhost + * mode. There just isn't any way to ask any known proxy type for + * them. + */ + if (addr && sk_address_is_special_local(addr)) + return 0; /* do not proxy */ + /* * Check the host name and IP against the hard-coded * representations of `localhost'. @@ -349,20 +362,45 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port, return 1; } -SockAddr name_lookup(char *host, int port, char **canonicalname, - Conf *conf, int addressfamily) +static char *dns_log_msg(const char *host, int addressfamily, + const char *reason) { + return dupprintf("Looking up host \"%s\"%s for %s", host, + (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : + ""), reason); +} + +SockAddr name_lookup(const char *host, int port, char **canonicalname, + Conf *conf, int addressfamily, void *frontend, + const char *reason) +{ + char *logmsg; if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && do_proxy_dns(conf) && proxy_for_destination(NULL, host, port, conf)) { + + if (frontend) { + logmsg = dupprintf("Leaving host lookup to proxy of \"%s\"" + " (for %s)", host, reason); + logevent(frontend, logmsg); + sfree(logmsg); + } + *canonicalname = dupstr(host); return sk_nonamelookup(host); + } else { + if (frontend) { + logmsg = dns_log_msg(host, addressfamily, reason); + logevent(frontend, logmsg); + sfree(logmsg); + } + + return sk_namelookup(host, canonicalname, addressfamily); } - - return sk_namelookup(host, canonicalname, addressfamily); } -Socket new_connection(SockAddr addr, char *hostname, +Socket new_connection(SockAddr addr, const char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, Conf *conf) @@ -372,11 +410,11 @@ Socket new_connection(SockAddr addr, char *hostname, sk_proxy_close, sk_proxy_write, sk_proxy_write_oob, + sk_proxy_write_eof, sk_proxy_flush, - sk_proxy_set_private_ptr, - sk_proxy_get_private_ptr, sk_proxy_set_frozen, - sk_proxy_socket_error + sk_proxy_socket_error, + NULL, /* peer_info */ }; static const struct plug_function_table plug_fn_table = { @@ -394,6 +432,7 @@ Socket new_connection(SockAddr addr, char *hostname, Proxy_Plug pplug; SockAddr proxy_addr; char *proxy_canonical_name; + const char *proxy_type; Socket sret; int type; @@ -412,6 +451,7 @@ Socket new_connection(SockAddr addr, char *hostname, ret->error = NULL; ret->pending_flush = 0; + ret->pending_eof = 0; ret->freeze = 0; bufchain_init(&ret->pending_input_data); @@ -425,33 +465,67 @@ Socket new_connection(SockAddr addr, char *hostname, type = conf_get_int(conf, CONF_proxy_type); if (type == PROXY_HTTP) { ret->negotiate = proxy_http_negotiate; + proxy_type = "HTTP"; } else if (type == PROXY_SOCKS4) { ret->negotiate = proxy_socks4_negotiate; + proxy_type = "SOCKS 4"; } else if (type == PROXY_SOCKS5) { ret->negotiate = proxy_socks5_negotiate; + proxy_type = "SOCKS 5"; } else if (type == PROXY_TELNET) { ret->negotiate = proxy_telnet_negotiate; + proxy_type = "Telnet"; } else { ret->error = "Proxy error: Unknown proxy method"; return (Socket) ret; } + { + char *logmsg = dupprintf("Will use %s proxy at %s:%d to connect" + " to %s:%d", proxy_type, + conf_get_str(conf, CONF_proxy_host), + conf_get_int(conf, CONF_proxy_port), + hostname, port); + plug_log(plug, 2, NULL, 0, logmsg, 0); + sfree(logmsg); + } + /* create the proxy plug to map calls from the actual * socket into our proxy socket layer */ pplug = snew(struct Plug_proxy_tag); pplug->fn = &plug_fn_table; pplug->proxy_socket = ret; + { + char *logmsg = dns_log_msg(conf_get_str(conf, CONF_proxy_host), + conf_get_int(conf, CONF_addressfamily), + "proxy"); + plug_log(plug, 2, NULL, 0, logmsg, 0); + sfree(logmsg); + } + /* look-up proxy */ proxy_addr = sk_namelookup(conf_get_str(conf, CONF_proxy_host), &proxy_canonical_name, conf_get_int(conf, CONF_addressfamily)); if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; + sfree(pplug); + sk_addr_free(proxy_addr); return (Socket)ret; } sfree(proxy_canonical_name); + { + char addrbuf[256], *logmsg; + sk_getaddr(addr, addrbuf, lenof(addrbuf)); + logmsg = dupprintf("Connecting to %s proxy at %s port %d", + proxy_type, addrbuf, + conf_get_int(conf, CONF_proxy_port)); + plug_log(plug, 2, NULL, 0, logmsg, 0); + sfree(logmsg); + } + /* create the actual socket we will be using, * connected to our proxy server and port. */ @@ -473,8 +547,8 @@ Socket new_connection(SockAddr addr, char *hostname, return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); } -Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only, - Conf *conf, int addressfamily) +Socket new_listener(const char *srcaddr, int port, Plug plug, + int local_host_only, Conf *conf, int addressfamily) { /* TODO: SOCKS (and potentially others) support inbound * TODO: connections via the proxy. support them. @@ -590,7 +664,8 @@ int proxy_http_negotiate (Proxy_Socket p, int change) * what should we do? close the socket with an appropriate * error message? */ - return plug_accepting(p->plug, p->accepting_sock); + return plug_accepting(p->plug, + p->accepting_constructor, p->accepting_ctx); } if (change == PROXY_CHANGE_RECEIVE) { @@ -725,8 +800,7 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) 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); + p->error = "Proxy error: SOCKS version 4 does not support IPv6"; return 1; } else if (type == ADDRTYPE_IPV4) { namelen = 0; @@ -793,7 +867,8 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) * what should we do? close the socket with an appropriate * error message? */ - return plug_accepting(p->plug, p->accepting_sock); + return plug_accepting(p->plug, + p->accepting_constructor, p->accepting_ctx); } if (change == PROXY_CHANGE_RECEIVE) { @@ -932,7 +1007,8 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) * what should we do? close the socket with an appropriate * error message? */ - return plug_accepting(p->plug, p->accepting_sock); + return plug_accepting(p->plug, + p->accepting_constructor, p->accepting_ctx); } if (change == PROXY_CHANGE_RECEIVE) { @@ -1170,9 +1246,11 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) char userpwbuf[255 + 255 + 3]; int ulen, plen; ulen = strlen(username); - if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; + if (ulen > 255) ulen = 255; + if (ulen < 1) ulen = 1; plen = strlen(password); - if (plen > 255) plen = 255; if (plen < 1) plen = 1; + if (plen > 255) plen = 255; + if (plen < 1) plen = 1; userpwbuf[0] = 1; /* version number of subnegotiation */ userpwbuf[1] = ulen; memcpy(userpwbuf+2, username, ulen); @@ -1436,6 +1514,39 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change) formatted_cmd = format_telnet_command(p->remote_addr, p->remote_port, p->conf); + { + /* + * Re-escape control chars in the command, for logging. + */ + char *reescaped = snewn(4*strlen(formatted_cmd) + 1, char); + const char *in; + char *out; + char *logmsg; + + for (in = formatted_cmd, out = reescaped; *in; in++) { + if (*in == '\n') { + *out++ = '\\'; *out++ = 'n'; + } else if (*in == '\r') { + *out++ = '\\'; *out++ = 'r'; + } else if (*in == '\t') { + *out++ = '\\'; *out++ = 't'; + } else if (*in == '\\') { + *out++ = '\\'; *out++ = '\\'; + } else if ((unsigned)(((unsigned char)*in) - 0x20) < + (0x7F-0x20)) { + *out++ = *in; + } else { + out += sprintf(out, "\\x%02X", (unsigned)*in & 0xFF); + } + } + *out = '\0'; + + logmsg = dupprintf("Sending Telnet proxy command: %s", reescaped); + plug_log(p->plug, 2, NULL, 0, logmsg, 0); + sfree(logmsg); + sfree(reescaped); + } + sk_write(p->sub_socket, formatted_cmd, strlen(formatted_cmd)); sfree(formatted_cmd); @@ -1470,7 +1581,8 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change) * what should we do? close the socket with an appropriate * error message? */ - return plug_accepting(p->plug, p->accepting_sock); + return plug_accepting(p->plug, + p->accepting_constructor, p->accepting_ctx); } if (change == PROXY_CHANGE_RECEIVE) {