Bugzilla – Attachment 3075 Details for
Bug 2784
Add native support for routing domains / VRF
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
ListenAddress rdomain qualifier
0001-rdomain-option-on-ListenAddress.patch (text/plain), 17.46 KB, created by
Damien Miller
on 2017-10-23 12:27:56 AEDT
(
hide
)
Description:
ListenAddress rdomain qualifier
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2017-10-23 12:27:56 AEDT
Size:
17.46 KB
patch
obsolete
>From 74ded9883856de6a8477de3c5542e22ae3d8e337 Mon Sep 17 00:00:00 2001 >From: Damien Miller <djm@mindrot.org> >Date: Fri, 20 Oct 2017 15:14:07 +1100 >Subject: [PATCH 1/3] rdomain option on ListenAddress > >--- > channels.c | 17 +---- > misc.c | 38 ++++++++++ > misc.h | 2 + > servconf.c | 223 +++++++++++++++++++++++++++++++++++++++++----------------- > servconf.h | 23 +++++- > sshd.c | 43 +++++++---- > sshd_config.5 | 25 +++++-- > 7 files changed, 271 insertions(+), 100 deletions(-) > >diff --git a/channels.c b/channels.c >index bc4798e..17c1b73 100644 >--- a/channels.c >+++ b/channels.c >@@ -1658,19 +1658,6 @@ port_open_helper(struct ssh *ssh, Channel *c, char *rtype) > free(local_ipaddr); > } > >-static void >-channel_set_reuseaddr(int fd) >-{ >- int on = 1; >- >- /* >- * Set socket options. >- * Allow local port reuse in TIME_WAIT. >- */ >- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) >- error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); >-} >- > void > channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time) > { >@@ -3337,7 +3324,7 @@ channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, > continue; > } > >- channel_set_reuseaddr(sock); >+ set_reuseaddr(sock); > > debug("Local forwarding listening on %s port %s.", > ntop, strport); >@@ -4389,7 +4376,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, > freeaddrinfo(aitop); > return -1; > } >- channel_set_reuseaddr(sock); >+ set_reuseaddr(sock); > if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { > debug2("%s: bind port %d: %.100s", __func__, > port, strerror(errno)); >diff --git a/misc.c b/misc.c >index 672701d..14b4735 100644 >--- a/misc.c >+++ b/misc.c >@@ -155,6 +155,44 @@ set_nodelay(int fd) > error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); > } > >+/* Allow local port reuse in TIME_WAIT */ >+int >+set_reuseaddr(int fd) >+{ >+ int on = 1; >+ >+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { >+ error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); >+ return -1; >+ } >+ return 0; >+} >+ >+/* Set routing table */ >+int >+set_rdomain(int fd, const char *name) >+{ >+ int rtable; >+ const char *errstr; >+ >+ if (name == NULL) >+ return 0; /* default table */ >+ >+ rtable = (int)strtonum(name, 0, 255, &errstr); >+ if (errstr != NULL) { >+ /* Shouldn't happen */ >+ error("Invalid routing domain \"%s\": %s", name, errstr); >+ return -1; >+ } >+ if (setsockopt(fd, SOL_SOCKET, SO_RTABLE, >+ &rtable, sizeof(rtable)) == -1) { >+ error("Failed to set routing domain %d on fd %d: %s", >+ rtable, fd, strerror(errno)); >+ return -1; >+ } >+ return 0; >+} >+ > /* Characters considered whitespace in strsep calls. */ > #define WHITESPACE " \t\r\n" > #define QUOTE "\"" >diff --git a/misc.h b/misc.h >index f10347b..14a59c8 100644 >--- a/misc.h >+++ b/misc.h >@@ -48,6 +48,8 @@ char *strdelim(char **); > int set_nonblock(int); > int unset_nonblock(int); > void set_nodelay(int); >+int set_reuseaddr(int); >+int set_rdomain(int, const char *); > int a2port(const char *); > int a2tun(const char *, int *); > char *put_host_port(const char *, u_short); >diff --git a/servconf.c b/servconf.c >index c37563a..82d6b5a 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -14,9 +14,11 @@ > #include <sys/types.h> > #include <sys/socket.h> > #include <sys/queue.h> >+#include <sys/sysctl.h> > > #include <netinet/in.h> > #include <netinet/ip.h> >+#include <net/route.h> > > #include <ctype.h> > #include <netdb.h> >@@ -53,8 +55,10 @@ > #include "myproposal.h" > #include "digest.h" > >-static void add_listen_addr(ServerOptions *, char *, int); >-static void add_one_listen_addr(ServerOptions *, char *, int); >+static void add_listen_addr(ServerOptions *, const char *, >+ const char *, int); >+static void add_one_listen_addr(ServerOptions *, const char *, >+ const char *, int); > > /* Use of privilege separation or not */ > extern int use_privsep; >@@ -71,6 +75,7 @@ initialize_server_options(ServerOptions *options) > options->queued_listen_addrs = NULL; > options->num_queued_listens = 0; > options->listen_addrs = NULL; >+ options->num_listen_addrs = 0; > options->address_family = -1; > options->num_host_key_files = 0; > options->num_host_cert_files = 0; >@@ -235,7 +240,7 @@ fill_default_server_options(ServerOptions *options) > if (options->address_family == -1) > options->address_family = AF_UNSPEC; > if (options->listen_addrs == NULL) >- add_listen_addr(options, NULL, 0); >+ add_listen_addr(options, NULL, NULL, 0); > if (options->pid_file == NULL) > options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); > if (options->login_grace_time == -1) >@@ -612,23 +617,51 @@ derelativise_path(const char *path) > } > > static void >-add_listen_addr(ServerOptions *options, char *addr, int port) >+add_listen_addr(ServerOptions *options, const char *addr, >+ const char *rdomain, int port) > { > u_int i; > >- if (port == 0) >- for (i = 0; i < options->num_ports; i++) >- add_one_listen_addr(options, addr, options->ports[i]); >- else >- add_one_listen_addr(options, addr, port); >+ if (port > 0) >+ add_one_listen_addr(options, addr, rdomain, port); >+ else { >+ for (i = 0; i < options->num_ports; i++) { >+ add_one_listen_addr(options, addr, rdomain, >+ options->ports[i]); >+ } >+ } > } > > static void >-add_one_listen_addr(ServerOptions *options, char *addr, int port) >+add_one_listen_addr(ServerOptions *options, const char *addr, >+ const char *rdomain, int port) > { > struct addrinfo hints, *ai, *aitop; > char strport[NI_MAXSERV]; > int gaierr; >+ u_int i; >+ >+ /* Find listen_addrs entry for this rdomain */ >+ for (i = 0; i < options->num_listen_addrs; i++) { >+ if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL) >+ break; >+ if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL) >+ continue; >+ if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0) >+ break; >+ } >+ if (i >= options->num_listen_addrs) { >+ /* No entry for this rdomain; allocate one */ >+ if (i >= INT_MAX) >+ fatal("%s: too many listen addresses", __func__); >+ options->listen_addrs = xrecallocarray(options->listen_addrs, >+ options->num_listen_addrs, options->num_listen_addrs + 1, >+ sizeof(*options->listen_addrs)); >+ i = options->num_listen_addrs++; >+ if (rdomain != NULL) >+ options->listen_addrs[i].rdomain = xstrdup(rdomain); >+ } >+ /* options->listen_addrs[i] points to the addresses for this rdomain */ > > memset(&hints, 0, sizeof(hints)); > hints.ai_family = options->address_family; >@@ -641,8 +674,37 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) > ssh_gai_strerror(gaierr)); > for (ai = aitop; ai->ai_next; ai = ai->ai_next) > ; >- ai->ai_next = options->listen_addrs; >- options->listen_addrs = aitop; >+ ai->ai_next = options->listen_addrs[i].addrs; >+ options->listen_addrs[i].addrs = aitop; >+} >+ >+/* Returns nonzero if the routing domain name is valid */ >+static int >+valid_rdomain(const char *name) >+{ >+ const char *errstr; >+ long long num; >+ struct rt_tableinfo info; >+ int mib[6]; >+ size_t miblen = sizeof(mib); >+ >+ if (name == NULL) >+ return 1; >+ >+ num = strtonum(name, 0, 255, &errstr); >+ if (errstr != NULL) >+ return 0; >+ >+ /* Check whether the table actually exists */ >+ memset(mib, 0, sizeof(mib)); >+ mib[0] = CTL_NET; >+ mib[1] = PF_ROUTE; >+ mib[4] = NET_RT_TABLE; >+ mib[5] = (int)num; >+ if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1) >+ return 0; >+ >+ return 1; > } > > /* >@@ -650,18 +712,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port) > * and AddressFamily options. > */ > static void >-queue_listen_addr(ServerOptions *options, char *addr, int port) >+queue_listen_addr(ServerOptions *options, const char *addr, >+ const char *rdomain, int port) > { >- options->queued_listen_addrs = xreallocarray( >- options->queued_listen_addrs, options->num_queued_listens + 1, >- sizeof(addr)); >- options->queued_listen_ports = xreallocarray( >- options->queued_listen_ports, options->num_queued_listens + 1, >- sizeof(port)); >- options->queued_listen_addrs[options->num_queued_listens] = >- xstrdup(addr); >- options->queued_listen_ports[options->num_queued_listens] = port; >- options->num_queued_listens++; >+ struct queued_listenaddr *qla; >+ >+ options->queued_listen_addrs = xrecallocarray( >+ options->queued_listen_addrs, >+ options->num_queued_listens, options->num_queued_listens + 1, >+ sizeof(*options->queued_listen_addrs)); >+ qla = &options->queued_listen_addrs[options->num_queued_listens++]; >+ qla->addr = xstrdup(addr); >+ qla->port = port; >+ qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain); > } > > /* >@@ -671,6 +734,7 @@ static void > process_queued_listen_addrs(ServerOptions *options) > { > u_int i; >+ struct queued_listenaddr *qla; > > if (options->num_ports == 0) > options->ports[options->num_ports++] = SSH_DEFAULT_PORT; >@@ -678,15 +742,13 @@ process_queued_listen_addrs(ServerOptions *options) > options->address_family = AF_UNSPEC; > > for (i = 0; i < options->num_queued_listens; i++) { >- add_listen_addr(options, options->queued_listen_addrs[i], >- options->queued_listen_ports[i]); >- free(options->queued_listen_addrs[i]); >- options->queued_listen_addrs[i] = NULL; >+ qla = &options->queued_listen_addrs[i]; >+ add_listen_addr(options, qla->addr, qla->rdomain, qla->port); >+ free(qla->addr); >+ free(qla->rdomain); > } > free(options->queued_listen_addrs); > options->queued_listen_addrs = NULL; >- free(options->queued_listen_ports); >- options->queued_listen_ports = NULL; > options->num_queued_listens = 0; > } > >@@ -1075,20 +1137,33 @@ process_server_config_line(ServerOptions *options, char *line, > /* check for bare IPv6 address: no "[]" and 2 or more ":" */ > if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL > && strchr(p+1, ':') != NULL) { >- queue_listen_addr(options, arg, 0); >- break; >- } >- p = hpdelim(&arg); >- if (p == NULL) >- fatal("%s line %d: bad address:port usage", >- filename, linenum); >- p = cleanhostname(p); >- if (arg == NULL) > port = 0; >- else if ((port = a2port(arg)) <= 0) >- fatal("%s line %d: bad port number", filename, linenum); >+ p = arg; >+ } else { >+ p = hpdelim(&arg); >+ if (p == NULL) >+ fatal("%s line %d: bad address:port usage", >+ filename, linenum); >+ p = cleanhostname(p); >+ if (arg == NULL) >+ port = 0; >+ else if ((port = a2port(arg)) <= 0) >+ fatal("%s line %d: bad port number", >+ filename, linenum); >+ } >+ /* Optional routing table */ >+ arg2 = NULL; >+ if ((arg = strdelim(&cp)) != NULL) { >+ if (strcmp(arg, "rdomain") != 0 || >+ (arg2 = strdelim(&cp)) == NULL) >+ fatal("%s line %d: bad ListenAddress syntax", >+ filename, linenum); >+ if (!valid_rdomain(arg2)) >+ fatal("%s line %d: bad routing domain", >+ filename, linenum); >+ } > >- queue_listen_addr(options, p, port); >+ queue_listen_addr(options, p, arg2, port); > > break; > >@@ -2199,45 +2274,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) > printf("\n"); > } > >-void >-dump_config(ServerOptions *o) >+static char * >+format_listen_addrs(struct listenaddr *la) > { >- u_int i; >- int ret; >+ int r; > struct addrinfo *ai; >- char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; >+ char addr[NI_MAXHOST], port[NI_MAXSERV]; > char *laddr1 = xstrdup(""), *laddr2 = NULL; > >- /* these are usually at the top of the config */ >- for (i = 0; i < o->num_ports; i++) >- printf("port %d\n", o->ports[i]); >- dump_cfg_fmtint(sAddressFamily, o->address_family); >- > /* > * ListenAddress must be after Port. add_one_listen_addr pushes > * addresses onto a stack, so to maintain ordering we need to > * print these in reverse order. > */ >- for (ai = o->listen_addrs; ai; ai = ai->ai_next) { >- if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, >+ for (ai = la->addrs; ai; ai = ai->ai_next) { >+ if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, > sizeof(addr), port, sizeof(port), > NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { >- error("getnameinfo failed: %.100s", >- (ret != EAI_SYSTEM) ? gai_strerror(ret) : >- strerror(errno)); >+ error("getnameinfo: %.100s", ssh_gai_strerror(r)); >+ continue; >+ } >+ laddr2 = laddr1; >+ if (ai->ai_family == AF_INET6) { >+ xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s", >+ addr, port, >+ la->rdomain == NULL ? "" : " rdomain ", >+ la->rdomain == NULL ? "" : la->rdomain, >+ laddr2); > } else { >- laddr2 = laddr1; >- if (ai->ai_family == AF_INET6) >- xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", >- addr, port, laddr2); >- else >- xasprintf(&laddr1, "listenaddress %s:%s\n%s", >- addr, port, laddr2); >- free(laddr2); >+ xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s", >+ addr, port, >+ la->rdomain == NULL ? "" : " rdomain ", >+ la->rdomain == NULL ? "" : la->rdomain, >+ laddr2); > } >+ free(laddr2); >+ } >+ return laddr1; >+} >+ >+void >+dump_config(ServerOptions *o) >+{ >+ char *s; >+ u_int i; >+ >+ /* these are usually at the top of the config */ >+ for (i = 0; i < o->num_ports; i++) >+ printf("port %d\n", o->ports[i]); >+ dump_cfg_fmtint(sAddressFamily, o->address_family); >+ >+ for (i = 0; i < o->num_listen_addrs; i++) { >+ s = format_listen_addrs(&o->listen_addrs[i]); >+ printf("%s", s); >+ free(s); > } >- printf("%s", laddr1); >- free(laddr1); > > /* integer arguments */ > dump_cfg_int(sLoginGraceTime, o->login_grace_time); >diff --git a/servconf.h b/servconf.h >index ea381e2..cd8a097 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -51,14 +51,31 @@ > struct ssh; > struct fwd_perm_list; > >+/* >+ * Used to store addresses from ListenAddr directives. These may be >+ * incomplete, as they may specify addresses that need to be merged >+ * with any ports requested by ListenPort. >+ */ >+struct queued_listenaddr { >+ char *addr; >+ int port; /* <=0 if unspecified */ >+ char *rdomain; >+}; >+ >+/* Resolved listen addresses, grouped by optional routing domain */ >+struct listenaddr { >+ char *rdomain; >+ struct addrinfo *addrs; >+}; >+ > typedef struct { > u_int num_ports; > u_int ports_from_cmdline; > int ports[MAX_PORTS]; /* Port number to listen on. */ >+ struct queued_listenaddr *queued_listen_addrs; > u_int num_queued_listens; >- char **queued_listen_addrs; >- int *queued_listen_ports; >- struct addrinfo *listen_addrs; /* Addresses for server to listen. */ >+ struct listenaddr *listen_addrs; >+ u_int num_listen_addrs; > int address_family; /* Address family used by the server. */ > > char **host_key_files; /* Files containing host keys. */ >diff --git a/sshd.c b/sshd.c >index 72e6d87..cc77a1a 100644 >--- a/sshd.c >+++ b/sshd.c >@@ -962,13 +962,13 @@ server_accept_inetd(int *sock_in, int *sock_out) > * Listen for TCP connections > */ > static void >-server_listen(void) >+listen_on_addrs(struct listenaddr *la) > { >- int ret, listen_sock, on = 1; >+ int ret, listen_sock; > struct addrinfo *ai; > char ntop[NI_MAXHOST], strport[NI_MAXSERV]; > >- for (ai = options.listen_addrs; ai; ai = ai->ai_next) { >+ for (ai = la->addrs; ai; ai = ai->ai_next) { > if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) > continue; > if (num_listen_socks >= MAX_LISTEN_SOCKS) >@@ -998,13 +998,13 @@ server_listen(void) > close(listen_sock); > continue; > } >- /* >- * Set socket options. >- * Allow local port reuse in TIME_WAIT. >- */ >- if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, >- &on, sizeof(on)) == -1) >- error("setsockopt SO_REUSEADDR: %s", strerror(errno)); >+ /* Socket options */ >+ set_reuseaddr(listen_sock); >+ if (la->rdomain != NULL && >+ set_rdomain(listen_sock, la->rdomain) == -1) { >+ close(listen_sock); >+ continue; >+ } > > debug("Bind to port %s on %s.", strport, ntop); > >@@ -1022,9 +1022,28 @@ server_listen(void) > if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) > fatal("listen on [%s]:%s: %.100s", > ntop, strport, strerror(errno)); >- logit("Server listening on %s port %s.", ntop, strport); >+ logit("Server listening on %s port %s%s%s.", >+ ntop, strport, >+ la->rdomain == NULL ? "" : " rdomain ", >+ la->rdomain == NULL ? "" : la->rdomain); > } >- freeaddrinfo(options.listen_addrs); >+} >+ >+static void >+server_listen(void) >+{ >+ u_int i; >+ >+ for (i = 0; i < options.num_listen_addrs; i++) { >+ listen_on_addrs(&options.listen_addrs[i]); >+ freeaddrinfo(options.listen_addrs[i].addrs); >+ free(options.listen_addrs[i].rdomain); >+ memset(&options.listen_addrs[i], 0, >+ sizeof(options.listen_addrs[i])); >+ } >+ free(options.listen_addrs); >+ options.listen_addrs = NULL; >+ options.num_listen_addrs = 0; > > if (!num_listen_socks) > fatal("Cannot bind any address."); >diff --git a/sshd_config.5 b/sshd_config.5 >index 418f768..6e5b263 100644 >--- a/sshd_config.5 >+++ b/sshd_config.5 >@@ -910,31 +910,48 @@ The following forms may be used: > .It > .Cm ListenAddress > .Sm off >-.Ar host | Ar IPv4_addr | Ar IPv6_addr >+.Ar hostname | Ar address > .Sm on >+.Oo rdomain Ar domain Oc > .It > .Cm ListenAddress > .Sm off >-.Ar host | Ar IPv4_addr : Ar port >+.Ar hostname : Ar port > .Sm on >+.Oo rdomain Ar domain Oc >+.It >+.Cm ListenAddress >+.Sm off >+.Ar IPv4_address : Ar port >+.Sm on >+.Oo rdomain Ar domain Oc > .It > .Cm ListenAddress > .Sm off > .Oo >-.Ar host | Ar IPv6_addr Oc : Ar port >+.Ar hostname | address Oc : Ar port > .Sm on >+.Oo rdomain Ar domain Oc > .El > .Pp >+The optional >+.Cm rdomain >+qualifier requests >+.Xr sshd 8 >+listen in an explicit routing domain. > If > .Ar port > is not specified, > sshd will listen on the address and all > .Cm Port > options specified. >-The default is to listen on all local addresses. >+The default is to listen on all local addresses on the current default >+routing domain. > Multiple > .Cm ListenAddress > options are permitted. >+For more information on routing domains, see >+.Xr rdomain 4. > .It Cm LoginGraceTime > The server disconnects after this time if the user has not > successfully logged in. >-- >2.14.2 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2784
:
3061
|
3064
|
3070
|
3071
|
3072
| 3075 |
3076
|
3077
|
3078
|
3079
|
3080
|
3081
|
3082