From: Junio C Hamano Date: Thu, 5 Mar 2015 20:45:44 +0000 (-0800) Subject: Merge branch 'tb/connect-ipv6-parse-fix' X-Git-Tag: v2.4.0-rc0~68 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/42da484006186e653e8b3bf3b4c6b40816450ed2?hp=-c Merge branch 'tb/connect-ipv6-parse-fix' We did not parse username followed by literal IPv6 address in SSH transport URLs, e.g. ssh://user@[2001:db8::1]:22/repo.git correctly. * tb/connect-ipv6-parse-fix: t5500: show user name and host in diag-url t5601: add more test cases for IPV6 connect.c: allow ssh://user@[2001:db8::1]/repo.git --- 42da484006186e653e8b3bf3b4c6b40816450ed2 diff --combined connect.c index d50f52ad8b,84f8156a4c..ce0e121423 --- a/connect.c +++ b/connect.c @@@ -93,7 -93,7 +93,7 @@@ static void annotate_refs_with_symref_i parse_one_symref_info(&symref, val, len); feature_list = val + 1; } - sort_string_list(&symref); + string_list_sort(&symref); for (; ref; ref = ref->next) { struct string_list_item *item; @@@ -157,7 -157,8 +157,7 @@@ struct ref **get_remote_heads(int in, c server_capabilities = xstrdup(name + name_len + 1); } - if (extra_have && - name_len == 5 && !memcmp(".have", name, 5)) { + if (extra_have && !strcmp(name, ".have")) { sha1_array_append(extra_have, old_sha1); continue; } @@@ -273,28 -274,44 +273,44 @@@ static enum protocol get_protocol(cons die("I don't handle protocol '%s'", name); } + static char *host_end(char **hoststart, int removebrackets) + { + char *host = *hoststart; + char *end; + char *start = strstr(host, "@["); + if (start) + start++; /* Jump over '@' */ + else + start = host; + if (start[0] == '[') { + end = strchr(start + 1, ']'); + if (end) { + if (removebrackets) { + *end = 0; + memmove(start, start + 1, end - start); + end++; + } + } else + end = host; + } else + end = host; + return end; + } + #define STR_(s) # s #define STR(s) STR_(s) static void get_host_and_port(char **host, const char **port) { char *colon, *end; - - if (*host[0] == '[') { - end = strchr(*host + 1, ']'); - if (end) { - *end = 0; - end++; - (*host)++; - } else - end = *host; - } else - end = *host; + end = host_end(host, 1); colon = strchr(end, ':'); - if (colon) { - *colon = 0; - *port = colon + 1; + long portnr = strtol(colon + 1, &end, 10); + if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) { + *colon = 0; + *port = colon + 1; + } } } @@@ -546,13 -563,16 +562,16 @@@ static struct child_process *git_proxy_ return proxy; } - static const char *get_port_numeric(const char *p) + static char *get_port(char *host) { char *end; + char *p = strchr(host, ':'); + if (p) { long port = strtol(p + 1, &end, 10); if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) { - return p; + *p = '\0'; + return p+1; } } @@@ -594,14 -614,7 +613,7 @@@ static enum protocol parse_connect_url( * Don't do destructive transforms as protocol code does * '[]' unwrapping in get_host_and_port() */ - if (host[0] == '[') { - end = strchr(host + 1, ']'); - if (end) { - end++; - } else - end = host; - } else - end = host; + end = host_end(&host, 0); if (protocol == PROTO_LOCAL) path = end; @@@ -662,27 -675,17 +674,27 @@@ struct child_process *git_connect(int f signal(SIGCHLD, SIG_DFL); protocol = parse_connect_url(url, &hostandport, &path); - if (flags & CONNECT_DIAG_URL) { + if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) { printf("Diag: url=%s\n", url ? url : "NULL"); printf("Diag: protocol=%s\n", prot_name(protocol)); printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL"); printf("Diag: path=%s\n", path ? path : "NULL"); conn = NULL; } else if (protocol == PROTO_GIT) { + /* + * Set up virtual host information based on where we will + * connect, unless the user has overridden us in + * the environment. + */ + char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST"); + if (target_host) + target_host = xstrdup(target_host); + else + target_host = xstrdup(hostandport); + /* These underlying connection commands die() if they * cannot connect. */ - char *target_host = xstrdup(hostandport); if (git_use_proxy(hostandport)) conn = git_proxy_connect(fd, hostandport); else @@@ -709,33 -712,36 +721,47 @@@ conn->in = conn->out = -1; if (protocol == PROTO_SSH) { - const char *ssh = getenv("GIT_SSH"); - int putty = ssh && strcasestr(ssh, "plink"); + const char *ssh; + int putty; char *ssh_host = hostandport; const char *port = NULL; get_host_and_port(&ssh_host, &port); - port = get_port_numeric(port); + - ssh = getenv("GIT_SSH_COMMAND"); - if (ssh) { - conn->use_shell = 1; - putty = 0; - } else { - ssh = getenv("GIT_SSH"); - if (!ssh) - ssh = "ssh"; - putty = !!strcasestr(ssh, "plink"); - } + if (!port) + port = get_port(ssh_host); ++ + if (flags & CONNECT_DIAG_URL) { + printf("Diag: url=%s\n", url ? url : "NULL"); + printf("Diag: protocol=%s\n", prot_name(protocol)); + printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL"); + printf("Diag: port=%s\n", port ? port : "NONE"); + printf("Diag: path=%s\n", path ? path : "NULL"); - argv_array_push(&conn->args, ssh); - if (putty && !strcasestr(ssh, "tortoiseplink")) - argv_array_push(&conn->args, "-batch"); - if (port) { - /* P is for PuTTY, p is for OpenSSH */ - argv_array_push(&conn->args, putty ? "-P" : "-p"); - argv_array_push(&conn->args, port); + free(hostandport); + free(path); + return NULL; + } else { - if (!ssh) ssh = "ssh"; ++ ssh = getenv("GIT_SSH_COMMAND"); ++ if (ssh) { ++ conn->use_shell = 1; ++ putty = 0; ++ } else { ++ ssh = getenv("GIT_SSH"); ++ if (!ssh) ++ ssh = "ssh"; ++ putty = !!strcasestr(ssh, "plink"); ++ } + + argv_array_push(&conn->args, ssh); + if (putty && !strcasestr(ssh, "tortoiseplink")) + argv_array_push(&conn->args, "-batch"); + if (port) { + /* P is for PuTTY, p is for OpenSSH */ + argv_array_push(&conn->args, putty ? "-P" : "-p"); + argv_array_push(&conn->args, port); + } + argv_array_push(&conn->args, ssh_host); } - argv_array_push(&conn->args, ssh_host); } else { /* remove repo-local variables from the environment */ conn->env = local_repo_env;