diff options
-rw-r--r-- | channels.c | 19 | ||||
-rw-r--r-- | misc.c | 40 | ||||
-rw-r--r-- | misc.h | 4 | ||||
-rw-r--r-- | servconf.c | 229 | ||||
-rw-r--r-- | servconf.h | 25 | ||||
-rw-r--r-- | sshd.c | 45 | ||||
-rw-r--r-- | sshd_config.5 | 29 |
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 | ||
1671 | static void | ||
1672 | channel_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 | |||
1684 | void | 1671 | void |
1685 | channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time) | 1672 | channel_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)); |
@@ -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 */ | ||
171 | int | ||
172 | set_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 */ | ||
184 | int | ||
185 | set_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 "\"" |
@@ -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 **); | |||
48 | int set_nonblock(int); | 48 | int set_nonblock(int); |
49 | int unset_nonblock(int); | 49 | int unset_nonblock(int); |
50 | void set_nodelay(int); | 50 | void set_nodelay(int); |
51 | int set_reuseaddr(int); | ||
52 | int set_rdomain(int, const char *); | ||
51 | int a2port(const char *); | 53 | int a2port(const char *); |
52 | int a2tun(const char *, int *); | 54 | int a2tun(const char *, int *); |
53 | char *put_host_port(const char *, u_short); | 55 | char *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 | ||
61 | static void add_listen_addr(ServerOptions *, char *, int); | 67 | static void add_listen_addr(ServerOptions *, const char *, |
62 | static void add_one_listen_addr(ServerOptions *, char *, int); | 68 | const char *, int); |
69 | static 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 */ |
65 | extern int use_privsep; | 73 | extern 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 | ||
660 | static void | 669 | static void |
661 | add_listen_addr(ServerOptions *options, char *addr, int port) | 670 | add_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 | ||
672 | static void | 685 | static void |
673 | add_one_listen_addr(ServerOptions *options, char *addr, int port) | 686 | add_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 */ | ||
732 | static int | ||
733 | valid_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 | */ |
698 | static void | 764 | static void |
699 | queue_listen_addr(ServerOptions *options, char *addr, int port) | 765 | queue_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 | |||
717 | process_queued_listen_addrs(ServerOptions *options) | 784 | process_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 | ||
2254 | void | 2333 | static char * |
2255 | dump_config(ServerOptions *o) | 2334 | format_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 | |||
2372 | void | ||
2373 | dump_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 @@ | |||
51 | struct ssh; | 51 | struct ssh; |
52 | struct fwd_perm_list; | 52 | struct 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 | */ | ||
59 | struct 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 */ | ||
66 | struct listenaddr { | ||
67 | char *rdomain; | ||
68 | struct addrinfo *addrs; | ||
69 | }; | ||
70 | |||
54 | typedef struct { | 71 | typedef 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. */ |
@@ -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 | */ |
1017 | static void | 1017 | static void |
1018 | server_listen(void) | 1018 | listen_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 | |||
1089 | static void | ||
1090 | server_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 |
936 | The optional | ||
937 | .Cm rdomain | ||
938 | qualifier requests | ||
939 | .Xr sshd 8 | ||
940 | listen in an explicit routing domain. | ||
927 | If | 941 | If |
928 | .Ar port | 942 | .Ar port |
929 | is not specified, | 943 | is not specified, |
930 | sshd will listen on the address and all | 944 | sshd will listen on the address and all |
931 | .Cm Port | 945 | .Cm Port |
932 | options specified. | 946 | options specified. |
933 | The default is to listen on all local addresses. | 947 | The default is to listen on all local addresses on the current default |
948 | routing domain. | ||
934 | Multiple | 949 | Multiple |
935 | .Cm ListenAddress | 950 | .Cm ListenAddress |
936 | options are permitted. | 951 | options are permitted. |
952 | For more information on routing domains, see | ||
953 | .Xr rdomain 4. | ||
937 | .It Cm LoginGraceTime | 954 | .It Cm LoginGraceTime |
938 | The server disconnects after this time if the user has not | 955 | The server disconnects after this time if the user has not |
939 | successfully logged in. | 956 | successfully logged in. |