Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Wong authored and Junio C Hamano committed Feb 12, 2016
1 parent f3ee9ca commit c915f11
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Documentation/fetch-options.txt
Expand Up @@ -150,3 +150,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::
Use IPv4 addresses only, ignoring IPv6 addresses.

-6::
--ipv6::
Use IPv6 addresses only, ignoring IPv4 addresses.
7 changes: 7 additions & 0 deletions Documentation/git-push.txt
Expand Up @@ -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::
Use IPv4 addresses only, ignoring IPv6 addresses.

-6::
--ipv6::
Use IPv6 addresses only, ignoring IPv4 addresses.

include::urls-remotes.txt[]

Expand Down
6 changes: 6 additions & 0 deletions builtin/clone.c
Expand Up @@ -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 enum transport_family family;
static struct string_list option_config;
static struct string_list option_reference;
static int option_dissociate;
Expand Down Expand Up @@ -92,6 +93,10 @@ 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_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
OPT_END()
};

Expand Down Expand Up @@ -967,6 +972,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->family = family;

path = get_repo_path(remote->url[0], &is_bundle);
is_local = option_local != 0 && path && !is_bundle;
Expand Down
6 changes: 6 additions & 0 deletions builtin/fetch.c
Expand Up @@ -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 enum transport_family family;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
Expand Down Expand Up @@ -124,6 +125,10 @@ 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_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
OPT_END()
};

Expand Down Expand Up @@ -861,6 +866,7 @@ static struct transport *prepare_transport(struct remote *remote)
struct transport *transport;
transport = transport_get(remote, NULL);
transport_set_verbosity(transport, verbosity, progress);
transport->family = family;
if (upload_pack)
set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
if (keep)
Expand Down
6 changes: 6 additions & 0 deletions builtin/push.c
Expand Up @@ -23,6 +23,7 @@ static const char *receivepack;
static int verbosity;
static int progress = -1;
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static enum transport_family family;

static struct push_cas_option cas;

Expand Down Expand Up @@ -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->family = family;

if (receivepack)
transport_set_option(transport,
Expand Down Expand Up @@ -565,6 +567,10 @@ 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_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
OPT_END()
};

Expand Down
8 changes: 8 additions & 0 deletions connect.c
Expand Up @@ -357,6 +357,10 @@ static int git_tcp_connect_sock(char *host, int flags)
port = "<none>";

memset(&hints, 0, sizeof(hints));
if (flags & CONNECT_IPV4)
hints.ai_family = AF_INET;
else if (flags & CONNECT_IPV6)
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

Expand Down Expand Up @@ -783,6 +787,10 @@ struct child_process *git_connect(int fd[2], const char *url,
}

argv_array_push(&conn->args, ssh);
if (flags & CONNECT_IPV4)
argv_array_push(&conn->args, "-4");
else if (flags & CONNECT_IPV6)
argv_array_push(&conn->args, "-6");
if (tortoiseplink)
argv_array_push(&conn->args, "-batch");
if (port) {
Expand Down
2 changes: 2 additions & 0 deletions connect.h
Expand Up @@ -3,6 +3,8 @@

#define CONNECT_VERBOSE (1u << 0)
#define CONNECT_DIAG_URL (1u << 1)
#define CONNECT_IPV4 (1u << 2)
#define CONNECT_IPV6 (1u << 3)
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);
Expand Down
9 changes: 9 additions & 0 deletions http.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions http.h
Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions remote-curl.c
Expand Up @@ -119,6 +119,19 @@ static int set_option(const char *name, const char *value)
else
return -1;
return 0;

#if LIBCURL_VERSION_NUM >= 0x070a08
} else if (!strcmp(name, "family")) {
if (!strcmp(value, "ipv4"))
git_curl_ipresolve = CURL_IPRESOLVE_V4;
else if (!strcmp(value, "ipv6"))
git_curl_ipresolve = CURL_IPRESOLVE_V6;
else if (!strcmp(value, "all"))
git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
else
return -1;
return 0;
#endif /* LIBCURL_VERSION_NUM >= 0x070a08 */
} else {
return 1 /* unsupported */;
}
Expand Down
15 changes: 15 additions & 0 deletions transport-helper.c
Expand Up @@ -320,6 +320,21 @@ static void standard_options(struct transport *t)
if (n >= sizeof(buf))
die("impossibly large verbosity value");
set_helper_option(t, "verbosity", buf);

switch (t->family) {
case TRANSPORT_FAMILY_ALL:
/*
* this is already the default,
* do not break old remote helpers by setting "all" here
*/
break;
case TRANSPORT_FAMILY_IPV4:
set_helper_option(t, "family", "ipv4");
break;
case TRANSPORT_FAMILY_IPV6:
set_helper_option(t, "family", "ipv6");
break;
}
}

static int release_helper(struct transport *transport)
Expand Down
6 changes: 6 additions & 0 deletions transport.c
Expand Up @@ -489,6 +489,12 @@ static int connect_setup(struct transport *transport, int for_push)
if (data->conn)
return 0;

switch (transport->family) {
case TRANSPORT_FAMILY_ALL: break;
case TRANSPORT_FAMILY_IPV4: flags |= CONNECT_IPV4; break;
case TRANSPORT_FAMILY_IPV6: flags |= CONNECT_IPV6; break;
}

data->conn = git_connect(data->fd, transport->url,
for_push ? data->options.receivepack :
data->options.uploadpack,
Expand Down
8 changes: 8 additions & 0 deletions transport.h
Expand Up @@ -18,6 +18,12 @@ struct git_transport_options {
struct push_cas_option *cas;
};

enum transport_family {
TRANSPORT_FAMILY_ALL = 0,
TRANSPORT_FAMILY_IPV4,
TRANSPORT_FAMILY_IPV6
};

struct transport {
struct remote *remote;
const char *url;
Expand Down Expand Up @@ -110,6 +116,8 @@ struct transport {
* actually turns out to be smart.
*/
struct git_transport_options *smart_options;

enum transport_family family;
};

#define TRANSPORT_PUSH_ALL 1
Expand Down

0 comments on commit c915f11

Please sign in to comment.