--- openssh-5.9p1-orig/configure.ac 2011-08-18 06:48:24.000000000 +0200 +++ openssh-5.9p1/configure.ac 2012-02-01 10:36:25.000000000 +0100 @@ -3373,6 +3373,17 @@ AC_SUBST([SSHLIBS]) AC_SUBST([SSHDLIBS]) +#check whether user wants SCTP support +SCTP_MSG="no" +AC_ARG_WITH(sctp, + [ --with-sctp Enable SCTP support], + [ if test "x$withval" != "xno" ; then + AC_DEFINE(SCTP,1,[Define if you want SCTP support.]) + AC_CHECK_FUNCS(sctp_recvmsg, , AC_CHECK_LIB(sctp, sctp_recvmsg)) + SCTP_MSG="yes" + fi ] +) + # Check whether user wants Kerberos 5 support KRB5_MSG="no" AC_ARG_WITH([kerberos5], @@ -4232,6 +4243,7 @@ echo " OSF SIA support: $SIA_MSG" echo " KerberosV support: $KRB5_MSG" echo " SELinux support: $SELINUX_MSG" +echo " SCTP support: $SCTP_MSG" echo " Smartcard support: $SCARD_MSG" echo " S/KEY support: $SKEY_MSG" echo " TCP Wrappers support: $TCPW_MSG" --- openssh-5.9p1-orig/misc.c 2011-05-05 06:14:34.000000000 +0200 +++ openssh-5.9p1/misc.c 2012-02-01 10:36:25.000000000 +0100 @@ -59,6 +59,10 @@ #include "log.h" #include "ssh.h" +#ifdef SCTP +#include +#endif + /* remove newline at end of string */ char * chop(char *s) @@ -141,17 +145,29 @@ optlen = sizeof opt; if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { - debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); +#ifdef SCTP + /* TCP_NODELAY failed, try SCTP_NODELAY */ + if (getsockopt(fd, IPPROTO_SCTP, SCTP_NODELAY, &opt, &optlen) == -1) { + debug("getsockopt TCP_NODELAY/SCTP_NODELAY: %.100s", strerror(errno)); + return; + } +#else return; +#endif } if (opt == 1) { - debug2("fd %d is TCP_NODELAY", fd); + debug2("fd %d is TCP_NODELAY/SCTP_NODELAY", fd); return; } opt = 1; - debug2("fd %d setting TCP_NODELAY", fd); - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) - error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); + debug2("fd %d setting TCP_NODELAY/SCTP_NODELAY", fd); + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) { +#ifdef SCTP + /* TCP_NODELAY failed, try SCTP_NODELAY */ + if (getsockopt(fd, IPPROTO_SCTP, SCTP_NODELAY, &opt, &optlen) == -1) + error("getsockopt TCP_NODELAY/SCTP_NODELAY: %.100s", strerror(errno)); +#endif + } } /* Characters considered whitespace in strsep calls. */ --- openssh-5.9p1-orig/openbsd-compat/bsd-openpty.c 2006-08-24 11:52:30.000000000 +0200 +++ openssh-5.9p1/openbsd-compat/bsd-openpty.c 2012-02-01 10:46:08.000000000 +0100 @@ -90,7 +90,7 @@ } return (0); -#elif defined(HAVE_DEV_PTMX) +#elif defined(HAVE_DEV_PTMX) && !defined(__FreeBSD__) /* * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 * also has bsd-style ptys, but they simply do not work.) --- openssh-5.9p1-orig/readconf.c 2011-05-29 13:42:31.000000000 +0200 +++ openssh-5.9p1/readconf.c 2012-02-01 10:36:25.000000000 +0100 @@ -117,6 +117,9 @@ oPasswordAuthentication, oRSAAuthentication, oChallengeResponseAuthentication, oXAuthLocation, oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, +#ifdef SCTP + oTransport, +#endif oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, @@ -182,6 +185,9 @@ { "hostname", oHostName }, { "hostkeyalias", oHostKeyAlias }, { "proxycommand", oProxyCommand }, +#ifdef SCTP + { "transport", oTransport }, +#endif { "port", oPort }, { "cipher", oCipher }, { "ciphers", oCiphers }, @@ -658,6 +664,22 @@ *charptr = xstrdup(s + len); return 0; +#ifdef SCTP + case oTransport: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%s line %d: missing transport protocol specification", + filename, linenum); + if (strcmp(arg, "tcp") == 0) + options->transport = TRANSPORT_TCP; + else if (strcmp(arg, "sctp") == 0) + options->transport = TRANSPORT_SCTP; + else + fatal("%s line %d: unknown transport protocol specified", + filename, linenum); + break; +#endif + case oPort: intptr = &options->port; parse_int: @@ -1150,6 +1172,9 @@ options->compression = -1; options->tcp_keep_alive = -1; options->compression_level = -1; +#ifdef SCTP + options->transport = -1; +#endif options->port = -1; options->address_family = -1; options->connection_attempts = -1; @@ -1260,6 +1285,10 @@ options->tcp_keep_alive = 1; if (options->compression_level == -1) options->compression_level = 6; +#ifdef SCTP + if (options->transport == -1) + options->transport = TRANSPORT_TCP; +#endif if (options->port == -1) options->port = 0; /* Filled in ssh_connect. */ if (options->address_family == -1) --- openssh-5.9p1-orig/readconf.h 2011-05-29 13:42:33.000000000 +0200 +++ openssh-5.9p1/readconf.h 2012-02-01 10:36:25.000000000 +0100 @@ -30,6 +30,10 @@ #define MAX_SEND_ENV 256 #define SSH_MAX_HOSTS_FILES 256 +/* Transport protocols */ +#define TRANSPORT_TCP 1 +#define TRANSPORT_SCTP 2 + typedef struct { int forward_agent; /* Forward authentication agent. */ int forward_x11; /* Forward X11 display. */ @@ -64,6 +68,9 @@ int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ LogLevel log_level; /* Level for logging. */ +#ifdef SCTP + int transport; /* Transport protocol used. */ +#endif int port; /* Port to connect. */ int address_family; int connection_attempts; /* Max attempts (seconds) before --- openssh-5.9p1-orig/scp.c 2011-01-06 12:41:21.000000000 +0100 +++ openssh-5.9p1/scp.c 2012-02-01 10:39:58.000000000 +0100 @@ -395,7 +395,11 @@ addargs(&args, "-oClearAllForwardings=yes"); fflag = tflag = 0; +#ifdef SCTP + while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:z")) != -1) +#else while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) +#endif switch (ch) { /* User-visible flags. */ case '1': @@ -403,6 +407,9 @@ case '4': case '6': case 'C': +#ifdef SCTP + case 'z': +#endif addargs(&args, "-%c", ch); addargs(&remote_remote_args, "-%c", ch); break; --- openssh-5.9p1-orig/servconf.c 2011-06-23 00:30:03.000000000 +0200 +++ openssh-5.9p1/servconf.c 2012-02-01 10:42:46.000000000 +0100 @@ -114,6 +114,9 @@ options->ciphers = NULL; options->macs = NULL; options->kex_algorithms = NULL; +#ifdef SCTP + options->transport = -1; +#endif options->protocol = SSH_PROTO_UNKNOWN; options->gateway_ports = -1; options->num_subsystems = 0; @@ -245,6 +248,10 @@ options->allow_tcp_forwarding = 1; if (options->allow_agent_forwarding == -1) options->allow_agent_forwarding = 1; +#ifdef SCTP + if (options->transport == -1) + options->transport = TRANSPORT_TCP; +#endif if (options->gateway_ports == -1) options->gateway_ports = 0; if (options->max_startups == -1) @@ -307,6 +314,9 @@ sKerberosTgtPassing, sChallengeResponseAuthentication, sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, +#ifdef SCTP + sTransport, sListenMultipleAddresses, +#endif sPrintMotd, sPrintLastLog, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, sStrictModes, sEmptyPasswd, sTCPKeepAlive, @@ -397,6 +407,9 @@ #endif { "checkmail", sDeprecated, SSHCFG_GLOBAL }, { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, +#ifdef SCTP + { "listenmultipleaddresses", sListenMultipleAddresses, SSHCFG_GLOBAL }, +#endif { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, { "printmotd", sPrintMotd, SSHCFG_GLOBAL }, { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL }, @@ -421,6 +434,9 @@ { "denygroups", sDenyGroups, SSHCFG_GLOBAL }, { "ciphers", sCiphers, SSHCFG_GLOBAL }, { "macs", sMacs, SSHCFG_GLOBAL }, +#ifdef SCTP + { "transport", sTransport, SSHCFG_GLOBAL }, +#endif { "protocol", sProtocol, SSHCFG_GLOBAL }, { "gatewayports", sGatewayPorts, SSHCFG_ALL }, { "subsystem", sSubsystem, SSHCFG_GLOBAL }, @@ -536,6 +552,81 @@ options->listen_addrs = aitop; } +#ifdef SCTP +static void +add_one_listen_multiple_addr(ServerOptions *options, char *addr, int port, int last) +{ + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = options->address_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0; + snprintf(strport, sizeof strport, "%d", port); + if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0) + fatal("bad addr or host: %s (%s)", + addr ? addr : "", + ssh_gai_strerror(gaierr)); + /* Mark addresses as multihomed */ + for (ai = aitop; ai->ai_next; ai = ai->ai_next) + ai->ai_flags = IS_MULTIPLE_ADDR; + ai->ai_flags = IS_MULTIPLE_ADDR; + ai->ai_next = options->listen_addrs; + options->listen_addrs = aitop; + + if (last) { + aitop->ai_flags = 0; + } +} + +static void +add_listen_multiple_addrs(ServerOptions *options, char *addrs, int port) +{ + u_int i, num_addrs; + char **addrsptr, *p; + + if (options->num_ports == 0) + options->ports[options->num_ports++] = SSH_DEFAULT_PORT; + if (options->address_family == -1) + options->address_family = AF_UNSPEC; + + num_addrs = 1; + p = addrs; + while ((p = strchr(p, ',')) != NULL) { + num_addrs++; + p++; + } + debug("found %d addresses for multi-homing", num_addrs); + + addrsptr = xmalloc(num_addrs * sizeof(char*)); + p = addrs; + for (i = 0; i < num_addrs; i++) { + addrsptr[i] = p; + p = strchr(p+1, ','); + if (p != NULL) + *(p++) = '\0'; + } + + if (port == 0) + for (i = 0; i < options->num_ports; i++) { + while (--num_addrs) { + add_one_listen_multiple_addr(options, addrsptr[num_addrs], options->ports[i], 0); + } + add_one_listen_multiple_addr(options, addrs, options->ports[i], 1); + } + else { + while (--num_addrs) { + add_one_listen_multiple_addr(options, addrsptr[num_addrs], port, 0); + } + add_one_listen_multiple_addr(options, addrs, port, 1); + } + + xfree(addrsptr); +} +#endif + /* * The strategy for the Match blocks is that the config file is parsed twice. * @@ -811,6 +902,26 @@ intptr = &options->key_regeneration_time; goto parse_time; +#ifdef SCTP + case sListenMultipleAddresses: + arg = strdelim(&cp); + if (arg == NULL || *arg == '\0') + fatal("%s line %d: missing addresses", + filename, linenum); + + /* Check for appended port */ + p = strchr(arg, ';'); + if (p != NULL) { + if ((port = a2port(p + 1)) <= 0) + fatal("%s line %d: bad port number", filename, linenum); + *p = '\0'; + } else { + port = 0; + } + add_listen_multiple_addrs(options, arg, port); + break; +#endif + case sListenAddress: arg = strdelim(&cp); if (arg == NULL || *arg == '\0') @@ -1148,6 +1259,24 @@ options->kex_algorithms = xstrdup(arg); break; +#ifdef SCTP + case sTransport: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing transport protocol specification", + filename, linenum); + if (strcmp(arg, "all") == 0) + options->transport = TRANSPORT_ALL; + else if (strcmp(arg, "tcp") == 0) + options->transport = TRANSPORT_TCP; + else if (strcmp(arg, "sctp") == 0) + options->transport = TRANSPORT_SCTP; + else + fatal("%s line %d: unknown transport protocol specified", + filename, linenum); + break; +#endif + case sProtocol: intptr = &options->protocol; arg = strdelim(&cp); @@ -1505,6 +1634,9 @@ M_CP_INTOPT(allow_tcp_forwarding); M_CP_INTOPT(allow_agent_forwarding); M_CP_INTOPT(permit_tun); +#ifdef SCTP + M_CP_INTOPT(transport); +#endif M_CP_INTOPT(gateway_ports); M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); @@ -1741,6 +1873,9 @@ dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); dump_cfg_fmtint(sUseLogin, o->use_login); dump_cfg_fmtint(sCompression, o->compression); +#ifdef SCTP + dump_cfg_fmtint(sTransport, o->transport); +#endif dump_cfg_fmtint(sGatewayPorts, o->gateway_ports); dump_cfg_fmtint(sUseDNS, o->use_dns); dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); --- openssh-5.9p1-orig/servconf.h 2011-06-23 00:30:03.000000000 +0200 +++ openssh-5.9p1/servconf.h 2012-02-01 10:41:12.000000000 +0100 @@ -47,6 +47,15 @@ /* Magic name for internal sftp-server */ #define INTERNAL_SFTP_NAME "internal-sftp" +#ifdef SCTP +/* Transport protocols */ +#define TRANSPORT_TCP 1 +#define TRANSPORT_SCTP 2 +#define TRANSPORT_ALL (TRANSPORT_TCP | TRANSPORT_SCTP) + +#define IS_MULTIPLE_ADDR 0x1000 +#endif + typedef struct { u_int num_ports; u_int ports_from_cmdline; @@ -81,6 +90,9 @@ char *ciphers; /* Supported SSH2 ciphers. */ char *macs; /* Supported SSH2 macs. */ char *kex_algorithms; /* SSH2 kex methods in order of preference. */ +#ifdef SCTP + int transport; /* Transport protocol(s) used */ +#endif int protocol; /* Supported protocol versions. */ int gateway_ports; /* If true, allow remote connects to forwarded ports. */ SyslogFacility log_facility; /* Facility for system logging. */ --- openssh-5.9p1-orig/ssh.c 2011-08-05 22:18:16.000000000 +0200 +++ openssh-5.9p1/ssh.c 2012-02-01 10:36:25.000000000 +0100 @@ -196,7 +196,11 @@ usage(void) { fprintf(stderr, +#ifdef SCTP +"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYyz] [-b bind_address] [-c cipher_spec]\n" +#else "usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" +#endif " [-D [bind_address:]port] [-e escape_char] [-F configfile]\n" " [-I pkcs11] [-i identity_file]\n" " [-L [bind_address:]port:host:hostport]\n" @@ -325,7 +329,11 @@ argv0 = av[0]; again: +#ifdef SCTP + while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvxz" +#else while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" +#endif "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': @@ -524,6 +532,11 @@ else options.control_master = SSHCTL_MASTER_YES; break; +#ifdef SCTP + case 'z': + options.transport = TRANSPORT_SCTP; + break; +#endif case 'p': options.port = a2port(optarg); if (options.port <= 0) { --- openssh-5.9p1-orig/sshconnect.c 2011-05-29 13:42:34.000000000 +0200 +++ openssh-5.9p1/sshconnect.c 2012-02-01 10:36:25.000000000 +0100 @@ -62,6 +62,10 @@ #include "ssh2.h" #include "version.h" +#ifdef SCTP +#include +#endif + char *client_version_string = NULL; char *server_version_string = NULL; @@ -189,6 +193,9 @@ { int sock, gaierr; struct addrinfo hints, *res; +#ifdef SCTP + char *more_addrs, *next_addr; +#endif /* * If we are running as root and want to connect to a privileged @@ -217,10 +224,22 @@ if (options.bind_address == NULL) return sock; +#ifdef SCTP + /* Check if multiple addresses have been specified */ + if ((more_addrs = strchr(options.bind_address, ',')) != NULL) { + *(more_addrs++) = '\0'; + } +#endif + memset(&hints, 0, sizeof(hints)); hints.ai_family = ai->ai_family; hints.ai_socktype = ai->ai_socktype; +#ifndef SCTP + /* Only specify protocol if SCTP is not used, due + * to the lack of SCTP support for getaddrinfo() + */ hints.ai_protocol = ai->ai_protocol; +#endif hints.ai_flags = AI_PASSIVE; gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); if (gaierr) { @@ -235,6 +254,34 @@ freeaddrinfo(res); return -1; } +#ifdef SCTP + /* If there are multiple addresses, bind them too */ + if (more_addrs) { + do { + next_addr = strchr(more_addrs, ','); + if (next_addr != NULL) { + *(next_addr++) = '\0'; + } + + gaierr = getaddrinfo(more_addrs, NULL, &hints, &res); + if (gaierr) { + error("getaddrinfo: %s: %s", more_addrs, + ssh_gai_strerror(gaierr)); + close(sock); + return -1; + } + if (sctp_bindx(sock, (struct sockaddr *)res->ai_addr, + 1, SCTP_BINDX_ADD_ADDR) != 0) { + error("bind: %s: %s", options.bind_address, strerror(errno)); + close(sock); + freeaddrinfo(res); + return -1; + } + + more_addrs = next_addr; + } while (next_addr != NULL); + } +#endif freeaddrinfo(res); return sock; } @@ -360,6 +407,15 @@ fatal("%s: Could not resolve hostname %.100s: %s", __progname, host, ssh_gai_strerror(gaierr)); +#ifdef SCTP + /* Use SCTP if requested */ + if (options.transport == TRANSPORT_SCTP) { + for (ai = aitop; ai; ai = ai->ai_next) { + ai->ai_protocol = IPPROTO_SCTP; + } + } +#endif + for (attempt = 0; attempt < connection_attempts; attempt++) { if (attempt > 0) { /* Sleep a moment before retrying. */ --- openssh-5.9p1-orig/sshd.c 2011-06-23 11:45:51.000000000 +0200 +++ openssh-5.9p1/sshd.c 2012-02-01 10:36:25.000000000 +0100 @@ -128,6 +128,10 @@ int deny_severity; #endif /* LIBWRAP */ +#ifdef SCTP +#include +#endif + #ifndef O_NOCTTY #define O_NOCTTY 0 #endif @@ -1027,6 +1031,12 @@ for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; +#ifdef SCTP + /* Ignore multi-homing addresses for TCP */ + if (ai->ai_flags & IS_MULTIPLE_ADDR || + (ai->ai_next != NULL && ai->ai_next->ai_flags & IS_MULTIPLE_ADDR)) + continue; +#endif if (num_listen_socks >= MAX_LISTEN_SOCKS) fatal("Too many listen sockets. " "Enlarge MAX_LISTEN_SOCKS"); @@ -1085,6 +1095,127 @@ fatal("Cannot bind any address."); } +#ifdef SCTP +/* + * Listen for SCTP connections + */ +static void +server_listen_sctp(void) +{ + int ret, listen_sock, on = 1; + struct addrinfo *ai, *aiv6; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + + for (ai = options.listen_addrs; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + /* Ignore multi-homing addresses at this point */ + if (ai->ai_flags & IS_MULTIPLE_ADDR) + continue; + if (num_listen_socks >= MAX_LISTEN_SOCKS) + fatal("Too many listen sockets. " + "Enlarge MAX_LISTEN_SOCKS"); + if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { + error("getnameinfo failed: %.100s", + ssh_gai_strerror(ret)); + continue; + } + /* Check for multi-homed IPv6 addresses if family is IPv4 */ + if (ai->ai_family == AF_INET) { + aiv6 = ai->ai_next; + while (aiv6 != NULL && aiv6->ai_flags & IS_MULTIPLE_ADDR) { + if (aiv6->ai_family == AF_INET6) { + ai->ai_family = AF_INET6; + break; + } + aiv6 = aiv6->ai_next; + } + } + + /* Create socket for listening. */ + listen_sock = socket(ai->ai_family, ai->ai_socktype, + IPPROTO_SCTP); + if (listen_sock < 0) { + /* kernel may not support ipv6 */ + verbose("SCTP socket: %.100s", strerror(errno)); + continue; + } + if (set_nonblock(listen_sock) == -1) { + 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("SCTP setsockopt SO_REUSEADDR: %s", strerror(errno)); + + /* Only communicate in IPv6 over AF_INET6 sockets if not multi-homed. */ + if (ai->ai_family == AF_INET6 && (ai->ai_next == NULL || + (ai->ai_next != NULL && ai->ai_next->ai_flags == 0))) + sock_set_v6only(listen_sock); + + if (ai->ai_next != NULL && ai->ai_next->ai_flags & IS_MULTIPLE_ADDR) + debug("Bind multi-homed to SCTP port %s on %s.", strport, ntop); + else + debug("Bind to SCTP port %s on %s.", strport, ntop); + + /* Bind the socket to the desired port. */ + if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { + error("Bind to SCTP port %s on %s failed: %.200s.", + strport, ntop, strerror(errno)); + close(listen_sock); + continue; + } + + /* Bind multi-homing addresses */ + while (ai->ai_next != NULL && + ai->ai_next->ai_flags & IS_MULTIPLE_ADDR) { + ai = ai->ai_next; + + if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { + error("getnameinfo failed: %.100s", + ssh_gai_strerror(ret)); + continue; + } + + debug("Bind multi-homed to SCTP port %s on %s.", strport, ntop); + + if (sctp_bindx(listen_sock, (struct sockaddr *)ai->ai_addr, 1, SCTP_BINDX_ADD_ADDR) != 0) { + error("Bind to SCTP port %s on %s failed: %.200s.", + strport, ntop, strerror(errno)); + close(listen_sock); + continue; + } + } + + listen_socks[num_listen_socks] = listen_sock; + num_listen_socks++; + + /* Start listening on the port. */ + if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) + fatal("SCTP listen on [%s]:%s: %.100s", + ntop, strport, strerror(errno)); + if (ai->ai_flags & IS_MULTIPLE_ADDR) + logit("Server listening multi-homed with SCTP on port %s.", strport); + else + logit("Server listening with SCTP on %s port %s.", ntop, strport); + } + /* Only free addresses if SCTP is the only used protocol */ + if (options.transport == TRANSPORT_SCTP) + freeaddrinfo(options.listen_addrs); + + if (!num_listen_socks) + fatal("Cannot bind any address for SCTP."); +} +#endif + /* * The main TCP accept loop. Note that, for the non-debug case, returns * from this function are in a forked subprocess. @@ -1784,7 +1915,14 @@ server_accept_inetd(&sock_in, &sock_out); } else { platform_pre_listen(); - server_listen(); + +#ifdef SCTP + if (options.transport & TRANSPORT_SCTP) + server_listen_sctp(); + + if (options.transport & TRANSPORT_TCP) +#endif + server_listen(); if (options.protocol & SSH_PROTO_1) generate_ephemeral_server_key();