[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Kernel Patch: TCP Stealth



Hello Felix,

Unfortunately, the TCP Stealth kernel patch ceased to work with kernel
versions (approximately) beyond 4.13, though it was still included in
Knoppix 8.2.0. I noticed shortly after the relase. As it seems, stealth
will also no longer be supported by the patch maintainers at gnunet. So
I won't include it in future versions. :-(

Attached, the current patch that I used, it's already applied in the
Knoppix Kernel Source package. If you find a way to make it work again
(makes only sense when also recompiling ssh with the same socket
numbers), I'd be happy! Maybe the new kernel "tcp_fastopen" feature
killed it.

To answer your second question: The reason for including TCP stealth was
to enable Knoppix-based SSH servers that are not easily found or
attacked by portscanners, and can only be accessed by the
stealth-patched ssh version (which was also included in Knoppix) plus
the correct TCP connect payload ("password"). This can be done in a
similar way using iptables, but IMHO not as elegant and effortless as
the stealth patch did when it was still working.

Regards
-Klaus Knopper

On 20.11.18, Felix Windsheimer wrote:
>    Hello,
>    I am using KNOPPIX 8.2 (DVD version). According to the release notes, the
>    kernel patch for TCP stealth is included in this version of KNOPPIX.
>    However, I can not manage to find how this patch was applied. The patch I
>    found on
>    [1]https://gnunet.org/knock
>    does not seem to be applied in my version of KNOPPIX. What am I missing?
>    Is the patch used in KNOPPIX a different one from the link above?
>    Also, on the topic of TCP Stealth: what was the rationale for including it
>    in KNOPPIX in the first place?
>    Kind regards,
>    Felix
> 
> References
> 
>    Visible links
>    1. https://gnunet.org/knock
diff -u -r linux-4.14.13.orig/include/linux/tcp.h linux-4.14.13/include/linux/tcp.h
--- linux-4.14.13.orig/include/linux/tcp.h	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/include/linux/tcp.h	2018-01-14 18:46:57.000000000 +0100
@@ -19,6 +19,7 @@
 
 
 #include <linux/skbuff.h>
+#include <linux/cryptohash.h>
 #include <linux/win_minmax.h>
 #include <net/sock.h>
 #include <net/inet_connection_sock.h>
@@ -356,6 +357,21 @@
 	struct tcp_md5sig_info	__rcu *md5sig_info;
 #endif
 
+#ifdef CONFIG_TCP_STEALTH
+/* Stealth TCP socket configuration */
+	struct {
+		#define TCP_STEALTH_MODE_AUTH		BIT(0)
+		#define TCP_STEALTH_MODE_INTEGRITY	BIT(1)
+		#define TCP_STEALTH_MODE_INTEGRITY_LEN	BIT(2)
+		u8 mode;
+		u8 secret[SHA_MESSAGE_BYTES];
+		u16 integrity_hash;
+		size_t integrity_len;
+		struct skb_mstamp *mstamp;
+		bool saw_tsval;
+	} stealth;
+#endif
+
 /* TCP fastopen related information */
 	struct tcp_fastopen_request *fastopen_req;
 	/* fastopen_rsk points to request_sock that resulted in this big
diff -u -r linux-4.14.13.orig/include/net/secure_seq.h linux-4.14.13/include/net/secure_seq.h
--- linux-4.14.13.orig/include/net/secure_seq.h	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/include/net/secure_seq.h	2018-01-14 18:46:57.000000000 +0100
@@ -18,5 +18,10 @@
 				__be16 sport, __be16 dport);
 u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
 				  __be16 sport, __be16 dport);
+#ifdef CONFIG_TCP_STEALTH
+u32 tcp_stealth_do_auth(struct sock *sk, struct sk_buff *skb);
+u32 tcp_stealth_sequence_number(struct sock *sk, __be32 *daddr,
+				u32 daddr_size, __be16 dport);
+#endif
 
 #endif /* _NET_SECURE_SEQ */
diff -u -r linux-4.14.13.orig/include/net/tcp.h linux-4.14.13/include/net/tcp.h
--- linux-4.14.13.orig/include/net/tcp.h	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/include/net/tcp.h	2018-01-14 18:46:57.000000000 +0100
@@ -435,6 +435,12 @@
 		       struct tcp_options_received *opt_rx,
 		       int estab, struct tcp_fastopen_cookie *foc);
 const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
+#ifdef CONFIG_TCP_STEALTH
+const bool tcp_parse_tsval_option(u32 *tsval, const struct tcphdr *th);
+int tcp_stealth_integrity(u16 *hash, u8 *secret, u8 *payload, int len);
+#define be32_isn_to_be16_av(x)	(((__be16 *)&x)[0])
+#define be32_isn_to_be16_ih(x)	(((__be16 *)&x)[1])
+#endif
 
 /*
  *	TCP v4 functions exported for the inet6 API
diff -u -r linux-4.14.13.orig/include/uapi/linux/tcp.h linux-4.14.13/include/uapi/linux/tcp.h
--- linux-4.14.13.orig/include/uapi/linux/tcp.h	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/include/uapi/linux/tcp.h	2018-01-14 18:46:57.000000000 +0100
@@ -120,6 +120,9 @@
 #define TCP_FASTOPEN_CONNECT	30	/* Attempt FastOpen with connect */
 #define TCP_ULP			31	/* Attach a ULP to a TCP connection */
 #define TCP_MD5SIG_EXT		32	/* TCP MD5 Signature with extensions */
+#define TCP_STEALTH		33
+#define TCP_STEALTH_INTEGRITY	34
+#define TCP_STEALTH_INTEGRITY_LEN 35
 
 struct tcp_repair_opt {
 	__u32	opt_code;
diff -u -r linux-4.14.13.orig/net/core/secure_seq.c linux-4.14.13/net/core/secure_seq.c
--- linux-4.14.13.orig/net/core/secure_seq.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/core/secure_seq.c	2018-01-14 18:46:57.000000000 +0100
@@ -14,6 +14,9 @@
 #include <linux/net.h>
 #include <linux/siphash.h>
 #include <net/secure_seq.h>
+#include <linux/socket.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 
 #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
 #include <linux/in6.h>
@@ -50,6 +53,102 @@
 }
 #endif
 
+#ifdef CONFIG_TCP_STEALTH
+u32 tcp_stealth_sequence_number(struct sock *sk, __be32 *daddr,
+				u32 daddr_size, __be16 dport)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct tcp_md5sig_key *md5;
+
+	__u32 sec[SHA_MESSAGE_BYTES / sizeof(__u32)];
+	__u32 i;
+	__u32 tsval = 0;
+
+	__be32 iv[MD5_DIGEST_WORDS] = { 0 };
+	__be32 isn;
+
+	memcpy(iv, daddr, (daddr_size > sizeof(iv)) ? sizeof(iv) : daddr_size);
+
+#ifdef CONFIG_TCP_MD5SIG
+	md5 = tp->af_specific->md5_lookup(sk, sk);
+#else
+	md5 = NULL;
+#endif
+	if (likely(sysctl_tcp_timestamps && !md5) || tp->stealth.saw_tsval)
+		tsval = tp->stealth.mstamp.stamp_jiffies;
+
+	((__be16 *)iv)[2] ^= cpu_to_be16(tp->stealth.integrity_hash);
+	iv[2] ^= cpu_to_be32(tsval);
+	((__be16 *)iv)[6] ^= dport;
+
+	for (i = 0; i < MD5_DIGEST_WORDS; i++)
+		iv[i] = le32_to_cpu(iv[i]);
+	for (i = 0; i < SHA_MESSAGE_BYTES / sizeof(__le32); i++)
+		sec[i] = le32_to_cpu(((__le32 *)tp->stealth.secret)[i]);
+
+	md5_transform(iv, sec);
+
+	isn = cpu_to_be32(iv[0]) ^ cpu_to_be32(iv[1]) ^
+	      cpu_to_be32(iv[2]) ^ cpu_to_be32(iv[3]);
+
+	if (tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY)
+		be32_isn_to_be16_ih(isn) =
+			cpu_to_be16(tp->stealth.integrity_hash);
+
+	return be32_to_cpu(isn);
+}
+EXPORT_SYMBOL(tcp_stealth_sequence_number);
+
+u32 tcp_stealth_do_auth(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct tcphdr *th = tcp_hdr(skb);
+	__be32 isn = th->seq;
+	__be32 hash;
+	__be32 *daddr;
+	u32 daddr_size;
+
+	tp->stealth.saw_tsval =
+		tcp_parse_tsval_option(&tp->stealth.mstamp.stamp_jiffies, th);
+
+	if (tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN)
+		tp->stealth.integrity_hash =
+			be16_to_cpu(be32_isn_to_be16_ih(isn));
+
+	switch (tp->inet_conn.icsk_inet.sk.sk_family) {
+#if IS_ENABLED(CONFIG_IPV6)
+	case PF_INET6:
+		daddr_size = sizeof(ipv6_hdr(skb)->daddr.s6_addr32);
+		daddr = ipv6_hdr(skb)->daddr.s6_addr32;
+	break;
+#endif
+	case PF_INET:
+		daddr_size = sizeof(ip_hdr(skb)->daddr);
+		daddr = &ip_hdr(skb)->daddr;
+	break;
+	default:
+		pr_err("TCP Stealth: Unknown network layer protocol, stop!\n");
+		return 1;
+	}
+
+	hash = tcp_stealth_sequence_number(sk, daddr, daddr_size, th->dest);
+	cpu_to_be32s(&hash);
+
+	if (tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
+	    tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN &&
+	    be32_isn_to_be16_av(isn) == be32_isn_to_be16_av(hash))
+		return 0;
+
+	if (tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
+	    !(tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN) &&
+	    isn == hash)
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(tcp_stealth_do_auth);
+#endif
+
 #if IS_ENABLED(CONFIG_IPV6)
 u32 secure_tcpv6_ts_off(const struct net *net,
 			const __be32 *saddr, const __be32 *daddr)
diff -u -r linux-4.14.13.orig/net/ipv4/Kconfig linux-4.14.13/net/ipv4/Kconfig
--- linux-4.14.13.orig/net/ipv4/Kconfig	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv4/Kconfig	2018-01-14 18:46:57.000000000 +0100
@@ -748,3 +748,13 @@
 	  on the Internet.
 
 	  If unsure, say N.
+
+config TCP_STEALTH
+	bool "TCP: Stealth TCP socket support"
+	default n
+	---help---
+	  This option enables support for stealth TCP sockets. If you do not
+	  know what this means, you do not need it.
+
+	  If unsure, say N.
+
diff -u -r linux-4.14.13.orig/net/ipv4/tcp.c linux-4.14.13/net/ipv4/tcp.c
--- linux-4.14.13.orig/net/ipv4/tcp.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv4/tcp.c	2018-01-14 18:48:20.000000000 +0100
@@ -269,6 +269,7 @@
 #include <linux/err.h>
 #include <linux/time.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/errqueue.h>
 
 #include <net/icmp.h>
@@ -2470,6 +2471,49 @@
 	return 0;
 }
 
+#ifdef CONFIG_TCP_STEALTH
+int tcp_stealth_integrity(__be16 *hash, u8 *secret, u8 *payload, int len)
+{
+	struct scatterlist sg[2];
+	struct crypto_ahash *tfm;
+	struct ahash_request *req;
+	__be16 h[MD5_DIGEST_WORDS * 2];
+	int i;
+	int err = 0;
+
+	tfm = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		err = -PTR_ERR(tfm);
+		goto out;
+	}
+	req = ahash_request_alloc(tfm, GFP_ATOMIC);
+	if (!req)
+		err = -EFAULT;
+		goto out;
+
+	sg_init_table(sg, 2);
+	sg_set_buf(&sg[0], secret, SHA_MESSAGE_BYTES);
+	sg_set_buf(&sg[1], payload, len);
+
+	ahash_request_set_callback(req, 0, NULL, NULL);
+	ahash_request_set_crypt(req, sg, (u8 *)h, SHA_MESSAGE_BYTES + len);
+
+	if (crypto_ahash_digest(req)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	*hash = be16_to_cpu(h[0]);
+	for (i = 1; i < MD5_DIGEST_WORDS * 2; i++)
+		*hash ^= be16_to_cpu(h[i]);
+
+out:
+	ahash_request_free(req);
+	crypto_free_ahash(tfm);
+	return err;
+}
+#endif
+
 /*
  *	Socket option code for TCP.
  */
@@ -2519,6 +2563,66 @@
 		release_sock(sk);
 		return err;
 	}
+#ifdef CONFIG_TCP_STEALTH
+	case TCP_STEALTH: {
+		u8 secret[SHA_MESSAGE_BYTES] = { 0 };
+
+		val = copy_from_user(secret, optval,
+				     min_t(unsigned int, optlen,
+					   SHA_MESSAGE_BYTES));
+		if (val != 0)
+			return -EFAULT;
+
+		lock_sock(sk);
+		memcpy(tp->stealth.secret, secret, SHA_MESSAGE_BYTES);
+		tp->stealth.mode = TCP_STEALTH_MODE_AUTH;
+		tp->stealth.mstamp.v64 = 0;
+		tp->stealth.saw_tsval = false;
+		release_sock(sk);
+		return err;
+	}
+	case TCP_STEALTH_INTEGRITY: {
+		u8 *payload;
+
+		lock_sock(sk);
+
+		if (!(tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
+			err = -EOPNOTSUPP;
+			goto stealth_integrity_out_1;
+		}
+
+		if (optlen < 1 || optlen > USHRT_MAX) {
+			err = -EINVAL;
+			goto stealth_integrity_out_1;
+		}
+
+		payload = vmalloc(optlen);
+		if (!payload) {
+			err = -ENOMEM;
+			goto stealth_integrity_out_1;
+		}
+
+		val = copy_from_user(payload, optval, optlen);
+		if (val != 0) {
+			err = -EFAULT;
+			goto stealth_integrity_out_2;
+		}
+
+		err = tcp_stealth_integrity(&tp->stealth.integrity_hash,
+					    tp->stealth.secret, payload,
+					    optlen);
+		if (err)
+			goto stealth_integrity_out_2;
+
+		tp->stealth.mode |= TCP_STEALTH_MODE_INTEGRITY;
+
+stealth_integrity_out_2:
+		vfree(payload);
+stealth_integrity_out_1:
+		release_sock(sk);
+		return err;
+	}
+#endif
 	default:
 		/* fallthru */
 		break;
@@ -2782,6 +2886,18 @@
 		tp->notsent_lowat = val;
 		sk->sk_write_space(sk);
 		break;
+#ifdef CONFIG_TCP_STEALTH
+	case TCP_STEALTH_INTEGRITY_LEN:
+		if (!(tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
+			err = -EOPNOTSUPP;
+		} else if (val < 1 || val > USHRT_MAX) {
+			err = -EINVAL;
+		} else {
+			tp->stealth.integrity_len = val;
+			tp->stealth.mode |= TCP_STEALTH_MODE_INTEGRITY_LEN;
+		}
+		break;
+#endif
 	default:
 		err = -ENOPROTOOPT;
 		break;
diff -u -r linux-4.14.13.orig/net/ipv4/tcp_input.c linux-4.14.13/net/ipv4/tcp_input.c
--- linux-4.14.13.orig/net/ipv4/tcp_input.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv4/tcp_input.c	2018-01-14 18:53:56.000000000 +0100
@@ -3892,6 +3892,47 @@
 	return true;
 }
 
+#ifdef CONFIG_TCP_STEALTH
+/* Parse only the TSVal field of the TCP Timestamp option header.
+ */
+const bool tcp_parse_tsval_option(u32 *tsval, const struct tcphdr *th)
+{
+	int length = (th->doff << 2) - sizeof(*th);
+	const u8 *ptr = (const u8 *)(th + 1);
+
+	/* If the TCP option is too short, we can short cut */
+	if (length < TCPOLEN_TIMESTAMP)
+		return false;
+
+	while (length > 0) {
+		int opcode = *ptr++;
+		int opsize;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return false;
+		case TCPOPT_NOP:
+			length--;
+			continue;
+		case TCPOPT_TIMESTAMP:
+			opsize = *ptr++;
+			if (opsize != TCPOLEN_TIMESTAMP || opsize > length)
+				return false;
+			*tsval = get_unaligned_be32(ptr);
+			return true;
+		default:
+			opsize = *ptr++;
+			if (opsize < 2 || opsize > length)
+				return false;
+		}
+		ptr += opsize - 2;
+		length -= opsize;
+	}
+	return false;
+}
+EXPORT_SYMBOL(tcp_parse_tsval_option);
+#endif
+
 #ifdef CONFIG_TCP_MD5SIG
 /*
  * Parse MD5 Signature option
@@ -4625,6 +4666,31 @@
 
 }
 
+#ifdef CONFIG_TCP_STEALTH
+static int __tcp_stealth_integrity_check(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcphdr *th = tcp_hdr(skb);
+	struct tcp_sock *tp = tcp_sk(sk);
+	u16 hash;
+	__be32 seq = cpu_to_be32(TCP_SKB_CB(skb)->seq - 1);
+	char *data = skb->data + th->doff * 4;
+	int len = skb->len - th->doff * 4;
+
+	if (len < tp->stealth.integrity_len)
+		return 1;
+
+	if (tcp_stealth_integrity(&hash, tp->stealth.secret, data,
+				  tp->stealth.integrity_len))
+		return 1;
+
+	if (be32_isn_to_be16_ih(seq) != cpu_to_be16(hash))
+		return 1;
+
+	tp->stealth.mode &= ~TCP_STEALTH_MODE_INTEGRITY_LEN;
+	return 0;
+}
+#endif
+
 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -4635,6 +4701,15 @@
 		__kfree_skb(skb);
 		return;
 	}
+
+#ifdef CONFIG_TCP_STEALTH
+	if (unlikely(tp->stealth.mode & TCP_STEALTH_MODE_INTEGRITY_LEN) &&
+	    __tcp_stealth_integrity_check(sk, skb)) {
+		tcp_reset(sk);
+		goto drop;
+	}
+#endif
+
 	skb_dst_drop(skb);
 	__skb_pull(skb, tcp_hdr(skb)->doff * 4);
 
@@ -5447,6 +5522,15 @@
 			int eaten = 0;
 			bool fragstolen = false;
 
+#ifdef CONFIG_TCP_STEALTH
+			if (unlikely(tp->stealth.mode &
+				     TCP_STEALTH_MODE_INTEGRITY_LEN) &&
+			    __tcp_stealth_integrity_check(sk, skb)) {
+				tcp_reset(sk);
+				goto discard;
+			}
+#endif
+
 			if (tcp_checksum_complete(skb))
 				goto csum_error;
 
diff -u -r linux-4.14.13.orig/net/ipv4/tcp_ipv4.c linux-4.14.13/net/ipv4/tcp_ipv4.c
--- linux-4.14.13.orig/net/ipv4/tcp_ipv4.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv4/tcp_ipv4.c	2018-01-14 18:46:57.000000000 +0100
@@ -74,6 +74,7 @@
 #include <net/xfrm.h>
 #include <net/secure_seq.h>
 #include <net/busy_poll.h>
+#include <net/secure_seq.h>
 
 #include <linux/inet.h>
 #include <linux/ipv6.h>
@@ -234,6 +235,21 @@
 	sk_setup_caps(sk, &rt->dst);
 	rt = NULL;
 
+#ifdef CONFIG_TCP_STEALTH
+	/* If CONFIG_TCP_STEALTH is defined, we need to know the timestamp as
+	 * early as possible and thus move taking the snapshot of tcp_time_stamp
+	 * here.
+	 */
+	skb_mstamp_get(&tp->stealth.mstamp);
+
+	if (!tp->write_seq && likely(!tp->repair) &&
+		unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH))
+			tp->write_seq = tcp_stealth_sequence_number(sk,
+								    &inet->inet_daddr,
+								    sizeof(inet->inet_daddr),
+								    usin->sin_port);
+#endif
+
 	if (likely(!tp->repair)) {
 		if (!tp->write_seq)
 			tp->write_seq = secure_tcp_seq(inet->inet_saddr,
@@ -1447,6 +1463,8 @@
  */
 int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct tcphdr *th = tcp_hdr(skb);
 	struct sock *rsk;
 
 	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
@@ -1468,6 +1486,15 @@
 	if (tcp_checksum_complete(skb))
 		goto csum_err;
 
+#ifdef CONFIG_TCP_STEALTH
+	if (sk->sk_state == TCP_LISTEN && th->syn && !th->fin &&
+	    unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH) &&
+	    tcp_stealth_do_auth(sk, skb)) {
+		rsk = sk;
+		goto reset;
+	}
+#endif
+
 	if (sk->sk_state == TCP_LISTEN) {
 		struct sock *nsk = tcp_v4_cookie_check(sk, skb);
 
diff -u -r linux-4.14.13.orig/net/ipv4/tcp_output.c linux-4.14.13/net/ipv4/tcp_output.c
--- linux-4.14.13.orig/net/ipv4/tcp_output.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv4/tcp_output.c	2018-01-14 18:46:57.000000000 +0100
@@ -1018,6 +1018,13 @@
 	tcb = TCP_SKB_CB(skb);
 	memset(&opts, 0, sizeof(opts));
 
+#ifdef TCP_STEALTH
+	if (unlikely(tcb->tcp_flags & TCPHDR_SYN &&
+		     tp->stealth.mode & TCP_STEALTH_MODE_AUTH)) {
+		skb->skb_mstamp = tp->stealth.mstamp;
+	}
+#endif
+
 	if (unlikely(tcb->tcp_flags & TCPHDR_SYN))
 		tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
 	else
@@ -3432,7 +3439,15 @@
 
 	tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
 	tcp_mstamp_refresh(tp);
+#ifdef CONFIG_TCP_STEALTH
+	/* The timetamp was already made at the time the ISN was generated
+	 * as we need to know its value in the stealth_tcp_sequence_number()
+	 * function.
+	 */
+	tp->retrans_stamp = tp->stealth.mstamp.stamp_jiffies;
+#else
 	tp->retrans_stamp = tcp_time_stamp(tp);
+#endif
 	tcp_connect_queue_skb(sk, buff);
 	tcp_ecn_send_syn(sk, buff);
 
diff -u -r linux-4.14.13.orig/net/ipv6/tcp_ipv6.c linux-4.14.13/net/ipv6/tcp_ipv6.c
--- linux-4.14.13.orig/net/ipv6/tcp_ipv6.c	2018-01-10 09:31:23.000000000 +0100
+++ linux-4.14.13/net/ipv6/tcp_ipv6.c	2018-01-14 18:46:57.000000000 +0100
@@ -62,6 +62,7 @@
 #include <net/inet_common.h>
 #include <net/secure_seq.h>
 #include <net/busy_poll.h>
+#include <net/secure_seq.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -286,6 +287,21 @@
 
 	sk_set_txhash(sk);
 
+#ifdef CONFIG_TCP_STEALTH
+	/* If CONFIG_TCP_STEALTH is defined, we need to know the timestamp as
+	 * early as possible and thus move taking the snapshot of tcp_time_stamp
+	 * here.
+	 */
+	skb_mstamp_get(&tp->stealth.mstamp);
+
+	if (!tp->write_seq && likely(!tp->repair) &&
+		unlikely(tp->stealth.mode & TCP_STEALTH_MODE_AUTH))
+			tp->write_seq = tcp_stealth_sequence_number(sk,
+								    sk->sk_v6_daddr.s6_addr32,
+								    sizeof(sk->sk_v6_daddr),
+								    inet->inet_dport);
+#endif
+
 	if (likely(!tp->repair)) {
 		if (!tp->write_seq)
 			tp->write_seq = secure_tcpv6_seq(np->saddr.s6_addr32,
@@ -1249,7 +1265,8 @@
 static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
-	struct tcp_sock *tp;
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct tcphdr *th = tcp_hdr(skb);
 	struct sk_buff *opt_skb = NULL;
 
 	/* Imagine: socket is IPv6. IPv4 packet arrives,
@@ -1306,6 +1323,13 @@
 	if (tcp_checksum_complete(skb))
 		goto csum_err;
 
+#ifdef CONFIG_TCP_STEALTH
+	if (sk->sk_state == TCP_LISTEN && th->syn && !th->fin &&
+	    tp->stealth.mode & TCP_STEALTH_MODE_AUTH &&
+	    tcp_stealth_do_auth(sk, skb))
+		goto reset;
+#endif
+
 	if (sk->sk_state == TCP_LISTEN) {
 		struct sock *nsk = tcp_v6_cookie_check(sk, skb);
 

Reply to: