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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.