diff -Nur openssh-7.0p1.orig/readconf.c openssh-7.0p1/readconf.c --- openssh-7.0p1.orig/readconf.c 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/readconf.c 2015-08-16 17:30:39.572679872 -0300 @@ -156,6 +156,9 @@ oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, +#ifdef TCP_STEALTH + oTCPStealthSecret, +#endif oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, oPubkeyAcceptedKeyTypes, oIgnoredUnknownOption, oDeprecated, oUnsupported @@ -278,6 +281,9 @@ { "hostbasedkeytypes", oHostbasedKeyTypes }, { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, { "ignoreunknown", oIgnoreUnknown }, +#ifdef TCP_STEALTH + { "tcpstealthsecret", oTCPStealthSecret }, +#endif { NULL, oBadOption } }; @@ -1496,6 +1502,23 @@ charptr = &options->pubkey_key_types; goto parse_keytypes; +#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-7.0p1.orig/readconf.h openssh-7.0p1/readconf.h --- openssh-7.0p1.orig/readconf.h 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/readconf.h 2015-08-16 17:30:39.576013041 -0300 @@ -154,6 +154,9 @@ char *pubkey_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-7.0p1.orig/servconf.c openssh-7.0p1/servconf.c --- openssh-7.0p1.orig/servconf.c 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/servconf.c 2015-08-16 17:30:39.576013041 -0300 @@ -168,6 +168,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; } @@ -423,6 +426,9 @@ sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sStreamLocalBindMask, sStreamLocalBindUnlink, sAllowStreamLocalForwarding, sFingerprintHash, +#ifdef TCP_STEALTH + sTCPStealthSecret, +#endif sDeprecated, sUnsupported } ServerOpCodes; @@ -560,6 +566,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 } }; @@ -1843,6 +1852,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-7.0p1.orig/servconf.h openssh-7.0p1/servconf.h --- openssh-7.0p1.orig/servconf.h 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/servconf.h 2015-08-16 17:30:39.576013041 -0300 @@ -194,6 +194,9 @@ u_int num_auth_methods; char *auth_methods[MAX_AUTH_METHODS]; +#ifdef TCP_STEALTH + char *tcp_stealth_secret; +#endif int fingerprint_hash; } ServerOptions; @@ -216,6 +219,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); \ @@ -234,6 +243,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-7.0p1.orig/ssh.0 openssh-7.0p1/ssh.0 --- openssh-7.0p1.orig/ssh.0 2015-08-11 06:20:10.000000000 -0300 +++ openssh-7.0p1/ssh.0 2015-08-16 17:30:39.576013041 -0300 @@ -420,6 +420,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-7.0p1.orig/ssh.1 openssh-7.0p1/ssh.1 --- openssh-7.0p1.orig/ssh.1 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/ssh.1 2015-08-16 17:30:39.576013041 -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 @@ -534,6 +535,7 @@ .It StreamLocalBindUnlink .It StrictHostKeyChecking .It TCPKeepAlive +.It TCPStealthSecret .It Tunnel .It TunnelDevice .It UpdateHostKeys @@ -768,6 +770,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-7.0p1.orig/ssh.c openssh-7.0p1/ssh.c --- openssh-7.0p1.orig/ssh.c 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/ssh.c 2015-08-16 17:33:12.415164235 -0300 @@ -195,6 +195,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 @@ -208,7 +216,7 @@ " [-O ctl_cmd] [-o option] [-p port]\n" " [-Q cipher | cipher-auth | mac | kex | key]\n" " [-R address] [-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); } @@ -596,7 +604,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; @@ -907,6 +915,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-7.0p1.orig/ssh.c.rej openssh-7.0p1/ssh.c.rej --- openssh-7.0p1.orig/ssh.c.rej 1969-12-31 21:00:00.000000000 -0300 +++ openssh-7.0p1/ssh.c.rej 2015-08-16 17:30:39.576013041 -0300 @@ -0,0 +1,11 @@ +--- ssh.c 2015-06-30 23:35:31.000000000 -0300 ++++ ssh.c 2015-07-15 14:07:18.282271552 -0300 +@@ -215,7 +223,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); + } diff -Nur openssh-7.0p1.orig/ssh_config.0 openssh-7.0p1/ssh_config.0 --- openssh-7.0p1.orig/ssh_config.0 2015-08-11 06:20:11.000000000 -0300 +++ openssh-7.0p1/ssh_config.0 2015-08-16 17:30:39.576013041 -0300 @@ -900,6 +900,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-7.0p1.orig/ssh_config.5 openssh-7.0p1/ssh_config.5 --- openssh-7.0p1.orig/ssh_config.5 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/ssh_config.5 2015-08-16 17:30:39.579346210 -0300 @@ -1521,6 +1521,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-7.0p1.orig/sshconnect.c openssh-7.0p1/sshconnect.c --- openssh-7.0p1.orig/sshconnect.c 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/sshconnect.c 2015-08-16 17:30:39.579346210 -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-7.0p1.orig/sshd.0 openssh-7.0p1/sshd.0 --- openssh-7.0p1.orig/sshd.0 2015-08-11 06:20:10.000000000 -0300 +++ openssh-7.0p1/sshd.0 2015-08-16 17:30:39.579346210 -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 @@ -143,6 +143,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-7.0p1.orig/sshd.8 openssh-7.0p1/sshd.8 --- openssh-7.0p1.orig/sshd.8 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/sshd.8 2015-08-16 17:30:39.579346210 -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 @@ -267,6 +268,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-7.0p1.orig/sshd.c openssh-7.0p1/sshd.c --- openssh-7.0p1.orig/sshd.c 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/sshd.c 2015-08-16 17:30:39.579346210 -0300 @@ -995,6 +995,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) { @@ -1010,7 +1018,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); } @@ -1188,6 +1196,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) @@ -1500,7 +1516,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; @@ -1612,6 +1629,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-7.0p1.orig/sshd_config.0 openssh-7.0p1/sshd_config.0 --- openssh-7.0p1.orig/sshd_config.0 2015-08-11 06:20:10.000000000 -0300 +++ openssh-7.0p1/sshd_config.0 2015-08-16 17:30:39.579346210 -0300 @@ -908,6 +908,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-7.0p1.orig/sshd_config.5 openssh-7.0p1/sshd_config.5 --- openssh-7.0p1.orig/sshd_config.5 2015-08-11 05:57:29.000000000 -0300 +++ openssh-7.0p1/sshd_config.5 2015-08-16 17:30:39.579346210 -0300 @@ -1499,6 +1499,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