void backend_socket_log(void *frontend, int type, SockAddr addr, int port, const char *error_msg, int error_code, Conf *conf, int session_started) { char addrbuf[256], *msg; switch (type) { case 0: sk_getaddr(addr, addrbuf, lenof(addrbuf)); if (sk_addr_needs_port(addr)) { msg = dupprintf("Connecting to %s port %d", addrbuf, port); } else { msg = dupprintf("Connecting to %s", addrbuf); } break; case 1: sk_getaddr(addr, addrbuf, lenof(addrbuf)); msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); break; case 2: /* Proxy-related log messages have their own identifying * prefix already, put on by our caller. */ { int len, log_to_term; /* Suffix \r\n temporarily, so we can log to the terminal. */ msg = dupprintf("%s\r\n", error_msg); len = (int)strlen(msg); assert(len >= 2); log_to_term = conf_get_int(conf, CONF_proxy_log_to_term); if (log_to_term == AUTO) log_to_term = session_started ? FORCE_OFF : FORCE_ON; if (log_to_term == FORCE_ON) from_backend(frontend, TRUE, msg, len); msg[len-2] = '\0'; /* remove the \r\n again */ } break; default: msg = NULL; /* shouldn't happen, but placate optimiser */ break; } if (msg) { logevent(frontend, msg); sfree(msg); } }
int proxy_http_negotiate (ProxySocket *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]; char *username, *password; 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); username = conf_get_str(p->conf, CONF_proxy_username); password = conf_get_str(p->conf, CONF_proxy_password); if (username[0] || password[0]) { char *buf, *buf2; int i, j, len; buf = dupprintf("%s:%s", username, password); len = strlen(buf); buf2 = snewn(len * 4 / 3 + 100, char); 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)); sfree(buf); sfree(buf2); }
static void raw_log(Plug plug, int type, SockAddr addr, int port, const char *error_msg, int error_code) { Raw raw = (Raw) plug; char addrbuf[256], *msg; sk_getaddr(addr, addrbuf, lenof(addrbuf)); if (type == 0) msg = dupprintf("Connecting to %s port %d", addrbuf, port); else msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg); logevent(raw->frontend, msg); }
/* * Called to set up the raw connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static char *raw_init(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { raw_closing, raw_receive, raw_sent }, *fn_table_ptr = &fn_table; SockAddr addr; char *err; /* * Try to find host. */ { char buf[200]; sprintf(buf, "Looking up host \"%.170s\"", host); logevent(buf); } addr = sk_namelookup(host, realhost); if ((err = sk_addr_error(addr))) return err; if (port < 0) port = 23; /* default telnet port */ /* * Open socket. */ { char buf[200], addrbuf[100]; sk_getaddr(addr, addrbuf, 100); sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; sk_addr_free(addr); return NULL; }
Socket new_connection(SockAddr addr, const char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, Conf *conf) { static const struct socket_function_table socket_fn_table = { sk_proxy_plug, sk_proxy_close, sk_proxy_write, sk_proxy_write_oob, sk_proxy_write_eof, sk_proxy_flush, sk_proxy_set_frozen, sk_proxy_socket_error, NULL, /* peer_info */ }; static const struct plug_function_table plug_fn_table = { plug_proxy_log, plug_proxy_closing, plug_proxy_receive, plug_proxy_sent, plug_proxy_accepting}; if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && proxy_for_destination(addr, hostname, port, conf)) { Proxy_Socket ret; Proxy_Plug pplug; SockAddr proxy_addr; char *proxy_canonical_name; const char *proxy_type; Socket sret; int type; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, plug, conf)) != NULL) return sret; ret = snew(struct Socket_proxy_tag); ret->fn = &socket_fn_table; ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; ret->error = NULL; ret->pending_flush = 0; ret->pending_eof = 0; ret->freeze = 0; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_oob_output_data); ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; 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(proxy_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. */ ret->sub_socket = sk_new(proxy_addr, conf_get_int(conf, CONF_proxy_port), privport, oobinline, nodelay, keepalive, (Plug)pplug); if (sk_socket_error(ret->sub_socket) != NULL) return (Socket)ret; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); return (Socket)ret; }
/* * This function can accept a NULL pointer as `addr', in which case * it will only check the host name. */ 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'. */ if (!conf_get_int(conf, CONF_even_proxy_localhost) && (sk_hostname_is_local(hostname) || (addr && sk_address_is_local(addr)))) return 0; /* do not proxy */ /* we want a string representation of the IP address for comparisons */ if (addr) { sk_getaddr(addr, hostip, 64); hostip_len = strlen(hostip); } else hostip_len = 0; /* placate gcc; shouldn't be required */ hostname_len = strlen(hostname); exclude_list = conf_get_str(conf, CONF_proxy_exclude_list); /* now parse the exclude list, and see if either our IP * or hostname matches anything in it. */ while (exclude_list[s]) { while (exclude_list[s] && (isspace((unsigned char)exclude_list[s]) || exclude_list[s] == ',')) s++; if (!exclude_list[s]) break; e = s; while (exclude_list[e] && (isalnum((unsigned char)exclude_list[e]) || exclude_list[e] == '-' || exclude_list[e] == '.' || exclude_list[e] == '*')) e++; if (exclude_list[s] == '*') { /* wildcard at beginning of entry */ if ((addr && strnicmp(hostip + hostip_len - (e - s - 1), exclude_list + s + 1, e - s - 1) == 0) || strnicmp(hostname + hostname_len - (e - s - 1), exclude_list + s + 1, e - s - 1) == 0) return 0; /* IP/hostname range excluded. do not use proxy. */ } else if (exclude_list[e - 1] == '*') { /* wildcard at end of entry */ if ((addr && strnicmp(hostip, exclude_list + s, e - s - 1) == 0) || strnicmp(hostname, exclude_list + s, e - s - 1) == 0) return 0; /* IP/hostname range excluded. do not use proxy. */ } else { /* no wildcard at either end, so let's try an absolute * match (ie. a specific IP) */ if (addr && strnicmp(hostip, exclude_list + s, e - s) == 0) return 0; /* IP/hostname excluded. do not use proxy. */ if (strnicmp(hostname, exclude_list + s, e - s) == 0) return 0; /* IP/hostname excluded. do not use proxy. */ } s = e; /* Make sure we really have reached the next comma or end-of-string */ while (exclude_list[s] && !isspace((unsigned char)exclude_list[s]) && exclude_list[s] != ',') s++; } /* no matches in the exclude list, so use the proxy */ return 1; }
/* * Called to set up the rlogin connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static const char *rlogin_init(void *frontend_handle, void **backend_handle, Config *cfg, char *host, int port, char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { rlogin_closing, rlogin_receive, rlogin_sent }; SockAddr addr; const char *err; Rlogin rlogin; rlogin = snew(struct rlogin_tag); rlogin->fn = &fn_table; rlogin->s = NULL; rlogin->frontend = frontend_handle; rlogin->term_width = cfg->width; rlogin->term_height = cfg->height; rlogin->firstbyte = 1; *backend_handle = rlogin; /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"", host); logevent(rlogin->frontend, buf); sfree(buf); } addr = name_lookup(host, port, realhost, cfg); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; } if (port < 0) port = 513; /* default rlogin port */ /* * Open socket. */ { char *buf, addrbuf[100]; sk_getaddr(addr, addrbuf, 100); buf = dupprintf("Connecting to %s port %d", addrbuf, port); logevent(rlogin->frontend, buf); sfree(buf); } rlogin->s = new_connection(addr, *realhost, port, 1, 0, nodelay, keepalive, (Plug) rlogin, cfg); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; /* * Send local username, remote username, terminal/speed */ { char z = 0; char *p; sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, cfg->localusername, strlen(cfg->localusername)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, cfg->username, strlen(cfg->username)); sk_write(rlogin->s, &z, 1); sk_write(rlogin->s, cfg->termtype, strlen(cfg->termtype)); sk_write(rlogin->s, "/", 1); for (p = cfg->termspeed; isdigit((unsigned char)*p); p++) continue; sk_write(rlogin->s, cfg->termspeed, p - cfg->termspeed); rlogin->bufsize = sk_write(rlogin->s, &z, 1); } return NULL; }
Socket *new_connection(SockAddr *addr, const char *hostname, int port, bool privport, bool oobinline, bool nodelay, bool keepalive, Plug *plug, Conf *conf) { if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && proxy_for_destination(addr, hostname, port, conf)) { ProxySocket *ret; SockAddr *proxy_addr; char *proxy_canonical_name; const char *proxy_type; Socket *sret; int type; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, plug, conf)) != NULL) return sret; ret = snew(ProxySocket); ret->sock.vt = &ProxySocket_sockvt; ret->plugimpl.vt = &ProxySocket_plugvt; ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; ret->error = NULL; ret->pending_flush = false; ret->pending_eof = false; ret->freeze = false; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_oob_output_data); ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; 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 &ret->sock; } { 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); } { 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"; sk_addr_free(proxy_addr); return &ret->sock; } sfree(proxy_canonical_name); { char addrbuf[256], *logmsg; sk_getaddr(proxy_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. */ ret->sub_socket = sk_new(proxy_addr, conf_get_int(conf, CONF_proxy_port), privport, oobinline, nodelay, keepalive, &ret->plugimpl); if (sk_socket_error(ret->sub_socket) != NULL) return &ret->sock; /* start the proxy negotiation process... */ sk_set_frozen(ret->sub_socket, 0); ret->negotiate(ret, PROXY_CHANGE_NEW); return &ret->sock; } /* no proxy, so just return the direct socket */ return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug); }
/* * Called to set up the rlogin connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ static char *rlogin_init(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { rlogin_closing, rlogin_receive, rlogin_sent }, *fn_table_ptr = &fn_table; SockAddr addr; char *err; /* * Try to find host. */ { char buf[200]; sprintf(buf, "Looking up host \"%.170s\"", host); logevent(buf); } addr = sk_namelookup(host, realhost); if ((err = sk_addr_error(addr))) return err; if (port < 0) port = 513; /* default rlogin port */ /* * Open socket. */ { char buf[200], addrbuf[100]; sk_getaddr(addr, addrbuf, 100); sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } s = sk_new(addr, port, 1, 0, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; sk_addr_free(addr); /* * Send local username, remote username, terminal/speed */ { char z = 0; char *p; sk_write(s, &z, 1); sk_write(s, cfg.localusername, strlen(cfg.localusername)); sk_write(s, &z, 1); sk_write(s, cfg.username, strlen(cfg.username)); sk_write(s, &z, 1); sk_write(s, cfg.termtype, strlen(cfg.termtype)); sk_write(s, "/", 1); for (p = cfg.termspeed; isdigit(*p); p++); sk_write(s, cfg.termspeed, p - cfg.termspeed); rlogin_bufsize = sk_write(s, &z, 1); } return NULL; }