From 8da4fa506389910599c59b87ba1b799efd6d3ae1 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 25 Jan 2014 15:58:54 +0000 Subject: [PATCH] Use the new host_str* functions to improve IPv6 literal support. I've gone through everywhere we handle host names / addresses (on command lines, in PuTTY config, in port forwarding, in X display names, in host key storage...) and tried to make them handle IPv6 literals sensibly, by using the host_str* functions I introduced in my previous commit. Generally it's now OK to use a bracketed IPv6 literal anywhere a hostname might have been valid; in a few cases where no ambiguity exists (e.g. no :port suffix is permitted anyway) unbracketed IPv6 literals are also acceptable. [originally from svn r10120] --- cmdline.c | 6 +++--- config.c | 2 +- pscp.c | 22 +++------------------- raw.c | 11 +++-------- rlogin.c | 11 +++-------- ssh.c | 30 +++++++++++++++++++----------- telnet.c | 11 +++-------- unix/uxnet.c | 12 ++++++++++-- unix/uxplink.c | 5 ++--- unix/uxputty.c | 3 +-- windows/window.c | 13 ++++++------- windows/winnet.c | 8 +++++++- windows/winplink.c | 5 ++--- x11fwd.c | 4 ++-- 14 files changed, 65 insertions(+), 78 deletions(-) diff --git a/cmdline.c b/cmdline.c index bafb9399..0c7ef4c9 100644 --- a/cmdline.c +++ b/cmdline.c @@ -261,9 +261,9 @@ int cmdline_process_param(char *p, char *value, int need_save, Conf *conf) type = p[1]; /* 'L' or 'R' */ - q = qq = strchr(value, ':'); + q = qq = host_strchr(value, ':'); while (qq) { - char *qqq = strchr(qq+1, ':'); + char *qqq = host_strchr(qq+1, ':'); if (qqq) q = qq; qq = qqq; @@ -301,7 +301,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Conf *conf) UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - portp = strchr(value, ':'); + portp = host_strchr(value, ':'); if (!portp) { cmdline_error("-nc expects argument of form 'host:port'"); return ret; diff --git a/config.c b/config.c index 5d019344..1596c2f1 100644 --- a/config.c +++ b/config.c @@ -1146,7 +1146,7 @@ static void portfwd_handler(union control *ctrl, void *dlg, } if (*type != 'D') { val = dlg_editbox_get(pfd->destbox, dlg); - if (!*val || !strchr(val, ':')) { + if (!*val || !host_strchr(val, ':')) { dlg_error_msg(dlg, "You need to specify a destination address\n" "in the form \"host.name:port\""); diff --git a/pscp.c b/pscp.c index 484c348e..f63e6b59 100644 --- a/pscp.c +++ b/pscp.c @@ -370,15 +370,9 @@ static void do_cmd(char *host, char *user, char *cmd) bump("Empty host name"); /* - * Remove fiddly bits of address: remove a colon suffix, and - * the square brackets around an IPv6 literal address. + * Remove a colon suffix. */ - if (host[0] == '[') { - host++; - host[strcspn(host, "]")] = '\0'; - } else { - host[strcspn(host, ":")] = '\0'; - } + host[host_strcspn(host, ":")] = '\0'; /* * If we haven't loaded session details already (e.g., from -load), @@ -613,17 +607,7 @@ static char *colon(char *str) if (str[0] == '\0' || str[0] == ':' || (str[0] != '[' && str[1] == ':')) return (NULL); - while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\') { - if (*str == '[') { - /* Skip over IPv6 literal addresses - * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */ - char *ipv6_end = strchr(str, ']'); - if (ipv6_end) { - str = ipv6_end; - } - } - str++; - } + str += host_strcspn(str, ":/\\"); if (*str == ':') return (str); else diff --git a/raw.c b/raw.c index 1d9f854c..a7fbbc5c 100644 --- a/raw.c +++ b/raw.c @@ -185,15 +185,10 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, sfree(*realhost); *realhost = dupstr(loghost); - colon = strrchr(*realhost, ':'); - if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ + + colon = host_strrchr(*realhost, ':'); + if (colon) *colon++ = '\0'; - } } return NULL; diff --git a/rlogin.c b/rlogin.c index f582f0c0..3c86eee8 100644 --- a/rlogin.c +++ b/rlogin.c @@ -226,15 +226,10 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, sfree(*realhost); *realhost = dupstr(loghost); - colon = strrchr(*realhost, ':'); - if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ + + colon = host_strrchr(*realhost, ':'); + if (colon) *colon++ = '\0'; - } } /* diff --git a/ssh.c b/ssh.c index 8bcb1e85..b86f0de1 100644 --- a/ssh.c +++ b/ssh.c @@ -3411,25 +3411,27 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, loghost = conf_get_str(ssh->conf, CONF_loghost); if (*loghost) { - char *colon; + char *tmphost; + char *colon; - ssh->savedhost = dupstr(loghost); + tmphost = dupstr(loghost); ssh->savedport = 22; /* default ssh port */ /* - * A colon suffix on savedhost also lets us affect + * A colon suffix on the hostname string also lets us affect * savedport. - * - * (FIXME: do something about IPv6 address literals here.) */ - colon = strrchr(ssh->savedhost, ':'); + colon = host_strrchr(tmphost, ':'); if (colon) { *colon++ = '\0'; if (*colon) ssh->savedport = atoi(colon); } + + ssh->savedhost = host_strduptrim(tmphost); + sfree(tmphost); } else { - ssh->savedhost = dupstr(host); + ssh->savedhost = host_strduptrim(host); if (port < 0) port = 22; /* default ssh port */ ssh->savedport = port; @@ -4915,13 +4917,15 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) if (*kp == 'L' || *kp == 'R') type = *kp++; - if ((kp2 = strchr(kp, ':')) != NULL) { + if ((kp2 = host_strchr(kp, ':')) != NULL) { /* * There's a colon in the middle of the source port * string, which means that the part before it is * actually a source address. */ - saddr = dupprintf("%.*s", (int)(kp2 - kp), kp); + char *saddr_tmp = dupprintf("%.*s", (int)(kp2 - kp), kp); + saddr = host_strduptrim(saddr_tmp); + sfree(saddr_tmp); sports = kp2+1; } else { saddr = NULL; @@ -4948,7 +4952,7 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf) } else { /* ordinary forwarding */ vp = val; - vp2 = vp + strcspn(vp, ":"); + vp2 = vp + host_strcspn(vp, ":"); host = dupprintf("%.*s", (int)(vp2 - vp), vp); if (vp2) vp2++; @@ -11024,7 +11028,11 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org) PKT_END); } else { pktout = ssh2_chanopen_init(c, "direct-tcpip"); - ssh2_pkt_addstring(pktout, hostname); + { + char *trimmed_host = host_strduptrim(hostname); + ssh2_pkt_addstring(pktout, trimmed_host); + sfree(trimmed_host); + } ssh2_pkt_adduint32(pktout, port); /* * We make up values for the originator data; partly it's diff --git a/telnet.c b/telnet.c index 6a56da77..098db292 100644 --- a/telnet.c +++ b/telnet.c @@ -818,15 +818,10 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, sfree(*realhost); *realhost = dupstr(loghost); - colon = strrchr(*realhost, ':'); - if (colon) { - /* - * FIXME: if we ever update this aspect of ssh.c for - * IPv6 literal management, this should change in line - * with it. - */ + + colon = host_strrchr(*realhost, ':'); + if (colon) *colon++ = '\0'; - } } return NULL; diff --git a/unix/uxnet.c b/unix/uxnet.c index 868f9d0a..1fe78436 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -221,7 +221,11 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_famil hints.ai_addr = NULL; hints.ai_canonname = NULL; hints.ai_next = NULL; - err = getaddrinfo(host, NULL, &hints, &ret->ais); + { + char *trimmed_host = host_strduptrim(host); /* strip [] on literals */ + err = getaddrinfo(trimmed_host, NULL, &hints, &ret->ais); + sfree(trimmed_host); + } if (err != 0) { ret->error = gai_strerror(err); return ret; @@ -868,7 +872,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i hints.ai_next = NULL; assert(port >= 0 && port <= 99999); sprintf(portstr, "%d", port); - retcode = getaddrinfo(srcaddr, portstr, &hints, &ai); + { + char *trimmed_addr = host_strduptrim(srcaddr); + retcode = getaddrinfo(trimmed_addr, portstr, &hints, &ai); + sfree(trimmed_addr); + } if (retcode == 0) { addr = (union sockaddr_union *)ai->ai_addr; addrlen = ai->ai_addrlen; diff --git a/unix/uxplink.c b/unix/uxplink.c index 7fbaa36a..961fcf9a 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -705,8 +705,7 @@ int main(int argc, char **argv) q += 2; conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; - while (*p && *p != ':' && *p != '/') - p++; + p += host_strcspn(p, ":/"); c = *p; if (*p) *p++ = '\0'; @@ -847,7 +846,7 @@ int main(int argc, char **argv) /* * Trim off a colon suffix if it's there. */ - host[strcspn(host, ":")] = '\0'; + host[host_strcspn(host, ":")] = '\0'; /* * Remove any remaining whitespace. diff --git a/unix/uxputty.c b/unix/uxputty.c index 1e3604ba..c7b0fcb2 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -76,8 +76,7 @@ int process_nonoption_arg(char *arg, Conf *conf, int *allow_launch) q += 2; conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; - while (*p && *p != ':' && *p != '/') - p++; + p += host_strcspn(p, ":/"); c = *p; if (*p) *p++ = '\0'; diff --git a/windows/window.c b/windows/window.c index bf212b9a..bf8d651e 100644 --- a/windows/window.c +++ b/windows/window.c @@ -548,8 +548,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) q += 2; conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; - while (*p && *p != ':' && *p != '/') - p++; + p += host_strcspn(p, ":/"); c = *p; if (*p) *p++ = '\0'; @@ -614,15 +613,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * Trim a colon suffix off the hostname if it's there. In - * order to protect IPv6 address literals against this - * treatment, we do not do this if there's _more_ than one - * colon. + * order to protect unbracketed IPv6 address literals + * against this treatment, we do not do this if there's + * _more_ than one colon. */ { - char *c = strchr(host, ':'); + char *c = host_strchr(host, ':'); if (c) { - char *d = strchr(c+1, ':'); + char *d = host_strchr(c+1, ':'); if (!d) *c = '\0'; } diff --git a/windows/winnet.c b/windows/winnet.c index f4507240..1a5a76f1 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -527,7 +527,13 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, memset(&hints, 0, sizeof(hints)); hints.ai_family = hint_family; hints.ai_flags = AI_CANONNAME; - if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0) + { + /* strip [] on IPv6 address literals */ + char *trimmed_host = host_strduptrim(host); + err = p_getaddrinfo(trimmed_host, NULL, &hints, &ret->ais); + sfree(trimmed_host); + } + if (err == 0) ret->resolved = TRUE; } else #endif diff --git a/windows/winplink.c b/windows/winplink.c index ac7069a2..48232b38 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -382,8 +382,7 @@ int main(int argc, char **argv) q += 2; conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; - while (*p && *p != ':' && *p != '/') - p++; + p += host_strcspn(p, ":/"); c = *p; if (*p) *p++ = '\0'; @@ -524,7 +523,7 @@ int main(int argc, char **argv) /* * Trim off a colon suffix if it's there. */ - host[strcspn(host, ":")] = '\0'; + host[host_strcspn(host, ":")] = '\0'; /* * Remove any remaining whitespace. diff --git a/x11fwd.c b/x11fwd.c index ce572f69..7ecb4cc2 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -230,7 +230,7 @@ struct X11Display *x11_setup_display(char *display, Conf *conf) char *colon, *dot, *slash; char *protocol, *hostname; - colon = strrchr(localcopy, ':'); + colon = host_strrchr(localcopy, ':'); if (!colon) { sfree(disp); sfree(localcopy); @@ -677,7 +677,7 @@ int x11_get_screen_number(char *display) { int n; - n = strcspn(display, ":"); + n = host_strcspn(display, ":"); if (!display[n]) return 0; n = strcspn(display, "."); -- 2.45.2