Created
January 8, 2015 22:26
-
-
Save neocturne/ac3f4532be4059b07698 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 510ee02f90b5c56d1abeafbbdb9fc7d21d173224 Mon Sep 17 00:00:00 2001 | |
Message-Id: <510ee02f90b5c56d1abeafbbdb9fc7d21d173224.1420755946.git.mschiffer@universe-factory.net> | |
From: Matthias Schiffer <mschiffer@universe-factory.net> | |
Date: Thu, 8 Jan 2015 22:19:36 +0100 | |
Subject: [PATCH] multibind patch | |
--- | |
readconf.c | 8 ++++-- | |
readconf.h | 12 +++++++- | |
ssh.c | 3 +- | |
ssh_config | 5 ++++ | |
ssh_config.5 | 7 +++-- | |
sshconnect.c | 89 +++++++++++++++++++++++++++++++++++------------------------- | |
6 files changed, 80 insertions(+), 44 deletions(-) | |
diff --git a/readconf.c b/readconf.c | |
index 7948ce1..95f9289 100644 | |
--- a/readconf.c | |
+++ b/readconf.c | |
@@ -1001,8 +1001,10 @@ parse_char_array: | |
goto parse_string; | |
case oBindAddress: | |
- charptr = &options->bind_address; | |
- goto parse_string; | |
+ cpptr = (char**)&options->bind_addresses; | |
+ uintptr = &options->num_bind_address; | |
+ max_entries = SSH_MAX_BIND_ADDRESSES; | |
+ goto parse_char_array; | |
case oPKCS11Provider: | |
charptr = &options->pkcs11_provider; | |
@@ -1576,7 +1578,7 @@ initialize_options(Options * options) | |
options->clear_forwardings = -1; | |
options->log_level = SYSLOG_LEVEL_NOT_SET; | |
options->preferred_authentications = NULL; | |
- options->bind_address = NULL; | |
+ options->num_bind_address = 0; | |
options->pkcs11_provider = NULL; | |
options->enable_ssh_keysign = - 1; | |
options->no_host_authentication_for_localhost = - 1; | |
diff --git a/readconf.h b/readconf.h | |
index 0b9cb77..9299c4b 100644 | |
--- a/readconf.h | |
+++ b/readconf.h | |
@@ -27,6 +27,11 @@ struct allowed_cname { | |
char *source_list; | |
char *target_list; | |
}; | |
+#define SSH_MAX_BIND_ADDRESSES 8 /* 16 addresses, should be enough */ | |
+ | |
+#define SSH_BIND_ADDRESS_ANY "any" /* any address mark, used in | |
+ * configuration file */ | |
+#define SSH_BIND_ADDRESS_ANYlen strlen(SSH_BIND_ADDRESS_ANY) | |
typedef struct { | |
int forward_agent; /* Forward authentication agent. */ | |
@@ -86,7 +91,12 @@ typedef struct { | |
u_int num_user_hostfiles; /* Path for $HOME/.ssh/known_hosts */ | |
char *user_hostfiles[SSH_MAX_HOSTS_FILES]; | |
char *preferred_authentications; | |
- char *bind_address; /* local socket address for connection to sshd */ | |
+ | |
+ char *bind_addresses[SSH_MAX_BIND_ADDRESSES]; /* local socket | |
+ * address list for connection to sshd, main reason for this is ipv4 and | |
+ * ipv6 only hosts, when using global host match */ | |
+ u_int num_bind_address; /* count of bind_addresses */ | |
+ | |
char *pkcs11_provider; /* PKCS#11 provider */ | |
int verify_host_key_dns; /* Verify host key using DNS */ | |
diff --git a/ssh.c b/ssh.c | |
index 26e9681..be59241 100644 | |
--- a/ssh.c | |
+++ b/ssh.c | |
@@ -803,7 +803,8 @@ main(int ac, char **av) | |
options.control_path = xstrdup(optarg); | |
break; | |
case 'b': | |
- options.bind_address = optarg; | |
+ options.bind_addresses[0] = optarg; | |
+ options.num_bind_address = 1; | |
break; | |
case 'F': | |
config = optarg; | |
diff --git a/ssh_config b/ssh_config | |
index 03a228f..c1b653b 100644 | |
--- a/ssh_config | |
+++ b/ssh_config | |
@@ -46,3 +46,8 @@ | |
# VisualHostKey no | |
# ProxyCommand ssh -q -W %h:%p gateway.example.com | |
# RekeyLimit 1G 1h | |
+ | |
+# --Example of BindAddress | |
+# BindAddress 192.168.0.1 3004:aaaa::beef any | |
+# This means, that ssh tries 192.168.0.1 if fail to bind, next address willbe 3004:aaaa::beef and if it fails, | |
+# uses default bind strategy, bind on any address | |
diff --git a/ssh_config.5 b/ssh_config.5 | |
index f9ede7a..f138d17 100644 | |
--- a/ssh_config.5 | |
+++ b/ssh_config.5 | |
@@ -214,8 +214,11 @@ or | |
The default is | |
.Dq no . | |
.It Cm BindAddress | |
-Use the specified address on the local machine as the source address of | |
-the connection. | |
+Use the specified address (or addresses seperated by space ) on the | |
+local machine as the source address of | |
+the connection. This list can be interrupted with | |
+.Dq any | |
+address. | |
Only useful on systems with more than one address. | |
Note that this option does not work if | |
.Cm UsePrivilegedPort | |
diff --git a/sshconnect.c b/sshconnect.c | |
index ac09eae..5ba4959 100644 | |
--- a/sshconnect.c | |
+++ b/sshconnect.c | |
@@ -280,49 +280,64 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |
fcntl(sock, F_SETFD, FD_CLOEXEC); | |
/* Bind the socket to an alternative local IP address */ | |
- if (options.bind_address == NULL && !privileged) | |
+ if (options.num_bind_address == 0 && !privileged) | |
return sock; | |
- if (options.bind_address) { | |
- memset(&hints, 0, sizeof(hints)); | |
- hints.ai_family = ai->ai_family; | |
- hints.ai_socktype = ai->ai_socktype; | |
- hints.ai_protocol = ai->ai_protocol; | |
- hints.ai_flags = AI_PASSIVE; | |
- gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); | |
- if (gaierr) { | |
- error("getaddrinfo: %s: %s", options.bind_address, | |
- ssh_gai_strerror(gaierr)); | |
- close(sock); | |
- return -1; | |
+ verbose("Trying %d addresses to connect", options.num_bind_address); | |
+ uint i; | |
+ for (i = 0; i < options.num_bind_address || i == 0; i++) { | |
+ if (options.num_bind_address > 0) | |
+ verbose("Trying bind address: %s", options.bind_addresses[i]); | |
+ | |
+ if (options.num_bind_address > 0 && strncmp(options.bind_addresses[i], SSH_BIND_ADDRESS_ANY, SSH_BIND_ADDRESS_ANYlen) != 0) { | |
+ memset(&hints, 0, sizeof(hints)); | |
+ hints.ai_family = ai->ai_family; | |
+ hints.ai_socktype = ai->ai_socktype; | |
+ hints.ai_protocol = ai->ai_protocol; | |
+ hints.ai_flags = AI_PASSIVE; | |
+ gaierr = getaddrinfo(options.bind_addresses[i], NULL, &hints, &res); | |
+ if (gaierr) { | |
+ error("getaddrinfo: %s: %s", options.bind_addresses[i], | |
+ ssh_gai_strerror(gaierr)); | |
+ continue; | |
+ } | |
} | |
- } | |
- /* | |
- * If we are running as root and want to connect to a privileged | |
- * port, bind our own socket to a privileged port. | |
- */ | |
- if (privileged) { | |
- PRIV_START; | |
- r = bindresvport_sa(sock, res ? res->ai_addr : NULL); | |
- PRIV_END; | |
- if (r < 0) { | |
- error("bindresvport_sa: af=%d %s", ai->ai_family, | |
- strerror(errno)); | |
- goto fail; | |
+ else if (!privileged) { | |
+ return sock; | |
} | |
- } else { | |
- if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { | |
- error("bind: %s: %s", options.bind_address, | |
- strerror(errno)); | |
- fail: | |
- close(sock); | |
- freeaddrinfo(res); | |
- return -1; | |
+ | |
+ /* | |
+ * If we are running as root and want to connect to a privileged | |
+ * port, bind our own socket to a privileged port. | |
+ */ | |
+ if (privileged) { | |
+ PRIV_START; | |
+ r = bindresvport_sa(sock, res ? res->ai_addr : NULL); | |
+ PRIV_END; | |
+ if (r < 0) { | |
+ error("bindresvport_sa: af=%d %s", ai->ai_family, | |
+ strerror(errno)); | |
+ goto fail; | |
+ } | |
+ } else { | |
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { | |
+ error("bind: %s: %s", options.bind_addresses[i], | |
+ strerror(errno)); | |
+ fail: | |
+ freeaddrinfo(res); | |
+ res = NULL; | |
+ continue; | |
+ } | |
} | |
+ | |
+ if (res != NULL) | |
+ freeaddrinfo(res); | |
+ | |
+ return sock; | |
} | |
- if (res != NULL) | |
- freeaddrinfo(res); | |
- return sock; | |
+ | |
+ close(sock); | |
+ return -1; | |
} | |
static int | |
-- | |
2.2.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment