diff -Nur openssh-6.9p1/readconf.c openssh-6.9p1-knock/readconf.c --- openssh-6.9p1/readconf.c 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/readconf.c 2015-07-15 14:16:47.607707232 -0300 @@ -156,6 +156,9 @@ oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, +#ifdef TCP_STEALTH + oTCPStealthSecret, +#endif oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -276,6 +279,9 @@ { "updatehostkeys", oUpdateHostkeys }, { "hostbasedkeytypes", oHostbasedKeyTypes }, { "ignoreunknown", oIgnoreUnknown }, +#ifdef TCP_STEALTH + { "tcpstealthsecret", oTCPStealthSecret }, +#endif { NULL, oBadOption } }; @@ -1496,6 +1502,23 @@ *charptr = xstrdup(arg); break; +#ifdef TCP_STEALTH + case oTCPStealthSecret: + charptr = &options->tcp_stealth_secret; + + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", + filename, linenum); + + if (*activep && *charptr == NULL) { + *charptr = xmalloc(64 + 1); + memset(*charptr, 0x00, 64 + 1); + strncpy(*charptr, arg, 64); + } + + break; +#endif case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1672,6 +1695,9 @@ options->canonicalize_max_dots = -1; options->canonicalize_fallback_local = -1; options->canonicalize_hostname = -1; +#ifdef TCP_STEALTH + options->tcp_stealth_secret = NULL; +#endif options->revoked_host_keys = NULL; options->fingerprint_hash = -1; options->update_hostkeys = -1; diff -Nur openssh-6.9p1/readconf.h openssh-6.9p1-knock/readconf.h --- openssh-6.9p1/readconf.h 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/readconf.h 2015-07-15 14:04:58.425806327 -0300 @@ -153,6 +153,9 @@ char *hostbased_key_types; char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ +#ifdef TCP_STEALTH + char *tcp_stealth_secret; +#endif } Options; #define SSH_CANONICALISE_NO 0 diff -Nur openssh-6.9p1/servconf.c openssh-6.9p1-knock/servconf.c --- openssh-6.9p1/servconf.c 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/servconf.c 2015-07-15 14:25:04.166739038 -0300 @@ -166,6 +166,9 @@ options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->version_addendum = NULL; +#ifdef TCP_STEALTH + options->tcp_stealth_secret = NULL; +#endif options->fingerprint_hash = -1; } @@ -412,6 +415,9 @@ sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sStreamLocalBindMask, sStreamLocalBindUnlink, sAllowStreamLocalForwarding, sFingerprintHash, +#ifdef TCP_STEALTH + sTCPStealthSecret, +#endif sDeprecated, sUnsupported } ServerOpCodes; @@ -548,6 +554,9 @@ { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, +#ifdef TCP_STEALTH + { "tcpstealthsecret", sTCPStealthSecret }, +#endif { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, { NULL, sBadOption, 0 } }; @@ -1826,6 +1835,24 @@ options->fingerprint_hash = value; break; +#ifdef TCP_STEALTH + case sTCPStealthSecret: + charptr = &options->tcp_stealth_secret; + + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", + filename, linenum); + + if (*activep && *charptr == NULL) { + *charptr = xmalloc(64 + 1); + memset(*charptr, 0x00, 64 + 1); + strncpy(*charptr, arg, 64); + } + + break; +#endif + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); diff -Nur openssh-6.9p1/servconf.h openssh-6.9p1-knock/servconf.h --- openssh-6.9p1/servconf.h 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/servconf.h 2015-07-15 14:18:38.255623536 -0300 @@ -193,6 +193,9 @@ u_int num_auth_methods; char *auth_methods[MAX_AUTH_METHODS]; +#ifdef TCP_STEALTH + char *tcp_stealth_secret; +#endif int fingerprint_hash; } ServerOptions; @@ -215,6 +218,12 @@ * NB. an option must appear in servconf.c:copy_set_server_options() or * COPY_MATCH_STRING_OPTS here but never both. */ +#ifdef TCP_STEALTH +#define M_CP_STEALTHSCRT(X) M_CP_STROPT(X); +#else +#define M_CP_STEALTHSCRT(X) +#endif + #define COPY_MATCH_STRING_OPTS() do { \ M_CP_STROPT(banner); \ M_CP_STROPT(trusted_user_ca_keys); \ @@ -233,6 +242,7 @@ M_CP_STRARRAYOPT(deny_groups, num_deny_groups); \ M_CP_STRARRAYOPT(accept_env, num_accept_env); \ M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \ + M_CP_STEALTHSCRT(tcp_stealth_secret); \ } while (0) struct connection_info *get_connection_info(int, int); diff -Nur openssh-6.9p1/ssh.0 openssh-6.9p1-knock/ssh.0 --- openssh-6.9p1/ssh.0 2015-06-30 23:41:10.000000000 -0300 +++ openssh-6.9p1-knock/ssh.0 2015-07-15 14:04:58.429139496 -0300 @@ -408,6 +408,20 @@ -y Send log information using the syslog(3) system module. By default this information is sent to stderr. + -z tcp_stealth_secret + Specifies the shared secret which is needed to connect to a stealth + SSH TCP server. Any string specified will be truncated to or padded + with zeroes to 64 bytes. This option needs kernel support and is + therefore only available if the required setsockopt() call is + available. + See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ + for details. + + IMPORTANT: This option should only be used for the purpose of + testing as other users could easily read out the secret from the + command line arguments. The TCPStealthSecret configuration option + is the preferred way of specifying the TCP Stealth secret. + ssh may additionally obtain configuration data from a per-user configuration file and a system-wide configuration file. The file format and configuration options are described in ssh_config(5). diff -Nur openssh-6.9p1/ssh.1 openssh-6.9p1-knock/ssh.1 --- openssh-6.9p1/ssh.1 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/ssh.1 2015-07-15 14:04:58.429139496 -0300 @@ -63,6 +63,7 @@ .Op Fl S Ar ctl_path .Op Fl W Ar host : Ns Ar port .Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun +.Op Fl z Ar tcp_stealth_secret .Oo Ar user Ns @ Oc Ns Ar hostname .Op Ar command .Ek @@ -483,6 +484,7 @@ .It StreamLocalBindUnlink .It StrictHostKeyChecking .It TCPKeepAlive +.It TCPStealthSecret .It Tunnel .It TunnelDevice .It UpdateHostKeys @@ -681,6 +683,21 @@ .Xr syslog 3 system module. By default this information is sent to stderr. +.It Fl z Ar tcp_stealth_secret +Specifies the shared secret which is needed to connect to a stealth SSH TCP +server. Any string specified will be truncated to or padded with zeroes to 64 +bytes. This option needs kernel support and is therefore only available if the +required +.Xr setsockopt 2 +call is available. +.Pp +See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ for details. +.Pp +.Cm IMPORTANT: +This option should only be used for the purpose of testing as other users could +easily read out the secret from the command line arguments. The +.Cm TCPStealthSecret +configuration option is the preferred way of specifying the TCP Stealth secret. .El .Pp .Nm diff -Nur openssh-6.9p1/ssh.c openssh-6.9p1-knock/ssh.c --- openssh-6.9p1/ssh.c 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/ssh.c 2015-07-15 14:07:18.282271552 -0300 @@ -194,6 +194,14 @@ extern int muxserver_sock; extern u_int muxclient_command; +#ifdef TCP_STEALTH +#define OPT_STEALTH "[-z tcp_stealth_secret] " +#define GETOPT_STEALTH "z:" +#else +#define OPT_STEALTH "" +#define GETOPT_STEALTH "" +#endif + /* Prints a help message to the user. This function never returns. */ static void @@ -207,7 +215,7 @@ " [-O ctl_cmd] [-o option] [-p port]\n" " [-Q cipher | cipher-auth | mac | kex | key]\n" " [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]\n" -" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" +" [-w local_tun[:remote_tun]] " OPT_STEALTH "[user@]hostname [command]\n" ); exit(255); } @@ -595,7 +603,7 @@ again: while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" - "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { + "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy" GETOPT_STEALTH)) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -906,6 +914,12 @@ case 'F': config = optarg; break; +#ifdef TCP_STEALTH + case 'z': + options.tcp_stealth_secret = xcalloc(64 + 1, sizeof(u_int8_t)); + strncpy(options.tcp_stealth_secret, optarg, 64); + break; +#endif default: usage(); } diff -Nur openssh-6.9p1/ssh_config.0 openssh-6.9p1-knock/ssh_config.0 --- openssh-6.9p1/ssh_config.0 2015-06-30 23:41:12.000000000 -0300 +++ openssh-6.9p1-knock/ssh_config.0 2015-07-15 14:04:58.432472666 -0300 @@ -859,6 +859,15 @@ To disable TCP keepalive messages, the value should be set to M-bM-^@M-^\noM-bM-^@M-^]. + TCPStealthSecret + Specifies the shared secret which is needed to connect to a stealth + SSH TCP Server. Any string specified will be truncated to or padded + with zeroes to 64 bytes. This option needs kernel support and is + therefore only available if the required setsockopt() call is + available. + See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ + for details. + Tunnel Request tun(4) device forwarding between the client and the server. The argument must be M-bM-^@M-^\yesM-bM-^@M-^], M-bM-^@M-^\point-to-pointM-bM-^@M-^] (layer 3), M-bM-^@M-^\ethernetM-bM-^@M-^] (layer 2), or M-bM-^@M-^\noM-bM-^@M-^]. Specifying M-bM-^@M-^\yesM-bM-^@M-^] requests the diff -Nur openssh-6.9p1/ssh_config.5 openssh-6.9p1-knock/ssh_config.5 --- openssh-6.9p1/ssh_config.5 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/ssh_config.5 2015-07-15 14:04:58.432472666 -0300 @@ -1469,6 +1469,15 @@ .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm TCPStealthSecret +Specifies the shared secret which is needed to connect to a stealth SSH TCP +Server. Any string specified will be truncated to or padded with zeroes to 64 +bytes. This option needs kernel support and is therefore only available if the +required +.Xr setsockopt 2 +call is available. +.Pp +See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ for details. .It Cm Tunnel Request .Xr tun 4 diff -Nur openssh-6.9p1/sshconnect.c openssh-6.9p1-knock/sshconnect.c --- openssh-6.9p1/sshconnect.c 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/sshconnect.c 2015-07-15 14:04:58.432472666 -0300 @@ -282,6 +282,17 @@ } fcntl(sock, F_SETFD, FD_CLOEXEC); +#ifdef TCP_STEALTH + if (options.tcp_stealth_secret) { + if (setsockopt(sock, IPPROTO_TCP, TCP_STEALTH, + options.tcp_stealth_secret, 64) == -1) { + error("setsockopt TCP_STEALTH: %s", strerror(errno)); + close(sock); + return -1; + } + } +#endif + /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL && !privileged) return sock; diff -Nur openssh-6.9p1/sshd.0 openssh-6.9p1-knock/sshd.0 --- openssh-6.9p1/sshd.0 2015-06-30 23:41:11.000000000 -0300 +++ openssh-6.9p1-knock/sshd.0 2015-07-15 14:04:58.432472666 -0300 @@ -7,7 +7,7 @@ sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_certificate_file] [-E log_file] [-f config_file] [-g login_grace_time] [-h host_key_file] [-k key_gen_time] - [-o option] [-p port] [-u len] + [-o option] [-p port] [-u len] [-z tcp_stealth_secret] DESCRIPTION sshd (OpenSSH Daemon) is the daemon program for ssh(1). Together these @@ -144,6 +144,21 @@ in a key file. Configuration options that require DNS include using a USER@HOST pattern in AllowUsers or DenyUsers. + -z tcp_stealth_secret + Turns this SSH server into a Stealth SSH TCP Server. This option + specifies the shared secret which is needed by the clients in order + to be able to connect to the port the SSH server is listening on. + Any string specified will be truncated or padded with zeroes to 64 + bytes. This option needs kernel support and is therefore only + available if the required setsockopt() call is available. + See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ + for details. + + IMPORTANT: This option should only be used for the purpose of + testing as other users could easily read out the secret from the + command line arguments. The TCPStealthSecret configuration option + is the preferred way of specifying the TCP Stealth secret. + AUTHENTICATION The OpenSSH SSH daemon supports SSH protocols 1 and 2. The default is to use protocol 2 only, though this can be changed via the Protocol option diff -Nur openssh-6.9p1/sshd.8 openssh-6.9p1-knock/sshd.8 --- openssh-6.9p1/sshd.8 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/sshd.8 2015-07-15 14:04:58.432472666 -0300 @@ -55,6 +55,7 @@ .Op Fl o Ar option .Op Fl p Ar port .Op Fl u Ar len +.Op Fl z Ar tcp_stealth_secret .Ek .Sh DESCRIPTION .Nm @@ -270,6 +271,24 @@ .Cm AllowUsers or .Cm DenyUsers . +.It Fl z Ar tcp_stealth_secret +Turns this SSH server into a stealth SSH TCP server. This option specifies the +shared secret which is needed by the clients in order to be able to connect to +the port the SSH server is listening on. Any string specified will be truncated +or padded with zeroes to 64 bytes. This option needs kernel support and is +therefore only available if the required +.Xr setsockopt 2 +call is available. +.Pp +See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ for details. + +.Cm IMPORTANT: +This option should only be used for the purpose of +testing as other users could easily read out the secret from the +command line arguments. The +.Cm TCPStealthSecret +configuration option +is the preferred way of specifying the TCP Stealth secret. .El .Sh AUTHENTICATION The OpenSSH SSH daemon supports SSH protocols 1 and 2. diff -Nur openssh-6.9p1/sshd.c openssh-6.9p1-knock/sshd.c --- openssh-6.9p1/sshd.c 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/sshd.c 2015-07-15 14:14:17.648384356 -0300 @@ -991,6 +991,14 @@ return (r < p) ? 1 : 0; } +#ifdef TCP_STEALTH +#define OPT_STEALTH " [-z tcp_stealth_secret]" +#define GETOPT_STEALTH "z:" +#else +#define OPT_STEALTH "" +#define GETOPT_STEALTH "" +#endif + static void usage(void) { @@ -1006,7 +1014,7 @@ "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" " [-E log_file] [-f config_file] [-g login_grace_time]\n" " [-h host_key_file] [-k key_gen_time] [-o option] [-p port]\n" -" [-u len]\n" +" [-u len]" OPT_STEALTH "\n" ); exit(1); } @@ -1184,6 +1192,14 @@ if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) error("setsockopt SO_REUSEADDR: %s", strerror(errno)); +#ifdef TCP_STEALTH + if (options.tcp_stealth_secret != NULL) { + if (setsockopt(listen_sock, IPPROTO_TCP, TCP_STEALTH, + options.tcp_stealth_secret, 64) == -1) + error("setsockopt TCP_STEALTH: %s", + strerror(errno)); + } +#endif /* Only communicate in IPv6 over AF_INET6 sockets. */ if (ai->ai_family == AF_INET6) @@ -1496,7 +1512,8 @@ /* Parse command-line arguments. */ while ((opt = getopt(ac, av, - "C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrt")) != -1) { + "z:C:E:b:c:f:g:h:k:o:p:u:" \ + "46DQRTdeiqrt" GETOPT_STEALTH)) != -1) { switch (opt) { case '4': options.address_family = AF_INET; @@ -1608,6 +1625,12 @@ exit(1); free(line); break; +#ifdef TCP_STEALTH + case 'z': + options.tcp_stealth_secret = xcalloc(64 + 1, sizeof(u_int8_t)); + strncpy(options.tcp_stealth_secret, optarg, 64); + break; +#endif case '?': default: usage(); diff -Nur openssh-6.9p1/sshd_config.0 openssh-6.9p1-knock/sshd_config.0 --- openssh-6.9p1/sshd_config.0 2015-06-30 23:41:12.000000000 -0300 +++ openssh-6.9p1-knock/sshd_config.0 2015-07-15 14:04:58.435805835 -0300 @@ -855,6 +855,19 @@ To disable TCP keepalive messages, the value should be set to M-bM-^@M-^\noM-bM-^@M-^]. + TCPStealthSecret + Turns this SSH server into a stealth SSH TCP server. This + configuration option specifies the shared secret needed by the + clients in order to be able to connect to the port the SSH server + is listening on. This means that port scanners will receive a + TCP RST and thus will not recognize this TCP port being open. + + Any string specified will be truncated or padded with zeroes to 64 + bytes. This option needs kernel support and is therefore only + available if the required setsockopt() call is available. + See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ + for details. + TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted to sign user certificates for diff -Nur openssh-6.9p1/sshd_config.5 openssh-6.9p1-knock/sshd_config.5 --- openssh-6.9p1/sshd_config.5 2015-06-30 23:35:31.000000000 -0300 +++ openssh-6.9p1-knock/sshd_config.5 2015-07-15 14:04:58.435805835 -0300 @@ -1432,6 +1432,18 @@ .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm TCPStealthSecret +Turns this SSH server into a stealth SSH TCP server. This configuration option +specifies the shared secret needed by the clients in order to be able to connect +to the port the SSH server is listening on. This means that port scanners will +receive a TCP RST and thus will not recognize this TCP port being open. Any +string specified will be truncated or padded with zeroes to 64 bytes. This +option needs kernel support and is therefore only available if the required +.Xr setsockopt 2 +call is available. +.Pp +See http://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/ for details. + .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted to sign user certificates for authentication, or