aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorWilliam Allen Simpson <william.allen.simpson@gmail.com>2009-12-02 13:12:09 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-03 01:07:23 -0500
commitda5c78c82629a167794436e4306b4cf1faddea90 (patch)
treec933fdc0583b592c01885890ebf770840555d28b /net
parente6b4d11367519bc71729c09d05a126b133c755be (diff)
TCPCT part 1b: generate Responder Cookie secret
Define (missing) hash message size for SHA1. Define hashing size constants specific to TCP cookies. Add new function: tcp_cookie_generator(). Maintain global secret values for tcp_cookie_generator(). This is a significantly revised implementation of earlier (15-year-old) Photuris [RFC-2522] code for the KA9Q cooperative multitasking platform. Linux RCU technique appears to be well-suited to this application, though neither of the circular queue items are freed. These functions will also be used in subsequent patches that implement additional features. Signed-off-by: William.Allen.Simpson@gmail.com Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7d4648f8b3d3..ba03ac80435a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -264,6 +264,7 @@
264#include <linux/cache.h> 264#include <linux/cache.h>
265#include <linux/err.h> 265#include <linux/err.h>
266#include <linux/crypto.h> 266#include <linux/crypto.h>
267#include <linux/time.h>
267 268
268#include <net/icmp.h> 269#include <net/icmp.h>
269#include <net/tcp.h> 270#include <net/tcp.h>
@@ -2848,6 +2849,135 @@ EXPORT_SYMBOL(tcp_md5_hash_key);
2848 2849
2849#endif 2850#endif
2850 2851
2852/**
2853 * Each Responder maintains up to two secret values concurrently for
2854 * efficient secret rollover. Each secret value has 4 states:
2855 *
2856 * Generating. (tcp_secret_generating != tcp_secret_primary)
2857 * Generates new Responder-Cookies, but not yet used for primary
2858 * verification. This is a short-term state, typically lasting only
2859 * one round trip time (RTT).
2860 *
2861 * Primary. (tcp_secret_generating == tcp_secret_primary)
2862 * Used both for generation and primary verification.
2863 *
2864 * Retiring. (tcp_secret_retiring != tcp_secret_secondary)
2865 * Used for verification, until the first failure that can be
2866 * verified by the newer Generating secret. At that time, this
2867 * cookie's state is changed to Secondary, and the Generating
2868 * cookie's state is changed to Primary. This is a short-term state,
2869 * typically lasting only one round trip time (RTT).
2870 *
2871 * Secondary. (tcp_secret_retiring == tcp_secret_secondary)
2872 * Used for secondary verification, after primary verification
2873 * failures. This state lasts no more than twice the Maximum Segment
2874 * Lifetime (2MSL). Then, the secret is discarded.
2875 */
2876struct tcp_cookie_secret {
2877 /* The secret is divided into two parts. The digest part is the
2878 * equivalent of previously hashing a secret and saving the state,
2879 * and serves as an initialization vector (IV). The message part
2880 * serves as the trailing secret.
2881 */
2882 u32 secrets[COOKIE_WORKSPACE_WORDS];
2883 unsigned long expires;
2884};
2885
2886#define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL)
2887#define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2)
2888#define TCP_SECRET_LIFE (HZ * 600)
2889
2890static struct tcp_cookie_secret tcp_secret_one;
2891static struct tcp_cookie_secret tcp_secret_two;
2892
2893/* Essentially a circular list, without dynamic allocation. */
2894static struct tcp_cookie_secret *tcp_secret_generating;
2895static struct tcp_cookie_secret *tcp_secret_primary;
2896static struct tcp_cookie_secret *tcp_secret_retiring;
2897static struct tcp_cookie_secret *tcp_secret_secondary;
2898
2899static DEFINE_SPINLOCK(tcp_secret_locker);
2900
2901/* Select a pseudo-random word in the cookie workspace.
2902 */
2903static inline u32 tcp_cookie_work(const u32 *ws, const int n)
2904{
2905 return ws[COOKIE_DIGEST_WORDS + ((COOKIE_MESSAGE_WORDS-1) & ws[n])];
2906}
2907
2908/* Fill bakery[COOKIE_WORKSPACE_WORDS] with generator, updating as needed.
2909 * Called in softirq context.
2910 * Returns: 0 for success.
2911 */
2912int tcp_cookie_generator(u32 *bakery)
2913{
2914 unsigned long jiffy = jiffies;
2915
2916 if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
2917 spin_lock_bh(&tcp_secret_locker);
2918 if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
2919 /* refreshed by another */
2920 memcpy(bakery,
2921 &tcp_secret_generating->secrets[0],
2922 COOKIE_WORKSPACE_WORDS);
2923 } else {
2924 /* still needs refreshing */
2925 get_random_bytes(bakery, COOKIE_WORKSPACE_WORDS);
2926
2927 /* The first time, paranoia assumes that the
2928 * randomization function isn't as strong. But,
2929 * this secret initialization is delayed until
2930 * the last possible moment (packet arrival).
2931 * Although that time is observable, it is
2932 * unpredictably variable. Mash in the most
2933 * volatile clock bits available, and expire the
2934 * secret extra quickly.
2935 */
2936 if (unlikely(tcp_secret_primary->expires ==
2937 tcp_secret_secondary->expires)) {
2938 struct timespec tv;
2939
2940 getnstimeofday(&tv);
2941 bakery[COOKIE_DIGEST_WORDS+0] ^=
2942 (u32)tv.tv_nsec;
2943
2944 tcp_secret_secondary->expires = jiffy
2945 + TCP_SECRET_1MSL
2946 + (0x0f & tcp_cookie_work(bakery, 0));
2947 } else {
2948 tcp_secret_secondary->expires = jiffy
2949 + TCP_SECRET_LIFE
2950 + (0xff & tcp_cookie_work(bakery, 1));
2951 tcp_secret_primary->expires = jiffy
2952 + TCP_SECRET_2MSL
2953 + (0x1f & tcp_cookie_work(bakery, 2));
2954 }
2955 memcpy(&tcp_secret_secondary->secrets[0],
2956 bakery, COOKIE_WORKSPACE_WORDS);
2957
2958 rcu_assign_pointer(tcp_secret_generating,
2959 tcp_secret_secondary);
2960 rcu_assign_pointer(tcp_secret_retiring,
2961 tcp_secret_primary);
2962 /*
2963 * Neither call_rcu() nor synchronize_rcu() needed.
2964 * Retiring data is not freed. It is replaced after
2965 * further (locked) pointer updates, and a quiet time
2966 * (minimum 1MSL, maximum LIFE - 2MSL).
2967 */
2968 }
2969 spin_unlock_bh(&tcp_secret_locker);
2970 } else {
2971 rcu_read_lock_bh();
2972 memcpy(bakery,
2973 &rcu_dereference(tcp_secret_generating)->secrets[0],
2974 COOKIE_WORKSPACE_WORDS);
2975 rcu_read_unlock_bh();
2976 }
2977 return 0;
2978}
2979EXPORT_SYMBOL(tcp_cookie_generator);
2980
2851void tcp_done(struct sock *sk) 2981void tcp_done(struct sock *sk)
2852{ 2982{
2853 if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) 2983 if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
@@ -2882,6 +3012,7 @@ void __init tcp_init(void)
2882 struct sk_buff *skb = NULL; 3012 struct sk_buff *skb = NULL;
2883 unsigned long nr_pages, limit; 3013 unsigned long nr_pages, limit;
2884 int order, i, max_share; 3014 int order, i, max_share;
3015 unsigned long jiffy = jiffies;
2885 3016
2886 BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); 3017 BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
2887 3018
@@ -2975,6 +3106,15 @@ void __init tcp_init(void)
2975 tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); 3106 tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size);
2976 3107
2977 tcp_register_congestion_control(&tcp_reno); 3108 tcp_register_congestion_control(&tcp_reno);
3109
3110 memset(&tcp_secret_one.secrets[0], 0, sizeof(tcp_secret_one.secrets));
3111 memset(&tcp_secret_two.secrets[0], 0, sizeof(tcp_secret_two.secrets));
3112 tcp_secret_one.expires = jiffy; /* past due */
3113 tcp_secret_two.expires = jiffy; /* past due */
3114 tcp_secret_generating = &tcp_secret_one;
3115 tcp_secret_primary = &tcp_secret_one;
3116 tcp_secret_retiring = &tcp_secret_two;
3117 tcp_secret_secondary = &tcp_secret_two;
2978} 3118}
2979 3119
2980EXPORT_SYMBOL(tcp_close); 3120EXPORT_SYMBOL(tcp_close);