Skip to content

Commit 8c2ea51

Browse files
committed
Merge branch 'tb/connect-ipv6-parse-fix' into maint
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
2 parents bb85775 + 3f55cca commit 8c2ea51

File tree

3 files changed

+144
-80
lines changed

3 files changed

+144
-80
lines changed

connect.c

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

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

279303
static void get_host_and_port(char **host, const char **port)
280304
{
281305
char *colon, *end;
282-
283-
if (*host[0] == '[') {
284-
end = strchr(*host + 1, ']');
285-
if (end) {
286-
*end = 0;
287-
end++;
288-
(*host)++;
289-
} else
290-
end = *host;
291-
} else
292-
end = *host;
306+
end = host_end(host, 1);
293307
colon = strchr(end, ':');
294-
295308
if (colon) {
296-
*colon = 0;
297-
*port = colon + 1;
309+
long portnr = strtol(colon + 1, &end, 10);
310+
if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {
311+
*colon = 0;
312+
*port = colon + 1;
313+
}
298314
}
299315
}
300316

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

549-
static const char *get_port_numeric(const char *p)
565+
static char *get_port(char *host)
550566
{
551567
char *end;
568+
char *p = strchr(host, ':');
569+
552570
if (p) {
553571
long port = strtol(p + 1, &end, 10);
554572
if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {
555-
return p;
573+
*p = '\0';
574+
return p+1;
556575
}
557576
}
558577

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

606618
if (protocol == PROTO_LOCAL)
607619
path = end;
@@ -662,7 +674,7 @@ struct child_process *git_connect(int fd[2], const char *url,
662674
signal(SIGCHLD, SIG_DFL);
663675

664676
protocol = parse_connect_url(url, &hostandport, &path);
665-
if (flags & CONNECT_DIAG_URL) {
677+
if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
666678
printf("Diag: url=%s\n", url ? url : "NULL");
667679
printf("Diag: protocol=%s\n", prot_name(protocol));
668680
printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
@@ -714,28 +726,42 @@ struct child_process *git_connect(int fd[2], const char *url,
714726
char *ssh_host = hostandport;
715727
const char *port = NULL;
716728
get_host_and_port(&ssh_host, &port);
717-
port = get_port_numeric(port);
718729

719-
ssh = getenv("GIT_SSH_COMMAND");
720-
if (ssh) {
721-
conn->use_shell = 1;
722-
putty = 0;
723-
} else {
724-
ssh = getenv("GIT_SSH");
725-
if (!ssh)
726-
ssh = "ssh";
727-
putty = !!strcasestr(ssh, "plink");
728-
}
730+
if (!port)
731+
port = get_port(ssh_host);
732+
733+
if (flags & CONNECT_DIAG_URL) {
734+
printf("Diag: url=%s\n", url ? url : "NULL");
735+
printf("Diag: protocol=%s\n", prot_name(protocol));
736+
printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
737+
printf("Diag: port=%s\n", port ? port : "NONE");
738+
printf("Diag: path=%s\n", path ? path : "NULL");
729739

730-
argv_array_push(&conn->args, ssh);
731-
if (putty && !strcasestr(ssh, "tortoiseplink"))
732-
argv_array_push(&conn->args, "-batch");
733-
if (port) {
734-
/* P is for PuTTY, p is for OpenSSH */
735-
argv_array_push(&conn->args, putty ? "-P" : "-p");
736-
argv_array_push(&conn->args, port);
740+
free(hostandport);
741+
free(path);
742+
return NULL;
743+
} else {
744+
ssh = getenv("GIT_SSH_COMMAND");
745+
if (ssh) {
746+
conn->use_shell = 1;
747+
putty = 0;
748+
} else {
749+
ssh = getenv("GIT_SSH");
750+
if (!ssh)
751+
ssh = "ssh";
752+
putty = !!strcasestr(ssh, "plink");
753+
}
754+
755+
argv_array_push(&conn->args, ssh);
756+
if (putty && !strcasestr(ssh, "tortoiseplink"))
757+
argv_array_push(&conn->args, "-batch");
758+
if (port) {
759+
/* P is for PuTTY, p is for OpenSSH */
760+
argv_array_push(&conn->args, putty ? "-P" : "-p");
761+
argv_array_push(&conn->args, port);
762+
}
763+
argv_array_push(&conn->args, ssh_host);
737764
}
738-
argv_array_push(&conn->args, ssh_host);
739765
} else {
740766
/* remove repo-local variables from the environment */
741767
conn->env = local_repo_env;

t/t5500-fetch-pack.sh

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,30 @@ check_prot_path () {
541541
test_cmp expected actual
542542
}
543543

544-
check_prot_host_path () {
545-
cat >expected <<-EOF &&
544+
check_prot_host_port_path () {
545+
local diagport
546+
case "$2" in
547+
*ssh*)
548+
pp=ssh
549+
uah=userandhost
550+
ehost=$(echo $3 | tr -d "[]")
551+
diagport="Diag: port=$4"
552+
;;
553+
*)
554+
pp=$p
555+
uah=hostandport
556+
ehost=$(echo $3$4 | sed -e "s/22$/:22/" -e "s/NONE//")
557+
diagport=""
558+
;;
559+
esac
560+
cat >exp <<-EOF &&
546561
Diag: url=$1
547-
Diag: protocol=$2
548-
Diag: hostandport=$3
549-
Diag: path=$4
562+
Diag: protocol=$pp
563+
Diag: $uah=$ehost
564+
$diagport
565+
Diag: path=$5
550566
EOF
567+
grep -v "^$" exp >expected
551568
git fetch-pack --diag-url "$1" >actual &&
552569
test_cmp expected actual
553570
}
@@ -557,22 +574,20 @@ do
557574
# git or ssh with scheme
558575
for p in "ssh+git" "git+ssh" git ssh
559576
do
560-
for h in host host:12 [::1] [::1]:23
577+
for h in host user@host user@[::1] user@::1
561578
do
562-
case "$p" in
563-
*ssh*)
564-
pp=ssh
565-
;;
566-
*)
567-
pp=$p
568-
;;
569-
esac
570579
test_expect_success "fetch-pack --diag-url $p://$h/$r" '
571-
check_prot_host_path $p://$h/$r $pp "$h" "/$r"
580+
check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r"
572581
'
573582
# "/~" -> "~" conversion
574583
test_expect_success "fetch-pack --diag-url $p://$h/~$r" '
575-
check_prot_host_path $p://$h/~$r $pp "$h" "~$r"
584+
check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r"
585+
'
586+
done
587+
for h in host User@host User@[::1]
588+
do
589+
test_expect_success "fetch-pack --diag-url $p://$h:22/$r" '
590+
check_prot_host_port_path $p://$h:22/$r $p "$h" 22 "/$r"
576591
'
577592
done
578593
done
@@ -603,11 +618,11 @@ do
603618
for h in host [::1]
604619
do
605620
test_expect_success "fetch-pack --diag-url $h:$r" '
606-
check_prot_path $h:$r $p "$r"
621+
check_prot_host_port_path $h:$r $p "$h" NONE "$r"
607622
'
608623
# Do "/~" -> "~" conversion
609624
test_expect_success "fetch-pack --diag-url $h:/~$r" '
610-
check_prot_host_path $h:/~$r $p "$h" "~$r"
625+
check_prot_host_port_path $h:/~$r $p "$h" NONE "~$r"
611626
'
612627
done
613628
done

t/t5601-clone.sh

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,17 @@ expect_ssh () {
301301
(cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output)
302302
' &&
303303
{
304-
case "$1" in
305-
none)
304+
case "$#" in
305+
1)
306306
;;
307-
*)
307+
2)
308308
echo "ssh: $1 git-upload-pack '$2'"
309+
;;
310+
3)
311+
echo "ssh: $1 $2 git-upload-pack '$3'"
312+
;;
313+
*)
314+
echo "ssh: $1 $2 git-upload-pack '$3' $4"
309315
esac
310316
} >"$TRASH_DIRECTORY/ssh-expect" &&
311317
(cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
@@ -326,7 +332,7 @@ test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' '
326332

327333
test_expect_success 'bracketed hostnames are still ssh' '
328334
git clone "[myhost:123]:src" ssh-bracket-clone &&
329-
expect_ssh myhost:123 src
335+
expect_ssh myhost '-p 123' src
330336
'
331337

332338
counter=0
@@ -336,7 +342,8 @@ counter=0
336342
test_clone_url () {
337343
counter=$(($counter + 1))
338344
test_might_fail git clone "$1" tmp$counter &&
339-
expect_ssh "$2" "$3"
345+
shift &&
346+
expect_ssh "$@"
340347
}
341348

342349
test_expect_success !MINGW 'clone c:temp is ssl' '
@@ -359,7 +366,7 @@ done
359366
for repo in rep rep/home/project 123
360367
do
361368
test_expect_success "clone [::1]:$repo" '
362-
test_clone_url [::1]:$repo ::1 $repo
369+
test_clone_url [::1]:$repo ::1 "$repo"
363370
'
364371
done
365372
#home directory
@@ -400,24 +407,40 @@ test_expect_success 'clone ssh://host.xz:22/~repo' '
400407
'
401408

402409
#IPv6
403-
test_expect_success 'clone ssh://[::1]/home/user/repo' '
404-
test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo"
405-
'
410+
for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
411+
do
412+
ehost=$(echo $tuah | tr -d "[]")
413+
test_expect_success "clone ssh://$tuah/home/user/repo" "
414+
test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo
415+
"
416+
done
406417

407418
#IPv6 from home directory
408-
test_expect_success 'clone ssh://[::1]/~repo' '
409-
test_clone_url "ssh://[::1]/~repo" "::1" "~repo"
410-
'
419+
for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
420+
do
421+
euah=$(echo $tuah | tr -d "[]")
422+
test_expect_success "clone ssh://$tuah/~repo" "
423+
test_clone_url ssh://$tuah/~repo $euah '~repo'
424+
"
425+
done
411426

412427
#IPv6 with port number
413-
test_expect_success 'clone ssh://[::1]:22/home/user/repo' '
414-
test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo"
415-
'
428+
for tuah in [::1] user@[::1] [user@::1]
429+
do
430+
euah=$(echo $tuah | tr -d "[]")
431+
test_expect_success "clone ssh://$tuah:22/home/user/repo" "
432+
test_clone_url ssh://$tuah:22/home/user/repo '-p 22' $euah /home/user/repo
433+
"
434+
done
416435

417436
#IPv6 from home directory with port number
418-
test_expect_success 'clone ssh://[::1]:22/~repo' '
419-
test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo"
420-
'
437+
for tuah in [::1] user@[::1] [user@::1]
438+
do
439+
euah=$(echo $tuah | tr -d "[]")
440+
test_expect_success "clone ssh://$tuah:22/~repo" "
441+
test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo'
442+
"
443+
done
421444

422445
test_expect_success 'clone from a repository with two identical branches' '
423446

0 commit comments

Comments
 (0)