* [PATCH] support -4 and -6 switches for remote operations
@ 2016-01-30 8:40 Eric Wong
0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2016-01-30 8:40 UTC (permalink / raw)
To: spew
From: Eric Wong <normalperson@yhbt.net>
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.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
Documentation/fetch-options.txt | 8 ++++++++
Documentation/git-push.txt | 7 +++++++
builtin/clone.c | 4 ++++
builtin/fetch.c | 4 ++++
builtin/push.c | 4 ++++
connect.c | 8 ++++++++
connect.h | 2 ++
http.c | 9 +++++++++
http.h | 1 +
remote-curl.c | 19 +++++++++++++++++++
transport-helper.c | 7 +++++++
transport.c | 18 ++++++++++++++++++
transport.h | 11 +++++++++++
13 files changed, 102 insertions(+)
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 952dfdf..6ec7dde 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -158,3 +158,11 @@ endif::git-pull[]
by default when it is attached to a terminal, unless -q
is specified. This flag forces progress status even if the
standard error stream is not directed to a terminal.
+
+-4::
+--ipv4::
+ Resolve IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+ Resolve IPv6 addresses only, ignoring IPv4 addresses.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 32482ce..559c166 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -277,6 +277,13 @@ origin +master` to force a push to the `master` branch). See the
default is --verify, giving the hook a chance to prevent the
push. With --no-verify, the hook is bypassed completely.
+-4::
+--ipv4::
+ Resolve IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+ Resolve IPv6 addresses only, ignoring IPv4 addresses.
include::urls-remotes.txt[]
diff --git a/builtin/clone.c b/builtin/clone.c
index a7c8def..0ba376d 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -47,6 +47,7 @@ static const char *real_git_dir;
static char *option_upload_pack = "git-upload-pack";
static int option_verbosity;
static int option_progress = -1;
+static int ipv4, ipv6;
static struct string_list option_config;
static struct string_list option_reference;
static int option_dissociate;
@@ -92,6 +93,8 @@ static struct option builtin_clone_options[] = {
N_("separate git dir from working tree")),
OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
N_("set config inside the new repository")),
+ OPT_BOOL('4', "ipv4", &ipv4, N_("resolve IPv4 addresses only")),
+ OPT_BOOL('6', "ipv6", &ipv6, N_("resolve IPv6 addresses only")),
OPT_END()
};
@@ -970,6 +973,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
transport_set_verbosity(transport, option_verbosity, option_progress);
+ transport_set_family(transport, ipv4, ipv6);
path = get_repo_path(remote->url[0], &is_bundle);
is_local = option_local != 0 && path && !is_bundle;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8e74213..c77af86 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -37,6 +37,7 @@ static int prune = -1; /* unspecified */
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT, unshallow, update_shallow;
+static int ipv4, ipv6;
static int max_children = 1;
static const char *depth;
static const char *upload_pack;
@@ -127,6 +128,8 @@ static struct option builtin_fetch_options[] = {
N_("accept refs that update .git/shallow")),
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
+ OPT_BOOL('4', "ipv4", &ipv4, N_("resolve IPv4 addresses only")),
+ OPT_BOOL('6', "ipv6", &ipv6, N_("resolve IPv6 addresses only")),
OPT_END()
};
@@ -864,6 +867,7 @@ static struct transport *prepare_transport(struct remote *remote)
struct transport *transport;
transport = transport_get(remote, NULL);
transport_set_verbosity(transport, verbosity, progress);
+ transport_set_family(transport, ipv4, ipv6);
if (upload_pack)
set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
if (keep)
diff --git a/builtin/push.c b/builtin/push.c
index 960ffc3..e0e8b40 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -23,6 +23,7 @@ static const char *receivepack;
static int verbosity;
static int progress = -1;
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int ipv4, ipv6;
static struct push_cas_option cas;
@@ -346,6 +347,7 @@ static int push_with_options(struct transport *transport, int flags)
unsigned int reject_reasons;
transport_set_verbosity(transport, verbosity, progress);
+ transport_set_family(transport, ipv4, ipv6);
if (receivepack)
transport_set_option(transport,
@@ -565,6 +567,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
+ OPT_BOOL('4', "ipv4", &ipv4, N_("resolve IPv4 addresses only")),
+ OPT_BOOL('6', "ipv6", &ipv6, N_("resolve IPv6 addresses only")),
OPT_END()
};
diff --git a/connect.c b/connect.c
index 69ac672..e36ff59 100644
--- a/connect.c
+++ b/connect.c
@@ -465,6 +465,10 @@ static int git_tcp_connect_sock(char *host, int flags)
port = "<none>";
memset(&hints, 0, sizeof(hints));
+ if (flags & CONNECT_IPV4ONLY)
+ hints.ai_family = AF_INET;
+ else if (flags & CONNECT_IPV6ONLY)
+ hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@@ -900,6 +904,10 @@ struct child_process *git_connect(int fd[2], const char *url,
}
argv_array_push(&conn->args, ssh);
+ if (flags & CONNECT_IPV4ONLY)
+ argv_array_push(&conn->args, "-4");
+ else if (flags & CONNECT_IPV6ONLY)
+ argv_array_push(&conn->args, "-6");
if (tortoiseplink)
argv_array_push(&conn->args, "-batch");
if (port) {
diff --git a/connect.h b/connect.h
index 72c175c..5b2fdf9 100644
--- a/connect.h
+++ b/connect.h
@@ -4,6 +4,8 @@
#define CONNECT_VERBOSE (1u << 0)
#define CONNECT_DIAG_URL (1u << 1)
#define CONNECT_PROGRESS (1u << 2)
+#define CONNECT_IPV4ONLY (1u << 3)
+#define CONNECT_IPV6ONLY (1u << 4)
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
extern int finish_connect(struct child_process *conn);
extern int git_connection_is_socket(struct child_process *conn);
diff --git a/http.c b/http.c
index 0da9e66..67e7bc2 100644
--- a/http.c
+++ b/http.c
@@ -11,6 +11,11 @@
#include "gettext.h"
#include "transport.h"
+#if LIBCURL_VERSION_NUM >= 0x070a08
+long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
+#else
+long int git_curl_ipresolve;
+#endif
int active_requests;
int http_is_verbose;
size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -692,6 +697,10 @@ struct active_request_slot *get_active_slot(void)
curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
+
+#if LIBCURL_VERSION_NUM >= 0x070a08
+ curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
+#endif
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
#endif
diff --git a/http.h b/http.h
index 4f97b60..fa45c2b 100644
--- a/http.h
+++ b/http.h
@@ -106,6 +106,7 @@ extern void http_init(struct remote *remote, const char *url,
int proactive_auth);
extern void http_cleanup(void);
+extern long int git_curl_ipresolve;
extern int active_requests;
extern int http_is_verbose;
extern size_t http_post_buffer;
diff --git a/remote-curl.c b/remote-curl.c
index f404faf..1f87095 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -119,6 +119,25 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;
+
+#if LIBCURL_VERSION_NUM >= 0x070a08
+ } else if (!strcmp(name, "ipv4")) {
+ if (!strcmp(value, "true"))
+ git_curl_ipresolve = CURL_IPRESOLVE_V4;
+ else if (!strcmp(value, "false"))
+ git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
+ else
+ return -1;
+ return 0;
+ } else if (!strcmp(name, "ipv6")) {
+ if (!strcmp(value, "true"))
+ git_curl_ipresolve = CURL_IPRESOLVE_V6;
+ else if (!strcmp(value, "false"))
+ git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
+ else
+ return -1;
+ return 0;
+#endif /* LIBCURL_VERSION_NUM >= 0x070a08 */
} else {
return 1 /* unsupported */;
}
diff --git a/transport-helper.c b/transport-helper.c
index 0eb3cf0..dd27068 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -257,6 +257,8 @@ static const char *boolean_options[] = {
TRANS_OPT_THIN,
TRANS_OPT_KEEP,
TRANS_OPT_FOLLOWTAGS,
+ TRANS_OPT_IPV4,
+ TRANS_OPT_IPV6,
};
static int set_helper_option(struct transport *transport,
@@ -320,6 +322,11 @@ static void standard_options(struct transport *t)
if (n >= sizeof(buf))
die("impossibly large verbosity value");
set_helper_option(t, "verbosity", buf);
+
+ if (t->ipv4)
+ set_helper_option(t, "ipv4", "true");
+ if (t->ipv6)
+ set_helper_option(t, "ipv6", "true");
}
static int release_helper(struct transport *transport)
diff --git a/transport.c b/transport.c
index fb71fb2..3766c24 100644
--- a/transport.c
+++ b/transport.c
@@ -491,6 +491,10 @@ static int connect_setup(struct transport *transport, int for_push)
if (transport->progress)
flags |= CONNECT_PROGRESS;
+ if (transport->ipv4)
+ flags |= CONNECT_IPV4ONLY;
+ if (transport->ipv6)
+ flags |= CONNECT_IPV6ONLY;
data->conn = git_connect(data->fd, transport->url,
for_push ? data->options.receivepack :
@@ -1089,6 +1093,20 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
transport->progress = verbosity >= 0 && isatty(2);
}
+void transport_set_family(struct transport *transport, int ipv4, int ipv6)
+{
+ if (ipv4 && ipv6)
+ die("-4/--ipv4 and -6/--ipv6 are incompatible");
+ if (ipv4) {
+ transport->ipv4 = 1;
+ transport_set_option(transport, TRANS_OPT_IPV4, "true");
+ }
+ if (ipv6) {
+ transport->ipv6 = 1;
+ transport_set_option(transport, TRANS_OPT_IPV6, "true");
+ }
+}
+
static void die_with_unpushed_submodules(struct string_list *needs_pushing)
{
int i;
diff --git a/transport.h b/transport.h
index 8ebaaf2..f9f3c00 100644
--- a/transport.h
+++ b/transport.h
@@ -104,6 +104,10 @@ struct transport {
* in transport_set_verbosity().
**/
unsigned progress : 1;
+
+ /* mutually exclusive, set by transport_set_family */
+ unsigned ipv4 : 1;
+ unsigned ipv6 : 1;
/*
* If transport is at least potentially smart, this points to
* git_transport_options structure to use in case transport
@@ -180,6 +184,12 @@ int transport_restrict_protocols(void);
/* Send push certificates */
#define TRANS_OPT_PUSH_CERT "pushcert"
+/* Limit to IPv4 only */
+#define TRANS_OPT_IPV4 "ipv4"
+
+/* Limit to IPv6 only */
+#define TRANS_OPT_IPV6 "ipv6"
+
/**
* Returns 0 if the option was used, non-zero otherwise. Prints a
* message to stderr if the option is not used.
@@ -188,6 +198,7 @@ int transport_set_option(struct transport *transport, const char *name,
const char *value);
void transport_set_verbosity(struct transport *transport, int verbosity,
int force_progress);
+void transport_set_family(struct transport *transport, int ipv4, int ipv6);
#define REJECT_NON_FF_HEAD 0x01
#define REJECT_NON_FF_OTHER 0x02
--
EW
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2016-01-30 8:40 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-30 8:40 [PATCH] support -4 and -6 switches for remote operations Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).