connect & http: support -4 and -6 switches for remote operations
Sometimes it is necessary to force IPv4-only or IPv6-only operation on networks where name lookups may return a non-routable address and stall remote operations. The ssh(1) command has an equivalent switches which we may pass when we run them. There may be old ssh(1) implementations out there which do not support these switches; they should report the appropriate error in that case. rsync support is untouched for now since it is deprecated and scheduled to be removed. Signed-off-by: Eric Wong <normalperson@yhbt.net> Reviewed-by: Torsten Bögershausen <tboegi@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eric Wong committed
Feb 3, 2016 at 04:09 UTC
c915f11eb4922e154e29cf62d3b549d65c06a170
13 files changed
+95
Documentation/fetch-options.txt
+8
@@ -150,3 +150,11 @@ endif::git-pull[]
150
by default when it is attached to a terminal, unless -q
151
is specified. This flag forces progress status even if the
152
standard error stream is not directed to a terminal.
153
+
154
+-4::
155
+--ipv4::
156
+ Use IPv4 addresses only, ignoring IPv6 addresses.
157
+
158
+-6::
159
+--ipv6::
160
+ Use IPv6 addresses only, ignoring IPv4 addresses.
Documentation/git-push.txt
+7
@@ -277,6 +277,13 @@ origin +master` to force a push to the `master` branch). See the
277
default is --verify, giving the hook a chance to prevent the
278
push. With --no-verify, the hook is bypassed completely.
279
280
+-4::
281
+--ipv4::
282
+ Use IPv4 addresses only, ignoring IPv6 addresses.
283
+
284
+-6::
285
+--ipv6::
286
+ Use IPv6 addresses only, ignoring IPv4 addresses.
287
288
include::urls-remotes.txt[]
289
builtin/clone.c
+6
@@ -47,6 +47,7 @@ static const char *real_git_dir;
47
static char *option_upload_pack = "git-upload-pack";
48
static int option_verbosity;
49
static int option_progress = -1;
50
+static enum transport_family family;
51
static struct string_list option_config;
52
static struct string_list option_reference;
53
static int option_dissociate;
@@ -92,6 +93,10 @@ static struct option builtin_clone_options[] = {
93
N_("separate git dir from working tree")),
94
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
95
N_("set config inside the new repository")),
96
+ OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
97
+ TRANSPORT_FAMILY_IPV4),
98
+ OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
99
+ TRANSPORT_FAMILY_IPV6),
100
OPT_END()
101
};
102
@@ -967,6 +972,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
972
remote = remote_get(option_origin);
973
transport = transport_get(remote, remote->url[0]);
974
transport_set_verbosity(transport, option_verbosity, option_progress);
975
+ transport->family = family;
976
977
path = get_repo_path(remote->url[0], &is_bundle);
978
is_local = option_local != 0 && path && !is_bundle;
builtin/fetch.c
+6
@@ -37,6 +37,7 @@ static int prune = -1; /* unspecified */
37
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
38
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
39
static int tags = TAGS_DEFAULT, unshallow, update_shallow;
40
+static enum transport_family family;
41
static const char *depth;
42
static const char *upload_pack;
43
static struct strbuf default_rla = STRBUF_INIT;
@@ -124,6 +125,10 @@ static struct option builtin_fetch_options[] = {
125
N_("accept refs that update .git/shallow")),
126
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
127
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
128
+ OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
129
+ TRANSPORT_FAMILY_IPV4),
130
+ OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
131
+ TRANSPORT_FAMILY_IPV6),
132
OPT_END()
133
};
134
@@ -861,6 +866,7 @@ static struct transport *prepare_transport(struct remote *remote)
866
struct transport *transport;
867
transport = transport_get(remote, NULL);
868
transport_set_verbosity(transport, verbosity, progress);
869
+ transport->family = family;
870
if (upload_pack)
871
set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
872
if (keep)
builtin/push.c
+6
@@ -23,6 +23,7 @@ static const char *receivepack;
23
static int verbosity;
24
static int progress = -1;
25
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
26
+static enum transport_family family;
27
28
static struct push_cas_option cas;
29
@@ -346,6 +347,7 @@ static int push_with_options(struct transport *transport, int flags)
347
unsigned int reject_reasons;
348
349
transport_set_verbosity(transport, verbosity, progress);
350
+ transport->family = family;
351
352
if (receivepack)
353
transport_set_option(transport,
@@ -565,6 +567,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
567
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
568
PARSE_OPT_OPTARG, option_parse_push_signed },
569
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
570
+ OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
571
+ TRANSPORT_FAMILY_IPV4),
572
+ OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
573
+ TRANSPORT_FAMILY_IPV6),
574
OPT_END()
575
};
576
connect.c
+8
@@ -357,6 +357,10 @@ static int git_tcp_connect_sock(char *host, int flags)
357
port = "<none>";
358
359
memset(&hints, 0, sizeof(hints));
360
+ if (flags & CONNECT_IPV4)
361
+ hints.ai_family = AF_INET;
362
+ else if (flags & CONNECT_IPV6)
363
+ hints.ai_family = AF_INET6;
364
hints.ai_socktype = SOCK_STREAM;
365
hints.ai_protocol = IPPROTO_TCP;
366
@@ -783,6 +787,10 @@ struct child_process *git_connect(int fd[2], const char *url,
787
}
788
789
argv_array_push(&conn->args, ssh);
790
+ if (flags & CONNECT_IPV4)
791
+ argv_array_push(&conn->args, "-4");
792
+ else if (flags & CONNECT_IPV6)
793
+ argv_array_push(&conn->args, "-6");
794
if (tortoiseplink)
795
argv_array_push(&conn->args, "-batch");
796
if (port) {
connect.h
+2
@@ -3,6 +3,8 @@
3
4
#define CONNECT_VERBOSE (1u << 0)
5
#define CONNECT_DIAG_URL (1u << 1)
6
+#define CONNECT_IPV4 (1u << 2)
7
+#define CONNECT_IPV6 (1u << 3)
8
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
9
extern int finish_connect(struct child_process *conn);
10
extern int git_connection_is_socket(struct child_process *conn);
http.c
+9
@@ -11,6 +11,11 @@
11
#include "gettext.h"
12
#include "transport.h"
13
14
+#if LIBCURL_VERSION_NUM >= 0x070a08
15
+long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
16
+#else
17
+long int git_curl_ipresolve;
18
+#endif
19
int active_requests;
20
int http_is_verbose;
21
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -692,6 +697,10 @@ struct active_request_slot *get_active_slot(void)
697
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
698
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
699
curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
700
+
701
+#if LIBCURL_VERSION_NUM >= 0x070a08
702
+ curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
703
+#endif
704
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
705
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
706
#endif
http.h
+1
@@ -106,6 +106,7 @@ extern void http_init(struct remote *remote, const char *url,
106
int proactive_auth);
107
extern void http_cleanup(void);
108
109
+extern long int git_curl_ipresolve;
110
extern int active_requests;
111
extern int http_is_verbose;
112
extern size_t http_post_buffer;
remote-curl.c
+13
@@ -119,6 +119,19 @@ static int set_option(const char *name, const char *value)
119
else
120
return -1;
121
return 0;
122
+
123
+#if LIBCURL_VERSION_NUM >= 0x070a08
124
+ } else if (!strcmp(name, "family")) {
125
+ if (!strcmp(value, "ipv4"))
126
+ git_curl_ipresolve = CURL_IPRESOLVE_V4;
127
+ else if (!strcmp(value, "ipv6"))
128
+ git_curl_ipresolve = CURL_IPRESOLVE_V6;
129
+ else if (!strcmp(value, "all"))
130
+ git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
131
+ else
132
+ return -1;
133
+ return 0;
134
+#endif /* LIBCURL_VERSION_NUM >= 0x070a08 */
135
} else {
136
return 1 /* unsupported */;
137
}
transport-helper.c
+15
@@ -320,6 +320,21 @@ static void standard_options(struct transport *t)
320
if (n >= sizeof(buf))
321
die("impossibly large verbosity value");
322
set_helper_option(t, "verbosity", buf);
323
+
324
+ switch (t->family) {
325
+ case TRANSPORT_FAMILY_ALL:
326
+ /*
327
+ * this is already the default,
328
+ * do not break old remote helpers by setting "all" here
329
+ */
330
+ break;
331
+ case TRANSPORT_FAMILY_IPV4:
332
+ set_helper_option(t, "family", "ipv4");
333
+ break;
334
+ case TRANSPORT_FAMILY_IPV6:
335
+ set_helper_option(t, "family", "ipv6");
336
+ break;
337
+ }
338
}
339
340
static int release_helper(struct transport *transport)
transport.c
+6
@@ -489,6 +489,12 @@ static int connect_setup(struct transport *transport, int for_push)
489
if (data->conn)
490
return 0;
491
492
+ switch (transport->family) {
493
+ case TRANSPORT_FAMILY_ALL: break;
494
+ case TRANSPORT_FAMILY_IPV4: flags |= CONNECT_IPV4; break;
495
+ case TRANSPORT_FAMILY_IPV6: flags |= CONNECT_IPV6; break;
496
+ }
497
+
498
data->conn = git_connect(data->fd, transport->url,
499
for_push ? data->options.receivepack :
500
data->options.uploadpack,
transport.h
+8
@@ -18,6 +18,12 @@ struct git_transport_options {
18
struct push_cas_option *cas;
19
};
20
21
+enum transport_family {
22
+ TRANSPORT_FAMILY_ALL = 0,
23
+ TRANSPORT_FAMILY_IPV4,
24
+ TRANSPORT_FAMILY_IPV6
25
+};
26
+
27
struct transport {
28
struct remote *remote;
29
const char *url;
@@ -110,6 +116,8 @@ struct transport {
116
* actually turns out to be smart.
117
*/
118
struct git_transport_options *smart_options;
119
+
120
+ enum transport_family family;
121
};
122
123
#define TRANSPORT_PUSH_ALL 1