From: William Allen Simpson <william.allen.simpson@gmail.com>
To: Linux Kernel Network Developers <netdev@vger.kernel.org>
Subject: [net-next-2.6 PATCH RFC] TCPCT part 1d: generate Responder Cookie
Date: Fri, 30 Oct 2009 07:00:51 -0400 [thread overview]
Message-ID: <4AEAC763.4070200@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 437 bytes --]
First of all, this is my first attempt at locks, so I'd like early review.
Secondly, scripts/checkpatch.pl tells me:
ERROR: do not initialise statics to 0 or NULL
#95: FILE: net/ipv4/tcp.c:2977:
+static struct tcp_cookie_secret *tcp_secret_generating = NULL;
They need to be NULL, and I'm not planning on exporting them, so what's
the preferred mechanism?
(I've grep'd many other instances of statics = 0 or NULL, so I'm not alone.)
[-- Attachment #2: TCPCT-1d.patch --]
[-- Type: text/plain, Size: 6070 bytes --]
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
index c118b2a..ec78a4b 100644
--- a/include/linux/cryptohash.h
+++ b/include/linux/cryptohash.h
@@ -2,6 +2,7 @@
#define __CRYPTOHASH_H
#define SHA_DIGEST_WORDS 5
+#define SHA_MESSAGE_BYTES (512 /*bits*/ / 8)
#define SHA_WORKSPACE_WORDS 80
void sha_init(__u32 *buf);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 51b7426..f669c43 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1526,12 +1526,18 @@ static inline int tcp_s_data_size(const struct tcp_sock *tp)
: 0;
}
+/* Using SHA1 for now, define some constants.
+ */
+#define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS)
+#define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4)
+#define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS)
+
/* As tcp_request_sock has already been extended in other places, the
* only remaining method is to pass stack values along as function
* parameters. These parameters are not needed after sending SYNACK.
*/
struct tcp_extend_values {
- u8 cookie_bakery[TCP_COOKIE_MAX];
+ u32 cookie_bakery[COOKIE_WORKSPACE_WORDS];
u8 cookie_plus;
u8 cookie_in_always:1,
cookie_out_never:1;
@@ -1542,6 +1548,8 @@ static inline struct tcp_extend_values *tcp_xv(const struct request_values *rvp)
return (struct tcp_extend_values *)rvp;
}
+extern int tcp_cookie_generator(struct tcp_extend_values *xvp);
+
extern void tcp_v4_init(void);
extern void tcp_init(void);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 12409df..32f8711 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2933,6 +2933,126 @@ EXPORT_SYMBOL(tcp_md5_hash_key);
#endif
+/**
+ * Each Responder maintains up to two secret values concurrently for
+ * efficient secret rollover. Each secret value has 4 states:
+ *
+ * Generating.
+ * Generates new Responder-Cookies, but not yet used for primary
+ * verification. This is a short-term state, typically lasting only
+ * one round trip time (RTT).
+ *
+ * Primary.
+ * Used both for generation and primary verification.
+ *
+ * Retiring.
+ * Used for verification, until the first failure that can be
+ * verified by the newer Generating secret. At that time, this
+ * cookie's state is changed to Secondary, and the Generating
+ * cookie's state is changed to Primary. This is a short-term state,
+ * typically lasting only one round trip time (RTT).
+ *
+ * Secondary.
+ * Used for secondary verification, after primary verification
+ * failures. This state lasts no more than twice the Maximum Segment
+ * Lifetime (2MSL). Then, the secret is discarded.
+ */
+struct tcp_cookie_secret {
+ /* The secret is divided into two parts. The digest part is the
+ * equivalent of previously hashing a secret and saving the state,
+ * and serves as an initialization vector (IV). The message part
+ * serves as the trailing secret.
+ */
+ u32 secrets[COOKIE_WORKSPACE_WORDS];
+ unsigned long expires;
+};
+
+#define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL)
+#define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2)
+#define TCP_SECRET_LIFE (HZ * 600)
+
+static struct tcp_cookie_secret tcp_secret_one;
+static struct tcp_cookie_secret tcp_secret_two;
+
+static struct tcp_cookie_secret *tcp_secret_generating = NULL;
+static struct tcp_cookie_secret *tcp_secret_primary = NULL;
+static struct tcp_cookie_secret *tcp_secret_retiring = NULL;
+static struct tcp_cookie_secret *tcp_secret_secondary = NULL;
+
+static DEFINE_RWLOCK(tcp_secret_locker);
+
+/* Fill cookie_bakery with current generator.
+ * Returns: 0 o success.
+ */
+int tcp_cookie_generator(struct tcp_extend_values *xvp)
+{
+ u32 secrets[COOKIE_WORKSPACE_WORDS];
+
+ if (unlikely(NULL == tcp_secret_primary)) {
+ get_random_bytes(secrets, sizeof(secrets));
+
+ /* The first time, paranoia assumes that the randomization
+ * function isn't as strong. But this secret initialization
+ * is delayed until the last possible moment (packet arrival).
+ * Although that time is observable, it is unpredictably
+ * variable. Mash in the fastest clock bits available, and
+ * expire the secret extra quickly.
+ */
+ secrets[COOKIE_DIGEST_WORDS] ^= (u32)jiffies;
+
+ write_lock(&tcp_secret_locker);
+ if (NULL == tcp_secret_primary) {
+ /* still needs initialization */
+ memcpy((u8 *)&tcp_secret_one.secrets[0],
+ (u8 *)&secrets[0],
+ sizeof(secrets));
+ tcp_secret_one.expires = jiffies + TCP_SECRET_1MSL;
+ tcp_secret_primary = &tcp_secret_one;
+ /* unused at this time */
+ memcpy((u8 *)&tcp_secret_two.secrets[0],
+ (u8 *)&secrets[0],
+ sizeof(secrets));
+ tcp_secret_two.expires = jiffies; /* past due */
+ tcp_secret_secondary = &tcp_secret_two;
+ }
+ write_unlock(&tcp_secret_locker);
+ }
+
+ if (unlikely(time_after(jiffies, tcp_secret_primary->expires))) {
+ get_random_bytes(secrets, sizeof(secrets));
+
+ write_lock(&tcp_secret_locker);
+ if (time_after(jiffies, tcp_secret_primary->expires)) {
+ /* still needs refreshing */
+ tcp_secret_primary->expires = jiffies
+ + TCP_SECRET_2MSL;
+ tcp_secret_retiring = tcp_secret_primary;
+ /* new generator at secondary position */
+ memcpy((u8 *)&tcp_secret_secondary->secrets[0],
+ (u8 *)&secrets[0],
+ sizeof(secrets));
+ tcp_secret_secondary->expires = jiffies
+ + TCP_SECRET_LIFE;
+ tcp_secret_generating = tcp_secret_secondary;
+ }
+ write_unlock(&tcp_secret_locker);
+ }
+
+ read_lock(&tcp_secret_locker);
+ if (unlikely(NULL != tcp_secret_generating)) {
+ memcpy((u8 *)&xvp->cookie_bakery[0],
+ (u8 *)&tcp_secret_generating->secrets[0],
+ sizeof(tcp_secret_generating->secrets));
+ } else {
+ memcpy((u8 *)&xvp->cookie_bakery[0],
+ (u8 *)&tcp_secret_primary->secrets[0],
+ sizeof(tcp_secret_primary->secrets));
+ }
+ read_unlock(&tcp_secret_locker);
+ return 0;
+}
+EXPORT_SYMBOL(tcp_cookie_generator);
+
void tcp_done(struct sock *sk)
{
if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
next reply other threads:[~2009-10-30 11:00 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-30 11:00 William Allen Simpson [this message]
2009-10-30 18:11 ` [net-next-2.6 PATCH RFC] TCPCT part 1d: generate Responder Cookie William Allen Simpson
2009-11-01 13:01 ` William Allen Simpson
2009-11-01 18:03 ` Eric Dumazet
2009-11-02 10:39 ` William Allen Simpson
2009-11-02 10:50 ` David Miller
2009-11-02 10:56 ` Eric Dumazet
2009-11-02 12:36 ` William Allen Simpson
2009-11-02 13:16 ` Eric Dumazet
2009-11-02 17:21 ` William Allen Simpson
2009-11-02 17:42 ` Eric Dumazet
2009-11-03 22:38 ` William Allen Simpson
2009-11-03 23:03 ` Eric Dumazet
2009-11-04 21:48 ` Paul E. McKenney
2009-11-05 12:17 ` William Allen Simpson
2009-11-05 12:45 ` William Allen Simpson
2009-11-05 13:34 ` Eric Dumazet
2009-11-05 13:19 ` Eric Dumazet
2009-11-05 19:44 ` William Allen Simpson
2009-11-05 14:59 ` Paul E. McKenney
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=4AEAC763.4070200@gmail.com \
--to=william.allen.simpson@gmail.com \
--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).