summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels.c19
-rw-r--r--misc.c40
-rw-r--r--misc.h4
-rw-r--r--servconf.c229
-rw-r--r--servconf.h25
-rw-r--r--sshd.c45
-rw-r--r--sshd_config.529
7 files changed, 283 insertions, 108 deletions
diff --git a/channels.c b/channels.c
index 83442be06..07dc9577a 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.375 2017/09/24 13:45:34 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.376 2017/10/25 00:15:35 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1668,19 +1668,6 @@ port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
1668 free(local_ipaddr); 1668 free(local_ipaddr);
1669} 1669}
1670 1670
1671static void
1672channel_set_reuseaddr(int fd)
1673{
1674 int on = 1;
1675
1676 /*
1677 * Set socket options.
1678 * Allow local port reuse in TIME_WAIT.
1679 */
1680 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1681 error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
1682}
1683
1684void 1671void
1685channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time) 1672channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time)
1686{ 1673{
@@ -3368,7 +3355,7 @@ channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type,
3368 continue; 3355 continue;
3369 } 3356 }
3370 3357
3371 channel_set_reuseaddr(sock); 3358 set_reuseaddr(sock);
3372 if (ai->ai_family == AF_INET6) 3359 if (ai->ai_family == AF_INET6)
3373 sock_set_v6only(sock); 3360 sock_set_v6only(sock);
3374 3361
@@ -4439,7 +4426,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset,
4439 if (ai->ai_family == AF_INET6) 4426 if (ai->ai_family == AF_INET6)
4440 sock_set_v6only(sock); 4427 sock_set_v6only(sock);
4441 if (x11_use_localhost) 4428 if (x11_use_localhost)
4442 channel_set_reuseaddr(sock); 4429 set_reuseaddr(sock);
4443 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 4430 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
4444 debug2("%s: bind port %d: %.100s", __func__, 4431 debug2("%s: bind port %d: %.100s", __func__,
4445 port, strerror(errno)); 4432 port, strerror(errno));
diff --git a/misc.c b/misc.c
index cb8bf5c14..cc22fbef4 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.c,v 1.116 2017/10/24 19:41:45 millert Exp $ */ 1/* $OpenBSD: misc.c,v 1.117 2017/10/25 00:15:35 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@@ -167,6 +167,44 @@ set_nodelay(int fd)
167 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 167 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
168} 168}
169 169
170/* Allow local port reuse in TIME_WAIT */
171int
172set_reuseaddr(int fd)
173{
174 int on = 1;
175
176 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
177 error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
178 return -1;
179 }
180 return 0;
181}
182
183/* Set routing table */
184int
185set_rdomain(int fd, const char *name)
186{
187 int rtable;
188 const char *errstr;
189
190 if (name == NULL)
191 return 0; /* default table */
192
193 rtable = (int)strtonum(name, 0, 255, &errstr);
194 if (errstr != NULL) {
195 /* Shouldn't happen */
196 error("Invalid routing domain \"%s\": %s", name, errstr);
197 return -1;
198 }
199 if (setsockopt(fd, SOL_SOCKET, SO_RTABLE,
200 &rtable, sizeof(rtable)) == -1) {
201 error("Failed to set routing domain %d on fd %d: %s",
202 rtable, fd, strerror(errno));
203 return -1;
204 }
205 return 0;
206}
207
170/* Characters considered whitespace in strsep calls. */ 208/* Characters considered whitespace in strsep calls. */
171#define WHITESPACE " \t\r\n" 209#define WHITESPACE " \t\r\n"
172#define QUOTE "\"" 210#define QUOTE "\""
diff --git a/misc.h b/misc.h
index 19fdf5c84..f36081f5d 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.h,v 1.65 2017/10/23 05:08:00 djm Exp $ */ 1/* $OpenBSD: misc.h,v 1.66 2017/10/25 00:15:35 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -48,6 +48,8 @@ char *strdelim(char **);
48int set_nonblock(int); 48int set_nonblock(int);
49int unset_nonblock(int); 49int unset_nonblock(int);
50void set_nodelay(int); 50void set_nodelay(int);
51int set_reuseaddr(int);
52int set_rdomain(int, const char *);
51int a2port(const char *); 53int a2port(const char *);
52int a2tun(const char *, int *); 54int a2tun(const char *, int *);
53char *put_host_port(const char *, u_short); 55char *put_host_port(const char *, u_short);
diff --git a/servconf.c b/servconf.c
index a96df4f67..68db047f2 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
1 1
2/* $OpenBSD: servconf.c,v 1.314 2017/10/05 15:52:03 djm Exp $ */ 2/* $OpenBSD: servconf.c,v 1.315 2017/10/25 00:15:35 djm Exp $ */
3/* 3/*
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved 5 * All rights reserved
@@ -15,10 +15,16 @@
15 15
16#include <sys/types.h> 16#include <sys/types.h>
17#include <sys/socket.h> 17#include <sys/socket.h>
18#ifdef HAVE_SYS_SYSCTL_H
19#include <sys/sysctl.h>
20#endif
18 21
19#include <netinet/in.h> 22#include <netinet/in.h>
20#include <netinet/in_systm.h> 23#include <netinet/in_systm.h>
21#include <netinet/ip.h> 24#include <netinet/ip.h>
25#ifdef HAVE_NET_ROUTE_H
26#include <net/route.h>
27#endif
22 28
23#include <ctype.h> 29#include <ctype.h>
24#include <netdb.h> 30#include <netdb.h>
@@ -58,8 +64,10 @@
58#include "myproposal.h" 64#include "myproposal.h"
59#include "digest.h" 65#include "digest.h"
60 66
61static void add_listen_addr(ServerOptions *, char *, int); 67static void add_listen_addr(ServerOptions *, const char *,
62static void add_one_listen_addr(ServerOptions *, char *, int); 68 const char *, int);
69static void add_one_listen_addr(ServerOptions *, const char *,
70 const char *, int);
63 71
64/* Use of privilege separation or not */ 72/* Use of privilege separation or not */
65extern int use_privsep; 73extern int use_privsep;
@@ -81,6 +89,7 @@ initialize_server_options(ServerOptions *options)
81 options->queued_listen_addrs = NULL; 89 options->queued_listen_addrs = NULL;
82 options->num_queued_listens = 0; 90 options->num_queued_listens = 0;
83 options->listen_addrs = NULL; 91 options->listen_addrs = NULL;
92 options->num_listen_addrs = 0;
84 options->address_family = -1; 93 options->address_family = -1;
85 options->num_host_key_files = 0; 94 options->num_host_key_files = 0;
86 options->num_host_cert_files = 0; 95 options->num_host_cert_files = 0;
@@ -252,7 +261,7 @@ fill_default_server_options(ServerOptions *options)
252 if (options->address_family == -1) 261 if (options->address_family == -1)
253 options->address_family = AF_UNSPEC; 262 options->address_family = AF_UNSPEC;
254 if (options->listen_addrs == NULL) 263 if (options->listen_addrs == NULL)
255 add_listen_addr(options, NULL, 0); 264 add_listen_addr(options, NULL, NULL, 0);
256 if (options->pid_file == NULL) 265 if (options->pid_file == NULL)
257 options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); 266 options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
258 if (options->login_grace_time == -1) 267 if (options->login_grace_time == -1)
@@ -658,23 +667,51 @@ derelativise_path(const char *path)
658} 667}
659 668
660static void 669static void
661add_listen_addr(ServerOptions *options, char *addr, int port) 670add_listen_addr(ServerOptions *options, const char *addr,
671 const char *rdomain, int port)
662{ 672{
663 u_int i; 673 u_int i;
664 674
665 if (port == 0) 675 if (port > 0)
666 for (i = 0; i < options->num_ports; i++) 676 add_one_listen_addr(options, addr, rdomain, port);
667 add_one_listen_addr(options, addr, options->ports[i]); 677 else {
668 else 678 for (i = 0; i < options->num_ports; i++) {
669 add_one_listen_addr(options, addr, port); 679 add_one_listen_addr(options, addr, rdomain,
680 options->ports[i]);
681 }
682 }
670} 683}
671 684
672static void 685static void
673add_one_listen_addr(ServerOptions *options, char *addr, int port) 686add_one_listen_addr(ServerOptions *options, const char *addr,
687 const char *rdomain, int port)
674{ 688{
675 struct addrinfo hints, *ai, *aitop; 689 struct addrinfo hints, *ai, *aitop;
676 char strport[NI_MAXSERV]; 690 char strport[NI_MAXSERV];
677 int gaierr; 691 int gaierr;
692 u_int i;
693
694 /* Find listen_addrs entry for this rdomain */
695 for (i = 0; i < options->num_listen_addrs; i++) {
696 if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
697 break;
698 if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
699 continue;
700 if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
701 break;
702 }
703 if (i >= options->num_listen_addrs) {
704 /* No entry for this rdomain; allocate one */
705 if (i >= INT_MAX)
706 fatal("%s: too many listen addresses", __func__);
707 options->listen_addrs = xrecallocarray(options->listen_addrs,
708 options->num_listen_addrs, options->num_listen_addrs + 1,
709 sizeof(*options->listen_addrs));
710 i = options->num_listen_addrs++;
711 if (rdomain != NULL)
712 options->listen_addrs[i].rdomain = xstrdup(rdomain);
713 }
714 /* options->listen_addrs[i] points to the addresses for this rdomain */
678 715
679 memset(&hints, 0, sizeof(hints)); 716 memset(&hints, 0, sizeof(hints));
680 hints.ai_family = options->address_family; 717 hints.ai_family = options->address_family;
@@ -687,8 +724,37 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
687 ssh_gai_strerror(gaierr)); 724 ssh_gai_strerror(gaierr));
688 for (ai = aitop; ai->ai_next; ai = ai->ai_next) 725 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
689 ; 726 ;
690 ai->ai_next = options->listen_addrs; 727 ai->ai_next = options->listen_addrs[i].addrs;
691 options->listen_addrs = aitop; 728 options->listen_addrs[i].addrs = aitop;
729}
730
731/* Returns nonzero if the routing domain name is valid */
732static int
733valid_rdomain(const char *name)
734{
735 const char *errstr;
736 long long num;
737 struct rt_tableinfo info;
738 int mib[6];
739 size_t miblen = sizeof(mib);
740
741 if (name == NULL)
742 return 1;
743
744 num = strtonum(name, 0, 255, &errstr);
745 if (errstr != NULL)
746 return 0;
747
748 /* Check whether the table actually exists */
749 memset(mib, 0, sizeof(mib));
750 mib[0] = CTL_NET;
751 mib[1] = PF_ROUTE;
752 mib[4] = NET_RT_TABLE;
753 mib[5] = (int)num;
754 if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
755 return 0;
756
757 return 1;
692} 758}
693 759
694/* 760/*
@@ -696,18 +762,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
696 * and AddressFamily options. 762 * and AddressFamily options.
697 */ 763 */
698static void 764static void
699queue_listen_addr(ServerOptions *options, char *addr, int port) 765queue_listen_addr(ServerOptions *options, const char *addr,
766 const char *rdomain, int port)
700{ 767{
701 options->queued_listen_addrs = xreallocarray( 768 struct queued_listenaddr *qla;
702 options->queued_listen_addrs, options->num_queued_listens + 1, 769
703 sizeof(addr)); 770 options->queued_listen_addrs = xrecallocarray(
704 options->queued_listen_ports = xreallocarray( 771 options->queued_listen_addrs,
705 options->queued_listen_ports, options->num_queued_listens + 1, 772 options->num_queued_listens, options->num_queued_listens + 1,
706 sizeof(port)); 773 sizeof(*options->queued_listen_addrs));
707 options->queued_listen_addrs[options->num_queued_listens] = 774 qla = &options->queued_listen_addrs[options->num_queued_listens++];
708 xstrdup(addr); 775 qla->addr = xstrdup(addr);
709 options->queued_listen_ports[options->num_queued_listens] = port; 776 qla->port = port;
710 options->num_queued_listens++; 777 qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
711} 778}
712 779
713/* 780/*
@@ -717,6 +784,7 @@ static void
717process_queued_listen_addrs(ServerOptions *options) 784process_queued_listen_addrs(ServerOptions *options)
718{ 785{
719 u_int i; 786 u_int i;
787 struct queued_listenaddr *qla;
720 788
721 if (options->num_ports == 0) 789 if (options->num_ports == 0)
722 options->ports[options->num_ports++] = SSH_DEFAULT_PORT; 790 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
@@ -724,15 +792,13 @@ process_queued_listen_addrs(ServerOptions *options)
724 options->address_family = AF_UNSPEC; 792 options->address_family = AF_UNSPEC;
725 793
726 for (i = 0; i < options->num_queued_listens; i++) { 794 for (i = 0; i < options->num_queued_listens; i++) {
727 add_listen_addr(options, options->queued_listen_addrs[i], 795 qla = &options->queued_listen_addrs[i];
728 options->queued_listen_ports[i]); 796 add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
729 free(options->queued_listen_addrs[i]); 797 free(qla->addr);
730 options->queued_listen_addrs[i] = NULL; 798 free(qla->rdomain);
731 } 799 }
732 free(options->queued_listen_addrs); 800 free(options->queued_listen_addrs);
733 options->queued_listen_addrs = NULL; 801 options->queued_listen_addrs = NULL;
734 free(options->queued_listen_ports);
735 options->queued_listen_ports = NULL;
736 options->num_queued_listens = 0; 802 options->num_queued_listens = 0;
737} 803}
738 804
@@ -1127,20 +1193,33 @@ process_server_config_line(ServerOptions *options, char *line,
1127 /* check for bare IPv6 address: no "[]" and 2 or more ":" */ 1193 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
1128 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL 1194 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
1129 && strchr(p+1, ':') != NULL) { 1195 && strchr(p+1, ':') != NULL) {
1130 queue_listen_addr(options, arg, 0);
1131 break;
1132 }
1133 p = hpdelim(&arg);
1134 if (p == NULL)
1135 fatal("%s line %d: bad address:port usage",
1136 filename, linenum);
1137 p = cleanhostname(p);
1138 if (arg == NULL)
1139 port = 0; 1196 port = 0;
1140 else if ((port = a2port(arg)) <= 0) 1197 p = arg;
1141 fatal("%s line %d: bad port number", filename, linenum); 1198 } else {
1199 p = hpdelim(&arg);
1200 if (p == NULL)
1201 fatal("%s line %d: bad address:port usage",
1202 filename, linenum);
1203 p = cleanhostname(p);
1204 if (arg == NULL)
1205 port = 0;
1206 else if ((port = a2port(arg)) <= 0)
1207 fatal("%s line %d: bad port number",
1208 filename, linenum);
1209 }
1210 /* Optional routing table */
1211 arg2 = NULL;
1212 if ((arg = strdelim(&cp)) != NULL) {
1213 if (strcmp(arg, "rdomain") != 0 ||
1214 (arg2 = strdelim(&cp)) == NULL)
1215 fatal("%s line %d: bad ListenAddress syntax",
1216 filename, linenum);
1217 if (!valid_rdomain(arg2))
1218 fatal("%s line %d: bad routing domain",
1219 filename, linenum);
1220 }
1142 1221
1143 queue_listen_addr(options, p, port); 1222 queue_listen_addr(options, p, arg2, port);
1144 1223
1145 break; 1224 break;
1146 1225
@@ -2251,45 +2330,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
2251 printf("\n"); 2330 printf("\n");
2252} 2331}
2253 2332
2254void 2333static char *
2255dump_config(ServerOptions *o) 2334format_listen_addrs(struct listenaddr *la)
2256{ 2335{
2257 u_int i; 2336 int r;
2258 int ret;
2259 struct addrinfo *ai; 2337 struct addrinfo *ai;
2260 char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL; 2338 char addr[NI_MAXHOST], port[NI_MAXSERV];
2261 char *laddr1 = xstrdup(""), *laddr2 = NULL; 2339 char *laddr1 = xstrdup(""), *laddr2 = NULL;
2262 2340
2263 /* these are usually at the top of the config */
2264 for (i = 0; i < o->num_ports; i++)
2265 printf("port %d\n", o->ports[i]);
2266 dump_cfg_fmtint(sAddressFamily, o->address_family);
2267
2268 /* 2341 /*
2269 * ListenAddress must be after Port. add_one_listen_addr pushes 2342 * ListenAddress must be after Port. add_one_listen_addr pushes
2270 * addresses onto a stack, so to maintain ordering we need to 2343 * addresses onto a stack, so to maintain ordering we need to
2271 * print these in reverse order. 2344 * print these in reverse order.
2272 */ 2345 */
2273 for (ai = o->listen_addrs; ai; ai = ai->ai_next) { 2346 for (ai = la->addrs; ai; ai = ai->ai_next) {
2274 if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, 2347 if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
2275 sizeof(addr), port, sizeof(port), 2348 sizeof(addr), port, sizeof(port),
2276 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { 2349 NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
2277 error("getnameinfo failed: %.100s", 2350 error("getnameinfo: %.100s", ssh_gai_strerror(r));
2278 (ret != EAI_SYSTEM) ? gai_strerror(ret) : 2351 continue;
2279 strerror(errno)); 2352 }
2353 laddr2 = laddr1;
2354 if (ai->ai_family == AF_INET6) {
2355 xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
2356 addr, port,
2357 la->rdomain == NULL ? "" : " rdomain ",
2358 la->rdomain == NULL ? "" : la->rdomain,
2359 laddr2);
2280 } else { 2360 } else {
2281 laddr2 = laddr1; 2361 xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
2282 if (ai->ai_family == AF_INET6) 2362 addr, port,
2283 xasprintf(&laddr1, "listenaddress [%s]:%s\n%s", 2363 la->rdomain == NULL ? "" : " rdomain ",
2284 addr, port, laddr2); 2364 la->rdomain == NULL ? "" : la->rdomain,
2285 else 2365 laddr2);
2286 xasprintf(&laddr1, "listenaddress %s:%s\n%s",
2287 addr, port, laddr2);
2288 free(laddr2);
2289 } 2366 }
2367 free(laddr2);
2368 }
2369 return laddr1;
2370}
2371
2372void
2373dump_config(ServerOptions *o)
2374{
2375 char *s;
2376 u_int i;
2377
2378 /* these are usually at the top of the config */
2379 for (i = 0; i < o->num_ports; i++)
2380 printf("port %d\n", o->ports[i]);
2381 dump_cfg_fmtint(sAddressFamily, o->address_family);
2382
2383 for (i = 0; i < o->num_listen_addrs; i++) {
2384 s = format_listen_addrs(&o->listen_addrs[i]);
2385 printf("%s", s);
2386 free(s);
2290 } 2387 }
2291 printf("%s", laddr1);
2292 free(laddr1);
2293 2388
2294 /* integer arguments */ 2389 /* integer arguments */
2295#ifdef USE_PAM 2390#ifdef USE_PAM
diff --git a/servconf.h b/servconf.h
index 1ff3bc5a1..3d0a0653f 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.127 2017/10/05 15:52:03 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.128 2017/10/25 00:15:35 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -51,14 +51,31 @@
51struct ssh; 51struct ssh;
52struct fwd_perm_list; 52struct fwd_perm_list;
53 53
54/*
55 * Used to store addresses from ListenAddr directives. These may be
56 * incomplete, as they may specify addresses that need to be merged
57 * with any ports requested by ListenPort.
58 */
59struct queued_listenaddr {
60 char *addr;
61 int port; /* <=0 if unspecified */
62 char *rdomain;
63};
64
65/* Resolved listen addresses, grouped by optional routing domain */
66struct listenaddr {
67 char *rdomain;
68 struct addrinfo *addrs;
69};
70
54typedef struct { 71typedef struct {
55 u_int num_ports; 72 u_int num_ports;
56 u_int ports_from_cmdline; 73 u_int ports_from_cmdline;
57 int ports[MAX_PORTS]; /* Port number to listen on. */ 74 int ports[MAX_PORTS]; /* Port number to listen on. */
75 struct queued_listenaddr *queued_listen_addrs;
58 u_int num_queued_listens; 76 u_int num_queued_listens;
59 char **queued_listen_addrs; 77 struct listenaddr *listen_addrs;
60 int *queued_listen_ports; 78 u_int num_listen_addrs;
61 struct addrinfo *listen_addrs; /* Addresses for server to listen. */
62 int address_family; /* Address family used by the server. */ 79 int address_family; /* Address family used by the server. */
63 80
64 char **host_key_files; /* Files containing host keys. */ 81 char **host_key_files; /* Files containing host keys. */
diff --git a/sshd.c b/sshd.c
index 0e3ac26db..93b02b6c8 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.493 2017/10/05 15:52:03 djm Exp $ */ 1/* $OpenBSD: sshd.c,v 1.494 2017/10/25 00:15:35 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1015,13 +1015,13 @@ server_accept_inetd(int *sock_in, int *sock_out)
1015 * Listen for TCP connections 1015 * Listen for TCP connections
1016 */ 1016 */
1017static void 1017static void
1018server_listen(void) 1018listen_on_addrs(struct listenaddr *la)
1019{ 1019{
1020 int ret, listen_sock, on = 1; 1020 int ret, listen_sock;
1021 struct addrinfo *ai; 1021 struct addrinfo *ai;
1022 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 1022 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
1023 1023
1024 for (ai = options.listen_addrs; ai; ai = ai->ai_next) { 1024 for (ai = la->addrs; ai; ai = ai->ai_next) {
1025 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 1025 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
1026 continue; 1026 continue;
1027 if (num_listen_socks >= MAX_LISTEN_SOCKS) 1027 if (num_listen_socks >= MAX_LISTEN_SOCKS)
@@ -1051,13 +1051,13 @@ server_listen(void)
1051 close(listen_sock); 1051 close(listen_sock);
1052 continue; 1052 continue;
1053 } 1053 }
1054 /* 1054 /* Socket options */
1055 * Set socket options. 1055 set_reuseaddr(listen_sock);
1056 * Allow local port reuse in TIME_WAIT. 1056 if (la->rdomain != NULL &&
1057 */ 1057 set_rdomain(listen_sock, la->rdomain) == -1) {
1058 if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, 1058 close(listen_sock);
1059 &on, sizeof(on)) == -1) 1059 continue;
1060 error("setsockopt SO_REUSEADDR: %s", strerror(errno)); 1060 }
1061 1061
1062 /* Only communicate in IPv6 over AF_INET6 sockets. */ 1062 /* Only communicate in IPv6 over AF_INET6 sockets. */
1063 if (ai->ai_family == AF_INET6) 1063 if (ai->ai_family == AF_INET6)
@@ -1079,9 +1079,28 @@ server_listen(void)
1079 if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) 1079 if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
1080 fatal("listen on [%s]:%s: %.100s", 1080 fatal("listen on [%s]:%s: %.100s",
1081 ntop, strport, strerror(errno)); 1081 ntop, strport, strerror(errno));
1082 logit("Server listening on %s port %s.", ntop, strport); 1082 logit("Server listening on %s port %s%s%s.",
1083 ntop, strport,
1084 la->rdomain == NULL ? "" : " rdomain ",
1085 la->rdomain == NULL ? "" : la->rdomain);
1086 }
1087}
1088
1089static void
1090server_listen(void)
1091{
1092 u_int i;
1093
1094 for (i = 0; i < options.num_listen_addrs; i++) {
1095 listen_on_addrs(&options.listen_addrs[i]);
1096 freeaddrinfo(options.listen_addrs[i].addrs);
1097 free(options.listen_addrs[i].rdomain);
1098 memset(&options.listen_addrs[i], 0,
1099 sizeof(options.listen_addrs[i]));
1083 } 1100 }
1084 freeaddrinfo(options.listen_addrs); 1101 free(options.listen_addrs);
1102 options.listen_addrs = NULL;
1103 options.num_listen_addrs = 0;
1085 1104
1086 if (!num_listen_socks) 1105 if (!num_listen_socks)
1087 fatal("Cannot bind any address."); 1106 fatal("Cannot bind any address.");
diff --git a/sshd_config.5 b/sshd_config.5
index 77a8354ab..b63a022b7 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd_config.5,v 1.255 2017/10/13 16:50:45 jmc Exp $ 36.\" $OpenBSD: sshd_config.5,v 1.256 2017/10/25 00:15:35 djm Exp $
37.Dd $Mdocdate: October 13 2017 $ 37.Dd $Mdocdate: October 25 2017 $
38.Dt SSHD_CONFIG 5 38.Dt SSHD_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -909,31 +909,48 @@ The following forms may be used:
909.It 909.It
910.Cm ListenAddress 910.Cm ListenAddress
911.Sm off 911.Sm off
912.Ar host | Ar IPv4_addr | Ar IPv6_addr 912.Ar hostname | Ar address
913.Sm on 913.Sm on
914.Oo rdomain Ar domain Oc
914.It 915.It
915.Cm ListenAddress 916.Cm ListenAddress
916.Sm off 917.Sm off
917.Ar host | Ar IPv4_addr : Ar port 918.Ar hostname : Ar port
918.Sm on 919.Sm on
920.Oo rdomain Ar domain Oc
921.It
922.Cm ListenAddress
923.Sm off
924.Ar IPv4_address : Ar port
925.Sm on
926.Oo rdomain Ar domain Oc
919.It 927.It
920.Cm ListenAddress 928.Cm ListenAddress
921.Sm off 929.Sm off
922.Oo 930.Oo
923.Ar host | Ar IPv6_addr Oc : Ar port 931.Ar hostname | address Oc : Ar port
924.Sm on 932.Sm on
933.Oo rdomain Ar domain Oc
925.El 934.El
926.Pp 935.Pp
936The optional
937.Cm rdomain
938qualifier requests
939.Xr sshd 8
940listen in an explicit routing domain.
927If 941If
928.Ar port 942.Ar port
929is not specified, 943is not specified,
930sshd will listen on the address and all 944sshd will listen on the address and all
931.Cm Port 945.Cm Port
932options specified. 946options specified.
933The default is to listen on all local addresses. 947The default is to listen on all local addresses on the current default
948routing domain.
934Multiple 949Multiple
935.Cm ListenAddress 950.Cm ListenAddress
936options are permitted. 951options are permitted.
952For more information on routing domains, see
953.Xr rdomain 4.
937.It Cm LoginGraceTime 954.It Cm LoginGraceTime
938The server disconnects after this time if the user has not 955The server disconnects after this time if the user has not
939successfully logged in. 956successfully logged in.