From b7a189f38294c745ae4ea6efb55891c8196e275b Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 18 Dec 2002 16:23:11 +0000 Subject: [PATCH] Support for doing DNS at the proxy end. I've invented a new type of SockAddr, which just contains an unresolved hostname and is created by a stub function in *net.c. It's an error to pass this to most of the real-meat functions in *net.c; these fake addresses should have been dealt with by the time they get down that far. proxy.c now contains name_lookup(), a wrapper on sk_namelookup() which decides whether or not to do real DNS, and the individual proxy implementations each deal sensibly with being handed an unresolved address and avoid ever passing one down to *net.c. git-svn-id: svn://svn.tartarus.org/sgt/putty@2353 cda61777-01e9-0310-a592-d414129be87e --- doc/config.but | 39 ++++++++++++++++++++++++- network.h | 4 ++- portfwd.c | 2 +- proxy.c | 89 ++++++++++++++++++++++++++++++++++++++++++---------------- putty.h | 1 + raw.c | 2 +- rlogin.c | 2 +- settings.c | 2 ++ ssh.c | 2 +- telnet.c | 2 +- unix/uxnet.c | 56 ++++++++++++++++++++++++++---------- windlg.c | 31 +++++++++++++++++++- winnet.c | 58 +++++++++++++++++++++++++++----------- x11fwd.c | 2 +- 14 files changed, 227 insertions(+), 65 deletions(-) diff --git a/doc/config.but b/doc/config.but index dfe7da5c..909d60fb 100644 --- a/doc/config.but +++ b/doc/config.but @@ -1,4 +1,4 @@ -\versionid $Id: config.but,v 1.46 2002/12/18 12:18:54 simon Exp $ +\versionid $Id: config.but,v 1.47 2002/12/18 16:23:10 simon Exp $ \C{config} Configuring PuTTY @@ -1445,6 +1445,43 @@ list does not explicitly contain them. It is very unlikely that this behaviour would ever cause problems, but if it does you can change it by enabling \q{Consider proxying local host connections}. +Note that if you are doing DNS at the proxy (see +\k{config-proxy-dns}), you should make sure that your proxy +exclusion settings do not depend on knowing the IP address of a +host. If the name is passed on to the proxy without PuTTY looking it +up, it will never know the IP address and cannot check it against +your list. + +\S{config-proxy-dns} Name resolution when using a proxy + +\cfg{winhelp-topic}{proxy.dns} + +If you are using a proxy to access a private network, it can make a +difference whether DNS name resolution is performed by PuTTY itself +(on the client machine) or performed by the proxy. + +The \q{Do DNS name lookup at proxy end} configuration option allows +you to control this. If you set it to \q{No}, PuTTY will always do +its own DNS, and will always pass an IP address to the proxy. If you +set it to \q{Yes}, PuTTY will always pass host names straight to the +proxy without trying to look them up first. + +If you set this option to \q{Auto} (the default), PuTTY will do +something it considers appropriate for each type of proxy. Telnet +and HTTP proxies will have host names passed straight to them; SOCKS +proxies will not. + +Note that if you are doing DNS at the proxy, you should make sure +that your proxy exclusion settings (see \k{config-proxy-exclude}) do +not depend on knowing the IP address of a host. If the name is +passed on to the proxy without PuTTY looking it up, it will never +know the IP address and cannot check it against your list. + +The original SOCKS 4 protocol does not support proxy-side DNS. There +is a protocol extension (SOCKS 4A) which does support it, but not +all SOCKS 4 servers provide this extension. If you enable proxy DNS +and your SOCKS 4 server cannot deal with it, this might be why. + \S{config-proxy-auth} Username and password \cfg{winhelp-topic}{proxy.auth} diff --git a/network.h b/network.h index 17a73217..e9ad518d 100644 --- a/network.h +++ b/network.h @@ -68,6 +68,7 @@ Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, Plug plug); Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only); +SockAddr name_lookup(char *host, int port, char **canonicalname); /* socket functions */ @@ -75,10 +76,11 @@ void sk_init(void); /* called once at program startup */ void sk_cleanup(void); /* called just before program exit */ SockAddr sk_namelookup(char *host, char **canonicalname); +SockAddr sk_nonamelookup(char *host); void sk_getaddr(SockAddr addr, char *buf, int buflen); int sk_hostname_is_local(char *name); int sk_address_is_local(SockAddr addr); -enum { ADDRTYPE_IPV4, ADDRTYPE_IPV6 }; +enum { ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME }; int sk_addrtype(SockAddr addr); void sk_addrcopy(SockAddr addr, char *buf); void sk_addr_free(SockAddr addr); diff --git a/portfwd.c b/portfwd.c index dd8e6550..dc865f62 100644 --- a/portfwd.c +++ b/portfwd.c @@ -126,7 +126,7 @@ char *pfd_newconnect(Socket *s, char *hostname, int port, void *c) /* * Try to find host. */ - addr = sk_namelookup(hostname, &dummy_realhost); + addr = name_lookup(hostname, port, &dummy_realhost); if ((err = sk_addr_error(addr))) return err; diff --git a/proxy.c b/proxy.c index 3313abfa..d43ad7b4 100644 --- a/proxy.c +++ b/proxy.c @@ -14,6 +14,10 @@ #include "network.h" #include "proxy.h" +#define do_proxy_dns \ + (cfg.proxy_dns == 2 || \ + (cfg.proxy_dns == 1 && cfg.proxy_type != PROXY_SOCKS)) + /* * Call this when proxy negotiation is complete, so that this * socket can begin working normally. @@ -240,6 +244,10 @@ static int plug_proxy_accepting (Plug p, void *sock) return plug_accepting(ps->plug, sock); } +/* + * 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) { int s = 0, e = 0; @@ -252,13 +260,16 @@ static int proxy_for_destination (SockAddr addr, char * hostname, int port) * representations of `localhost'. */ if (!cfg.even_proxy_localhost && - (sk_hostname_is_local(hostname) || sk_address_is_local(addr))) + (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 */ - sk_getaddr(addr, hostip, 64); + if (addr) { + sk_getaddr(addr, hostip, 64); + hostip_len = strlen(hostip); + } - hostip_len = strlen(hostip); hostname_len = strlen(hostname); exclude_list = cfg.proxy_exclude_list; @@ -285,8 +296,8 @@ static int proxy_for_destination (SockAddr addr, char * hostname, int port) if (exclude_list[s] == '*') { /* wildcard at beginning of entry */ - if (strnicmp(hostip + hostip_len - (e - s - 1), - exclude_list + s + 1, e - s - 1) == 0 || + 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. */ @@ -294,7 +305,7 @@ static int proxy_for_destination (SockAddr addr, char * hostname, int port) } else if (exclude_list[e-1] == '*') { /* wildcard at end of entry */ - if (strnicmp(hostip, exclude_list + s, e - s - 1) == 0 || + 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. */ @@ -303,7 +314,7 @@ static int proxy_for_destination (SockAddr addr, char * hostname, int port) * match (ie. a specific IP) */ - if (stricmp(hostip, exclude_list + s) == 0) + if (addr && stricmp(hostip, exclude_list + s) == 0) return 0; /* IP/hostname excluded. do not use proxy. */ if (stricmp(hostname, exclude_list + s) == 0) return 0; /* IP/hostname excluded. do not use proxy. */ @@ -316,6 +327,17 @@ static int proxy_for_destination (SockAddr addr, char * hostname, int port) return 1; } +SockAddr name_lookup(char *host, int port, char **canonicalname) +{ + if (cfg.proxy_type != PROXY_NONE && + do_proxy_dns && proxy_for_destination(NULL, host, port)) { + *canonicalname = dupstr(host); + return sk_nonamelookup(host); + } + + return sk_namelookup(host, canonicalname); +} + Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, Plug plug) @@ -471,9 +493,9 @@ int proxy_http_negotiate (Proxy_Socket p, int change) * for this proxy method, it's just a simple HTTP * request */ - char *buf, dest[64]; + char *buf, dest[512]; - sk_getaddr(p->remote_addr, dest, 64); + 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); @@ -649,16 +671,25 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) * user ID (variable length, null terminated string) */ - int length; - char * command; + int length, type, namelen; + char *command, addr[4], hostname[512]; - if (sk_addrtype(p->remote_addr) != ADDRTYPE_IPV4) { + 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 */ + 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(cfg.proxy_username) + 9; + length = strlen(cfg.proxy_username) + namelen + 9; command = (char*) smalloc(length); strcpy(command + 8, cfg.proxy_username); @@ -670,7 +701,11 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) command[3] = (char) p->remote_port & 0xff; /* address */ - sk_addrcopy(p->remote_addr, command + 4); + memcpy(command + 4, addr, 4); + + /* hostname */ + memcpy(command + 8 + strlen(cfg.proxy_username) + 1, + hostname, namelen); sk_write(p->sub_socket, command, length); sfree(command); @@ -939,24 +974,30 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) * dest. port (2 bytes) [network order] */ - char command[22]; + char command[512]; int len; + int type; - if (sk_addrtype(p->remote_addr) == ADDRTYPE_IPV4) { - len = 10; + type = sk_addrtype(p->remote_addr); + if (type == ADDRTYPE_IPV4) { + len = 10; /* 4 hdr + 4 addr + 2 trailer */ command[3] = 1; /* IPv4 */ - } else { - len = 22; + 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 if (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; - /* address */ - sk_addrcopy(p->remote_addr, command+4); - /* port */ command[len-2] = (char) (p->remote_port >> 8) & 0xff; command[len-1] = (char) p->remote_port & 0xff; @@ -1230,8 +1271,8 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change) } else if (strnicmp(cfg.proxy_telnet_command + eo, "host", 4) == 0) { - char dest[64]; - sk_getaddr(p->remote_addr, dest, 64); + char dest[512]; + sk_getaddr(p->remote_addr, dest, lenof(dest)); sk_write(p->sub_socket, dest, strlen(dest)); eo += 4; } diff --git a/putty.h b/putty.h index 144ed063..89531254 100644 --- a/putty.h +++ b/putty.h @@ -214,6 +214,7 @@ struct config_tag { int tcp_nodelay; /* Proxy options */ char proxy_exclude_list[512]; + enum { PROXYDNS_NO, PROXYDNS_AUTO, PROXYDNS_YES } proxy_dns; int even_proxy_localhost; enum { PROXY_NONE, PROXY_HTTP, PROXY_SOCKS, PROXY_TELNET } proxy_type; char proxy_host[512]; diff --git a/raw.c b/raw.c index 7aaafb37..8e8f7e0a 100644 --- a/raw.c +++ b/raw.c @@ -95,7 +95,7 @@ static char *raw_init(void *frontend_handle, void **backend_handle, logevent(raw->frontend, buf); sfree(buf); } - addr = sk_namelookup(host, realhost); + addr = name_lookup(host, port, realhost); if ((err = sk_addr_error(addr))) return err; diff --git a/rlogin.c b/rlogin.c index b43804d4..2cc2a217 100644 --- a/rlogin.c +++ b/rlogin.c @@ -126,7 +126,7 @@ static char *rlogin_init(void *frontend_handle, void **backend_handle, logevent(rlogin->frontend, buf); sfree(buf); } - addr = sk_namelookup(host, realhost); + addr = name_lookup(host, port, realhost); if ((err = sk_addr_error(addr))) return err; diff --git a/settings.c b/settings.c index fe90f117..ce21d2c2 100644 --- a/settings.c +++ b/settings.c @@ -150,6 +150,7 @@ void save_settings(char *section, int do_host, Config * cfg) /* proxy settings */ write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list); + write_setting_i(sesskey, "ProxyDNS", cfg->proxy_dns); write_setting_i(sesskey, "ProxyLocalhost", cfg->even_proxy_localhost); write_setting_i(sesskey, "ProxyType", cfg->proxy_type); write_setting_s(sesskey, "ProxyHost", cfg->proxy_host); @@ -384,6 +385,7 @@ void load_settings(char *section, int do_host, Config * cfg) /* proxy settings */ gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list, sizeof(cfg->proxy_exclude_list)); + gppi(sesskey, "ProxyDNS", PROXYDNS_AUTO, &i); cfg->proxy_dns = i; gppi(sesskey, "ProxyLocalhost", 0, &cfg->even_proxy_localhost); gppi(sesskey, "ProxyType", PROXY_NONE, &i); cfg->proxy_type = i; gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host, diff --git a/ssh.c b/ssh.c index 32753657..62f2a8e2 100644 --- a/ssh.c +++ b/ssh.c @@ -2072,7 +2072,7 @@ static char *connect_to_host(Ssh ssh, char *host, int port, * Try to find host. */ logeventf(ssh, "Looking up host \"%s\"", host); - addr = sk_namelookup(host, realhost); + addr = name_lookup(host, port, realhost); if ((err = sk_addr_error(addr))) return err; diff --git a/telnet.c b/telnet.c index cae64d83..ad0ffeb8 100644 --- a/telnet.c +++ b/telnet.c @@ -678,7 +678,7 @@ static char *telnet_init(void *frontend_handle, void **backend_handle, logevent(telnet->frontend, buf); sfree(buf); } - addr = sk_namelookup(host, realhost); + addr = name_lookup(host, port, realhost); if ((err = sk_addr_error(addr))) return err; diff --git a/unix/uxnet.c b/unix/uxnet.c index cad943a8..3440d19e 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -57,12 +57,18 @@ typedef struct Socket_tag *Actual_Socket; struct SockAddr_tag { char *error; - /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */ + /* + * Which address family this address belongs to. AF_INET for + * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name + * resolution has not been done and a simple host name is held + * in this SockAddr structure. + */ int family; unsigned long address; /* Address IPv4 style. */ #ifdef IPV6 struct addrinfo *ai; /* Address IPv6 style. */ #endif + char hostname[512]; /* Store an unresolved host name. */ }; static tree234 *sktree; @@ -194,19 +200,32 @@ SockAddr sk_namelookup(char *host, char **canonicalname) return ret; } +SockAddr sk_nonamelookup(char *host) +{ + SockAddr ret = smalloc(sizeof(struct SockAddr_tag)); + ret->family = AF_UNSPEC; + strncpy(ret->hostname, host, lenof(ret->hostname)); + ret->hostname[lenof(ret->hostname)-1] = '\0'; + return ret; +} + void sk_getaddr(SockAddr addr, char *buf, int buflen) { #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + FIXME; /* I don't know how to get a text form of an IPv6 address. */ + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); strncpy(buf, inet_ntoa(a), buflen); -#ifdef IPV6 + buf[buflen-1] = '\0'; } else { - FIXME; /* I don't know how to get a text form of an IPv6 address. */ + assert(addr->family == AF_UNSPEC); + strncpy(buf, addr->hostname, buflen); + buf[buflen-1] = '\0'; } -#endif } int sk_hostname_is_local(char *name) @@ -217,36 +236,42 @@ int sk_hostname_is_local(char *name) int sk_address_is_local(SockAddr addr) { #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + FIXME; /* someone who can compile for IPV6 had better do this bit */ + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); return ipv4_is_loopback(a); -#ifdef IPV6 } else { - FIXME; /* someone who can compile for IPV6 had better do this bit */ + assert(addr->family == AF_UNSPEC); + return 0; /* we don't know; assume not */ } -#endif } int sk_addrtype(SockAddr addr) { - return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6); + return (addr->family == AF_INET ? ADDRTYPE_IPV4 : +#ifdef IPV6 + addr->family == AF_INET6 ? ADDRTYPE_IPV6 : +#endif + ADDRTYPE_NAME); } void sk_addrcopy(SockAddr addr, char *buf) { + assert(addr->family != AF_UNSPEC); #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + memcpy(buf, (char*) addr->ai, 16); + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); memcpy(buf, (char*) &a.s_addr, 4); -#ifdef IPV6 - } else { - memcpy(buf, (char*) addr->ai, 16); } -#endif } void sk_addr_free(SockAddr addr) @@ -371,6 +396,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, /* * Open socket. */ + assert(addr->family != AF_UNSPEC); s = socket(addr->family, SOCK_STREAM, 0); ret->s = s; diff --git a/windlg.c b/windlg.c index 40880ec9..a8603e65 100644 --- a/windlg.c +++ b/windlg.c @@ -455,6 +455,10 @@ enum { IDCX_ABOUT = IDC_PROXYEXCLUDESTATIC, IDC_PROXYEXCLUDEEDIT, IDC_PROXYLOCALHOST, + IDC_PROXYDNSSTATIC, + IDC_PROXYDNSNO, + IDC_PROXYDNSAUTO, + IDC_PROXYDNSYES, IDC_PROXYUSERSTATIC, IDC_PROXYUSEREDIT, IDC_PROXYPASSSTATIC, @@ -885,6 +889,11 @@ char *help_context_cmd(int id) case IDC_PROXYEXCLUDEEDIT: case IDC_PROXYLOCALHOST: return "JI(`',`proxy.exclude')"; + case IDC_PROXYDNSSTATIC: + case IDC_PROXYDNSNO: + case IDC_PROXYDNSAUTO: + case IDC_PROXYDNSYES: + return "JI(`',`proxy.dns')"; case IDC_PROXYUSERSTATIC: case IDC_PROXYUSEREDIT: case IDC_PROXYPASSSTATIC: @@ -1352,6 +1361,10 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess) SetDlgItemInt(hwnd, IDC_PROXYPORTEDIT, cfg.proxy_port, FALSE); SetDlgItemText(hwnd, IDC_PROXYEXCLUDEEDIT, cfg.proxy_exclude_list); CheckDlgButton(hwnd, IDC_PROXYLOCALHOST, cfg.even_proxy_localhost); + CheckRadioButton(hwnd, IDC_PROXYDNSNO, IDC_PROXYDNSYES, + cfg.proxy_dns == PROXYDNS_NO ? IDC_PROXYDNSNO : + cfg.proxy_dns == PROXYDNS_YES ? IDC_PROXYDNSYES : + IDC_PROXYDNSAUTO); SetDlgItemText(hwnd, IDC_PROXYTELNETCMDEDIT, cfg.proxy_telnet_command); SetDlgItemText(hwnd, IDC_PROXYUSEREDIT, cfg.proxy_username); SetDlgItemText(hwnd, IDC_PROXYPASSEDIT, cfg.proxy_password); @@ -1853,7 +1866,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) } if (panel == proxypanelstart) { - /* The Proxy panel. Accelerators used: [acgoh] ntslypeuwmv */ + /* The Proxy panel. Accelerators used: [acgoh] ntslypeuwmvxd */ struct ctlpos cp; ctlposinit(&cp, hwnd, 80, 3, 13); if (dlgtype == 0) { @@ -1873,6 +1886,11 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) IDC_PROXYEXCLUDEEDIT, 100, NULL); checkbox(&cp, "Consider pro&xying local host connections", IDC_PROXYLOCALHOST); + radioline(&cp, "Do &DNS name lookup at proxy end:", + IDC_PROXYDNSSTATIC, 3, + "No", IDC_PROXYDNSNO, + "Auto", IDC_PROXYDNSAUTO, + "Yes", IDC_PROXYDNSYES, NULL); staticedit(&cp, "&Username", IDC_PROXYUSERSTATIC, IDC_PROXYUSEREDIT, 60); staticpassedit(&cp, "Pass&word", IDC_PROXYPASSSTATIC, @@ -3034,6 +3052,17 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg, cfg.even_proxy_localhost = IsDlgButtonChecked(hwnd, IDC_PROXYLOCALHOST); break; + case IDC_PROXYDNSNO: + case IDC_PROXYDNSAUTO: + case IDC_PROXYDNSYES: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) { + cfg.proxy_dns = + IsDlgButtonChecked(hwnd, IDC_PROXYDNSNO) ? PROXYDNS_NO : + IsDlgButtonChecked(hwnd, IDC_PROXYDNSYES) ? PROXYDNS_YES : + PROXYDNS_AUTO; + } + break; case IDC_PROXYTYPENONE: case IDC_PROXYTYPEHTTP: case IDC_PROXYTYPESOCKS: diff --git a/winnet.c b/winnet.c index b66cde6a..e94075b5 100644 --- a/winnet.c +++ b/winnet.c @@ -90,12 +90,18 @@ typedef struct Socket_tag *Actual_Socket; struct SockAddr_tag { char *error; - /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */ + /* + * Which address family this address belongs to. AF_INET for + * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name + * resolution has not been done and a simple host name is held + * in this SockAddr structure. + */ int family; unsigned long address; /* Address IPv4 style. */ #ifdef IPV6 struct addrinfo *ai; /* Address IPv6 style. */ #endif + char hostname[512]; /* Store an unresolved host name. */ }; static tree234 *sktree; @@ -356,19 +362,32 @@ SockAddr sk_namelookup(char *host, char **canonicalname) return ret; } +SockAddr sk_nonamelookup(char *host) +{ + SockAddr ret = smalloc(sizeof(struct SockAddr_tag)); + ret->family = AF_UNSPEC; + strncpy(ret->hostname, host, lenof(ret->hostname)); + ret->hostname[lenof(ret->hostname)-1] = '\0'; + return ret; +} + void sk_getaddr(SockAddr addr, char *buf, int buflen) { #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + FIXME; /* I don't know how to get a text form of an IPv6 address. */ + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); strncpy(buf, inet_ntoa(a), buflen); -#ifdef IPV6 + buf[buflen-1] = '\0'; } else { - FIXME; /* I don't know how to get a text form of an IPv6 address. */ + assert(addr->family == AF_UNSPEC); + strncpy(buf, addr->hostname, buflen); + buf[buflen-1] = '\0'; } -#endif } int sk_hostname_is_local(char *name) @@ -379,36 +398,42 @@ int sk_hostname_is_local(char *name) int sk_address_is_local(SockAddr addr) { #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + FIXME; /* someone who can compile for IPV6 had better do this bit */ + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); return ipv4_is_loopback(a); -#ifdef IPV6 } else { - FIXME; /* someone who can compile for IPV6 had better do this bit */ + assert(addr->family == AF_UNSPEC); + return 0; /* we don't know; assume not */ } -#endif } int sk_addrtype(SockAddr addr) { - return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6); + return (addr->family == AF_INET ? ADDRTYPE_IPV4 : +#ifdef IPV6 + addr->family == AF_INET6 ? ADDRTYPE_IPV6 : +#endif + ADDRTYPE_NAME); } void sk_addrcopy(SockAddr addr, char *buf) { + assert(addr->family != AF_UNSPEC); #ifdef IPV6 - if (addr->family == AF_INET) { + if (addr->family == AF_INET6) { + memcpy(buf, (char*) addr->ai, 16); + } else #endif + if (addr->family == AF_INET) { struct in_addr a; a.s_addr = htonl(addr->address); memcpy(buf, (char*) &a.s_addr, 4); -#ifdef IPV6 - } else { - memcpy(buf, (char*) addr->ai, 16); } -#endif } void sk_addr_free(SockAddr addr) @@ -543,6 +568,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, /* * Open socket. */ + assert(addr->family != AF_UNSPEC); s = socket(addr->family, SOCK_STREAM, 0); ret->s = s; @@ -731,10 +757,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only) ret->oobinline = 0; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); - #ifdef IPV6 if (addr->family == AF_INET6) { memset(&a6, 0, sizeof(a6)); diff --git a/x11fwd.c b/x11fwd.c index c6e36378..35d1d175 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -177,7 +177,7 @@ char *x11_init(Socket * s, char *display, void *c, void *auth) /* * Try to find host. */ - addr = sk_namelookup(host, &dummy_realhost); + addr = name_lookup(host, port, &dummy_realhost); if ((err = sk_addr_error(addr))) return err; -- 2.11.0