diff options
| -rw-r--r-- | include/linux/cryptohash.h | 1 | ||||
| -rw-r--r-- | include/net/tcp.h | 8 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 140 |
3 files changed, 149 insertions, 0 deletions
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h index c118b2ad9807..ec78a4bbe1d5 100644 --- a/include/linux/cryptohash.h +++ b/include/linux/cryptohash.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __CRYPTOHASH_H | 2 | #define __CRYPTOHASH_H |
| 3 | 3 | ||
| 4 | #define SHA_DIGEST_WORDS 5 | 4 | #define SHA_DIGEST_WORDS 5 |
| 5 | #define SHA_MESSAGE_BYTES (512 /*bits*/ / 8) | ||
| 5 | #define SHA_WORKSPACE_WORDS 80 | 6 | #define SHA_WORKSPACE_WORDS 80 |
| 6 | 7 | ||
| 7 | void sha_init(__u32 *buf); | 8 | void sha_init(__u32 *buf); |
diff --git a/include/net/tcp.h b/include/net/tcp.h index ec183fda05d0..4a99a8e39121 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
| @@ -1478,6 +1478,14 @@ struct tcp_request_sock_ops { | |||
| 1478 | #endif | 1478 | #endif |
| 1479 | }; | 1479 | }; |
| 1480 | 1480 | ||
| 1481 | /* Using SHA1 for now, define some constants. | ||
| 1482 | */ | ||
| 1483 | #define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS) | ||
| 1484 | #define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4) | ||
| 1485 | #define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS) | ||
| 1486 | |||
| 1487 | extern int tcp_cookie_generator(u32 *bakery); | ||
| 1488 | |||
| 1481 | extern void tcp_v4_init(void); | 1489 | extern void tcp_v4_init(void); |
| 1482 | extern void tcp_init(void); | 1490 | extern void tcp_init(void); |
| 1483 | 1491 | ||
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 | */ | ||
| 2876 | struct 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 | |||
| 2890 | static struct tcp_cookie_secret tcp_secret_one; | ||
| 2891 | static struct tcp_cookie_secret tcp_secret_two; | ||
| 2892 | |||
| 2893 | /* Essentially a circular list, without dynamic allocation. */ | ||
| 2894 | static struct tcp_cookie_secret *tcp_secret_generating; | ||
| 2895 | static struct tcp_cookie_secret *tcp_secret_primary; | ||
| 2896 | static struct tcp_cookie_secret *tcp_secret_retiring; | ||
| 2897 | static struct tcp_cookie_secret *tcp_secret_secondary; | ||
| 2898 | |||
| 2899 | static DEFINE_SPINLOCK(tcp_secret_locker); | ||
| 2900 | |||
| 2901 | /* Select a pseudo-random word in the cookie workspace. | ||
| 2902 | */ | ||
| 2903 | static 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 | */ | ||
| 2912 | int 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 | } | ||
| 2979 | EXPORT_SYMBOL(tcp_cookie_generator); | ||
| 2980 | |||
| 2851 | void tcp_done(struct sock *sk) | 2981 | void 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 | ||
| 2980 | EXPORT_SYMBOL(tcp_close); | 3120 | EXPORT_SYMBOL(tcp_close); |
