Skip to content

Commit 86ceb33

Browse files
tboegigitster
authored andcommitted
connect.c: allow ssh://user@[2001:db8::1]/repo.git
The ssh:// syntax was added in 2386d65 (Add first cut at "git protocol" connect logic., 2005-07-13), it accepted ssh://user@2001:db8::1/repo.git, which is now legacy. Over the years the parser was improved to support [] and port numbers, but the combination of ssh://user@[2001:db8::1]:222/repo.git did never work. The only only way to use a user name, a literall IPV6 address and a port number was ssh://[user@2001:db8::1]:222/repo.git (Thanks to Christian Taube <[email protected]> for reporting this long standing issue) New users would use ssh://user@[2001:db8::1]:222/repo.git, so change the parser to handle it correctly. Support the old legacy URLs as well, to be backwards compatible, and avoid regressions for users which upgrade an existing installation to a later Git version. Signed-off-by: Torsten Bögershausen <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fdf96a2 commit 86ceb33

File tree

2 files changed

+39
-26
lines changed

2 files changed

+39
-26
lines changed

connect.c

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -274,28 +274,44 @@ static enum protocol get_protocol(const char *name)
274274
die("I don't handle protocol '%s'", name);
275275
}
276276

277+
static char *host_end(char **hoststart, int removebrackets)
278+
{
279+
char *host = *hoststart;
280+
char *end;
281+
char *start = strstr(host, "@[");
282+
if (start)
283+
start++; /* Jump over '@' */
284+
else
285+
start = host;
286+
if (start[0] == '[') {
287+
end = strchr(start + 1, ']');
288+
if (end) {
289+
if (removebrackets) {
290+
*end = 0;
291+
memmove(start, start + 1, end - start);
292+
end++;
293+
}
294+
} else
295+
end = host;
296+
} else
297+
end = host;
298+
return end;
299+
}
300+
277301
#define STR_(s) # s
278302
#define STR(s) STR_(s)
279303

280304
static void get_host_and_port(char **host, const char **port)
281305
{
282306
char *colon, *end;
283-
284-
if (*host[0] == '[') {
285-
end = strchr(*host + 1, ']');
286-
if (end) {
287-
*end = 0;
288-
end++;
289-
(*host)++;
290-
} else
291-
end = *host;
292-
} else
293-
end = *host;
307+
end = host_end(host, 1);
294308
colon = strchr(end, ':');
295-
296309
if (colon) {
297-
*colon = 0;
298-
*port = colon + 1;
310+
long portnr = strtol(colon + 1, &end, 10);
311+
if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {
312+
*colon = 0;
313+
*port = colon + 1;
314+
}
299315
}
300316
}
301317

@@ -547,13 +563,16 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
547563
return proxy;
548564
}
549565

550-
static const char *get_port_numeric(const char *p)
566+
static char *get_port(char *host)
551567
{
552568
char *end;
569+
char *p = strchr(host, ':');
570+
553571
if (p) {
554572
long port = strtol(p + 1, &end, 10);
555573
if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {
556-
return p;
574+
*p = '\0';
575+
return p+1;
557576
}
558577
}
559578

@@ -595,14 +614,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
595614
* Don't do destructive transforms as protocol code does
596615
* '[]' unwrapping in get_host_and_port()
597616
*/
598-
if (host[0] == '[') {
599-
end = strchr(host + 1, ']');
600-
if (end) {
601-
end++;
602-
} else
603-
end = host;
604-
} else
605-
end = host;
617+
end = host_end(&host, 0);
606618

607619
if (protocol == PROTO_LOCAL)
608620
path = end;
@@ -705,7 +717,8 @@ struct child_process *git_connect(int fd[2], const char *url,
705717
char *ssh_host = hostandport;
706718
const char *port = NULL;
707719
get_host_and_port(&ssh_host, &port);
708-
port = get_port_numeric(port);
720+
if (!port)
721+
port = get_port(ssh_host);
709722

710723
if (!ssh) ssh = "ssh";
711724

t/t5601-clone.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' '
326326

327327
test_expect_success 'bracketed hostnames are still ssh' '
328328
git clone "[myhost:123]:src" ssh-bracket-clone &&
329-
expect_ssh myhost:123 src
329+
expect_ssh myhost '-p 123' src
330330
'
331331

332332
counter=0

0 commit comments

Comments
 (0)