From: Julian Kirsch <kirschju@sec.in.tum.de>
To: netdev@vger.kernel.org
Cc: Christian Grothoff <christian@grothoff.org>,
Jacob Appelbaum <jacob@appelbaum.net>
Subject: [PATCH] TCP: Add support for TCP Stealth
Date: Wed, 31 Dec 2014 22:54:59 +0100 [thread overview]
Message-ID: <54A470B3.3010501@sec.in.tum.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 2090 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
one year ago [0] we tried to convince you to add support for a new
socket option to the linux kernel. Equipped with an improved version of
our patch we're back to accomplish this task today. :-)
TCP Stealth is a modern variant of port knocking which borrows
techniques from network steganography to enable clients to authenticate
themselves towards a server on TCP level. You can find technical details
in an rfc draft we wrote earlier this year [1] and in my master's thesis
[2]. In summary, TCP Stealth derives authentication information from a
pre-shared secret and embeds it into the ISN sent along with the first
SYN from the client.
Our motivation is simple: During this year we gained hard evidence on
secret services actively port scanning the internets followed by
exploitation of your services using 0-day exploits [3, 4]. We don't want
our machines to be turned into relays from where they continue to
cascade their attacks. TCP Stealth makes port scanning more expensive by
a factor of 2^31 (on average).
A copy of this patch as well as patches for several user space
applications can be found on the project's home page [5].
All the best for the upcoming year,
Julian & Christian
[0] https://lkml.org/lkml/2013/12/10/1155
[1] https://datatracker.ietf.org/doc/draft-kirsch-ietf-tcp-stealth/
[2] https://gnunet.org/kirsch2014knock
[3]
http://www.heise.de/ct/artikel/NSA-GCHQ-The-HACIENDA-Program-for-Internet-Colonization-2292681.html
[4]
https://firstlook.org/theintercept/2014/12/13/belgacom-hack-gchq-inside-story/
[5] https://gnunet.org/knock
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAEBAgAGBQJUpHCvAAoJENwkOWttRRA4g10IALbJZU9/5Gp8tVdpXqbkOIMp
Kz+yOMyYULqYeM8yguSBZjZLbaz/VAS7SNpQxKGU+W0aAXa22FsSfVoUU7wqp3NT
3EGRuPkMaJkQ66IP8MtX+6/hSeWSh78tEaIFWVjyutihPyQGz0LefFc66gm54X4T
s8IYW7jKFhNmmROu9CXLTxq4B5t2v+Evv/qWqotZqR1t3IbIUmZAiKrlkMRd7dtM
SaS5JwFeiObxn+0M/7javQCAhfgPXYEOU0QKAGY55MXcPAner/5PuExIZdOJ41R3
XD9tgoLGhHEiQkxj0/bP2cs3Cl5xfJl9t2iecVfTIR7PytaTJ/kFuE4gNgWEcTA=
=T6/C
-----END PGP SIGNATURE-----
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tcp_stealth_3.18.diff --]
[-- Type: text/x-patch; name="tcp_stealth_3.18.diff", Size: 19140 bytes --]
Signed-off-by: Julian Kirsch <kirschju@sec.in.tum.de>
diff -Nurp linux-3.18-rc3/include/linux/tcp.h linux-3.18-rc3-knock/include/linux/tcp.h
--- linux-3.18-rc3/include/linux/tcp.h 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/include/linux/tcp.h 2014-11-06 21:26:34.976017001 +0100
@@ -19,6 +19,7 @@
#include <linux/skbuff.h>
+#include <linux/cryptohash.h>
#include <net/sock.h>
#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
@@ -309,6 +310,21 @@ struct tcp_sock {
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)
+ int mode;
+ u8 secret[MD5_MESSAGE_BYTES];
+ int integrity_len;
+ u16 integrity_hash;
+ 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 -Nurp linux-3.18-rc3/include/net/secure_seq.h linux-3.18-rc3-knock/include/net/secure_seq.h
--- linux-3.18-rc3/include/net/secure_seq.h 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/include/net/secure_seq.h 2014-11-06 21:26:34.976017001 +0100
@@ -14,5 +14,10 @@ u64 secure_dccp_sequence_number(__be32 s
__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 -Nurp linux-3.18-rc3/include/net/tcp.h linux-3.18-rc3-knock/include/net/tcp.h
--- linux-3.18-rc3/include/net/tcp.h 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/include/net/tcp.h 2014-11-06 21:26:34.976017001 +0100
@@ -439,6 +439,12 @@ void tcp_parse_options(const struct sk_b
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 -Nurp linux-3.18-rc3/include/uapi/linux/tcp.h linux-3.18-rc3-knock/include/uapi/linux/tcp.h
--- linux-3.18-rc3/include/uapi/linux/tcp.h 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/include/uapi/linux/tcp.h 2014-11-06 21:26:34.976017001 +0100
@@ -112,6 +112,9 @@ enum {
#define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */
#define TCP_TIMESTAMP 24
#define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */
+#define TCP_STEALTH 26
+#define TCP_STEALTH_INTEGRITY 27
+#define TCP_STEALTH_INTEGRITY_LEN 28
struct tcp_repair_opt {
__u32 opt_code;
diff -Nurp linux-3.18-rc3/net/core/secure_seq.c linux-3.18-rc3-knock/net/core/secure_seq.c
--- linux-3.18-rc3/net/core/secure_seq.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/core/secure_seq.c 2014-11-24 14:31:20.227872751 +0100
@@ -8,7 +8,11 @@
#include <linux/ktime.h>
#include <linux/string.h>
#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/tcp.h>
#include <net/secure_seq.h>
#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
@@ -39,6 +43,103 @@ static u32 seq_scale(u32 seq)
}
#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[MD5_MESSAGE_BYTES / sizeof(__u32)];
+ __u32 i;
+ __u32 tsval = 0;
+
+ __be32 iv[MD5_DIGEST_WORDS] = { 0 };
+ __be32 isn;
+
+ memcpy(iv, (const __u8 *)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 < MD5_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_sequence_number(const __be32 *saddr, const __be32 *daddr,
__be16 sport, __be16 dport)
diff -Nurp linux-3.18-rc3/net/ipv4/Kconfig linux-3.18-rc3-knock/net/ipv4/Kconfig
--- linux-3.18-rc3/net/ipv4/Kconfig 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv4/Kconfig 2014-11-06 21:26:34.976017001 +0100
@@ -671,3 +671,13 @@ config TCP_MD5SIG
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 -Nurp linux-3.18-rc3/net/ipv4/tcp.c linux-3.18-rc3-knock/net/ipv4/tcp.c
--- linux-3.18-rc3/net/ipv4/tcp.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv4/tcp.c 2014-11-24 11:44:39.700059516 +0100
@@ -2329,6 +2329,43 @@ static int tcp_repair_options_est(struct
return 0;
}
+#ifdef CONFIG_TCP_STEALTH
+int tcp_stealth_integrity(__be16 *hash, u8 *secret, u8 *payload, int len)
+{
+ struct scatterlist sg[2];
+ struct crypto_hash *tfm;
+ struct hash_desc desc;
+ __be16 h[MD5_DIGEST_WORDS * 2];
+ int i;
+ int err = 0;
+
+ tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ err = -PTR_ERR(tfm);
+ goto out;
+ }
+ desc.tfm = tfm;
+ desc.flags = 0;
+
+ sg_init_table(sg, 2);
+ sg_set_buf(&sg[0], secret, MD5_MESSAGE_BYTES);
+ sg_set_buf(&sg[1], payload, len);
+
+ if (crypto_hash_digest(&desc, sg, MD5_MESSAGE_BYTES + len, (u8 *)h)) {
+ 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:
+ crypto_free_hash(tfm);
+ return err;
+}
+#endif
+
/*
* Socket option code for TCP.
*/
@@ -2359,6 +2396,67 @@ static int do_tcp_setsockopt(struct sock
release_sock(sk);
return err;
}
+#ifdef CONFIG_TCP_STEALTH
+ case TCP_STEALTH: {
+ u8 secret[MD5_MESSAGE_BYTES] = { 0 };
+
+ val = copy_from_user(secret, optval,
+ min_t(unsigned int, optlen,
+ MD5_MESSAGE_BYTES));
+
+ if (val != 0)
+ return -EFAULT;
+
+ lock_sock(sk);
+ memcpy(tp->stealth.secret, secret, MD5_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;
@@ -2600,6 +2698,18 @@ static int do_tcp_setsockopt(struct sock
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 -Nurp linux-3.18-rc3/net/ipv4/tcp_input.c linux-3.18-rc3-knock/net/ipv4/tcp_input.c
--- linux-3.18-rc3/net/ipv4/tcp_input.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv4/tcp_input.c 2014-11-06 21:26:34.976017001 +0100
@@ -77,6 +77,9 @@
#include <linux/errqueue.h>
int sysctl_tcp_timestamps __read_mostly = 1;
+#ifdef CONFIG_TCP_STEALTH
+EXPORT_SYMBOL(sysctl_tcp_timestamps);
+#endif
int sysctl_tcp_window_scaling __read_mostly = 1;
int sysctl_tcp_sack __read_mostly = 1;
int sysctl_tcp_fack __read_mostly = 1;
@@ -3715,6 +3718,47 @@ static bool tcp_fast_parse_options(const
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
@@ -4384,6 +4428,31 @@ err:
return -ENOMEM;
}
+#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);
@@ -4393,6 +4462,14 @@ static void tcp_data_queue(struct sock *
if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
goto drop;
+#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);
@@ -5156,6 +5233,15 @@ void tcp_rcv_established(struct sock *sk
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 (tp->ucopy.task == current &&
tp->copied_seq == tp->rcv_nxt &&
len - tcp_header_len <= tp->ucopy.len &&
diff -Nurp linux-3.18-rc3/net/ipv4/tcp_ipv4.c linux-3.18-rc3-knock/net/ipv4/tcp_ipv4.c
--- linux-3.18-rc3/net/ipv4/tcp_ipv4.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv4/tcp_ipv4.c 2014-11-06 21:26:34.976017001 +0100
@@ -75,6 +75,7 @@
#include <net/secure_seq.h>
#include <net/tcp_memcontrol.h>
#include <net/busy_poll.h>
+#include <net/secure_seq.h>
#include <linux/inet.h>
#include <linux/ipv6.h>
@@ -235,6 +236,21 @@ int tcp_v4_connect(struct sock *sk, stru
sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
+#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 (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
@@ -1423,6 +1439,8 @@ static struct sock *tcp_v4_hnd_req(struc
*/
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 */
@@ -1443,6 +1461,15 @@ int tcp_v4_do_rcv(struct sock *sk, struc
if (skb->len < tcp_hdrlen(skb) || 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_hnd_req(sk, skb);
if (!nsk)
diff -Nurp linux-3.18-rc3/net/ipv4/tcp_output.c linux-3.18-rc3-knock/net/ipv4/tcp_output.c
--- linux-3.18-rc3/net/ipv4/tcp_output.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv4/tcp_output.c 2014-11-24 14:29:25.380852760 +0100
@@ -915,6 +915,13 @@ static int tcp_transmit_skb(struct sock
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
@@ -3109,7 +3116,15 @@ int tcp_connect(struct sock *sk)
skb_reserve(buff, MAX_TCP_HEADER);
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
+#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;
+#endif
tcp_connect_queue_skb(sk, buff);
tcp_ecn_send_syn(sk, buff);
diff -Nurp linux-3.18-rc3/net/ipv6/tcp_ipv6.c linux-3.18-rc3-knock/net/ipv6/tcp_ipv6.c
--- linux-3.18-rc3/net/ipv6/tcp_ipv6.c 2014-11-03 00:01:51.000000000 +0100
+++ linux-3.18-rc3-knock/net/ipv6/tcp_ipv6.c 2014-11-06 21:26:34.976017001 +0100
@@ -63,6 +63,7 @@
#include <net/secure_seq.h>
#include <net/tcp_memcontrol.h>
#include <net/busy_poll.h>
+#include <net/secure_seq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -297,6 +298,21 @@ static int tcp_v6_connect(struct sock *s
ip6_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 (!tp->write_seq && likely(!tp->repair))
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
sk->sk_v6_daddr.s6_addr32,
@@ -1251,7 +1267,8 @@ out:
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,
@@ -1310,6 +1327,13 @@ static int tcp_v6_do_rcv(struct sock *sk
if (skb->len < tcp_hdrlen(skb) || 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_hnd_req(sk, skb);
if (!nsk)
[-- Attachment #3: tcp_stealth_3.18.diff.sig --]
[-- Type: application/pgp-signature, Size: 287 bytes --]
next reply other threads:[~2014-12-31 22:00 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-31 21:54 Julian Kirsch [this message]
2015-01-01 15:25 ` [PATCH] TCP: Add support for TCP Stealth Daniel Borkmann
2015-01-01 15:32 ` Christian Grothoff
2015-01-02 12:50 ` Daniel Borkmann
2015-01-02 14:06 ` Christian Grothoff
2015-01-01 19:06 ` Stephen Hemminger
2015-01-01 19:10 ` Stephen Hemminger
2015-01-01 23:31 ` Julian Kirsch
2015-01-02 10:36 ` Hagen Paul Pfeifer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54A470B3.3010501@sec.in.tum.de \
--to=kirschju@sec.in.tum.de \
--cc=christian@grothoff.org \
--cc=jacob@appelbaum.net \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).