Skip to content

Instantly share code, notes, and snippets.

@neocturne
Created January 8, 2015 22:26
Show Gist options
  • Save neocturne/ac3f4532be4059b07698 to your computer and use it in GitHub Desktop.
Save neocturne/ac3f4532be4059b07698 to your computer and use it in GitHub Desktop.
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