diff options
| -rw-r--r-- | include/net/request_sock.h | 2 | ||||
| -rw-r--r-- | include/net/tcp.h | 4 | ||||
| -rw-r--r-- | net/ipv4/syncookies.c | 89 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 5 | ||||
| -rw-r--r-- | net/ipv4/tcp_output.c | 6 | ||||
| -rw-r--r-- | net/ipv6/syncookies.c | 20 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 5 |
7 files changed, 114 insertions, 17 deletions
diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 0369f98e9f3a..b220b5f624de 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h | |||
| @@ -45,7 +45,7 @@ struct request_sock { | |||
| 45 | struct request_sock *dl_next; /* Must be first member! */ | 45 | struct request_sock *dl_next; /* Must be first member! */ |
| 46 | u16 mss; | 46 | u16 mss; |
| 47 | u8 retrans; | 47 | u8 retrans; |
| 48 | u8 __pad; | 48 | u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */ |
| 49 | /* The following two fields can be easily recomputed I think -AK */ | 49 | /* The following two fields can be easily recomputed I think -AK */ |
| 50 | u32 window_clamp; /* window clamp at creation time */ | 50 | u32 window_clamp; /* window clamp at creation time */ |
| 51 | u32 rcv_wnd; /* rcv_wnd offered first time */ | 51 | u32 rcv_wnd; /* rcv_wnd offered first time */ |
diff --git a/include/net/tcp.h b/include/net/tcp.h index 723b36851dde..7b41bb962b9c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
| @@ -442,6 +442,9 @@ extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 442 | extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, | 442 | extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, |
| 443 | __u16 *mss); | 443 | __u16 *mss); |
| 444 | 444 | ||
| 445 | extern __u32 cookie_init_timestamp(struct request_sock *req); | ||
| 446 | extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt); | ||
| 447 | |||
| 445 | /* From net/ipv6/syncookies.c */ | 448 | /* From net/ipv6/syncookies.c */ |
| 446 | extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); | 449 | extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); |
| 447 | extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, | 450 | extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, |
| @@ -956,6 +959,7 @@ static inline void tcp_openreq_init(struct request_sock *req, | |||
| 956 | struct inet_request_sock *ireq = inet_rsk(req); | 959 | struct inet_request_sock *ireq = inet_rsk(req); |
| 957 | 960 | ||
| 958 | req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ | 961 | req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ |
| 962 | req->cookie_ts = 0; | ||
| 959 | tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; | 963 | tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; |
| 960 | req->mss = rx_opt->mss_clamp; | 964 | req->mss = rx_opt->mss_clamp; |
| 961 | req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; | 965 | req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index abc752d45cf7..73ba98921d64 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
| @@ -19,6 +19,10 @@ | |||
| 19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 20 | #include <net/tcp.h> | 20 | #include <net/tcp.h> |
| 21 | 21 | ||
| 22 | /* Timestamps: lowest 9 bits store TCP options */ | ||
| 23 | #define TSBITS 9 | ||
| 24 | #define TSMASK (((__u32)1 << TSBITS) - 1) | ||
| 25 | |||
| 22 | extern int sysctl_tcp_syncookies; | 26 | extern int sysctl_tcp_syncookies; |
| 23 | 27 | ||
| 24 | __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; | 28 | __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; |
| @@ -51,6 +55,39 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, | |||
| 51 | return tmp[17]; | 55 | return tmp[17]; |
| 52 | } | 56 | } |
| 53 | 57 | ||
| 58 | |||
| 59 | /* | ||
| 60 | * when syncookies are in effect and tcp timestamps are enabled we encode | ||
| 61 | * tcp options in the lowest 9 bits of the timestamp value that will be | ||
| 62 | * sent in the syn-ack. | ||
| 63 | * Since subsequent timestamps use the normal tcp_time_stamp value, we | ||
| 64 | * must make sure that the resulting initial timestamp is <= tcp_time_stamp. | ||
| 65 | */ | ||
| 66 | __u32 cookie_init_timestamp(struct request_sock *req) | ||
| 67 | { | ||
| 68 | struct inet_request_sock *ireq; | ||
| 69 | u32 ts, ts_now = tcp_time_stamp; | ||
| 70 | u32 options = 0; | ||
| 71 | |||
| 72 | ireq = inet_rsk(req); | ||
| 73 | if (ireq->wscale_ok) { | ||
| 74 | options = ireq->snd_wscale; | ||
| 75 | options |= ireq->rcv_wscale << 4; | ||
| 76 | } | ||
| 77 | options |= ireq->sack_ok << 8; | ||
| 78 | |||
| 79 | ts = ts_now & ~TSMASK; | ||
| 80 | ts |= options; | ||
| 81 | if (ts > ts_now) { | ||
| 82 | ts >>= TSBITS; | ||
| 83 | ts--; | ||
| 84 | ts <<= TSBITS; | ||
| 85 | ts |= options; | ||
| 86 | } | ||
| 87 | return ts; | ||
| 88 | } | ||
| 89 | |||
| 90 | |||
| 54 | static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, | 91 | static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, |
| 55 | __be16 dport, __u32 sseq, __u32 count, | 92 | __be16 dport, __u32 sseq, __u32 count, |
| 56 | __u32 data) | 93 | __u32 data) |
| @@ -185,6 +222,35 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, | |||
| 185 | return child; | 222 | return child; |
| 186 | } | 223 | } |
| 187 | 224 | ||
| 225 | |||
| 226 | /* | ||
| 227 | * when syncookies are in effect and tcp timestamps are enabled we stored | ||
| 228 | * additional tcp options in the timestamp. | ||
| 229 | * This extracts these options from the timestamp echo. | ||
| 230 | * | ||
| 231 | * The lowest 4 bits are for snd_wscale | ||
| 232 | * The next 4 lsb are for rcv_wscale | ||
| 233 | * The next lsb is for sack_ok | ||
| 234 | */ | ||
| 235 | void cookie_check_timestamp(struct tcp_options_received *tcp_opt) | ||
| 236 | { | ||
| 237 | /* echoed timestamp, 9 lowest bits contain options */ | ||
| 238 | u32 options = tcp_opt->rcv_tsecr & TSMASK; | ||
| 239 | |||
| 240 | tcp_opt->snd_wscale = options & 0xf; | ||
| 241 | options >>= 4; | ||
| 242 | tcp_opt->rcv_wscale = options & 0xf; | ||
| 243 | |||
| 244 | tcp_opt->sack_ok = (options >> 4) & 0x1; | ||
| 245 | |||
| 246 | if (tcp_opt->sack_ok) | ||
| 247 | tcp_sack_reset(tcp_opt); | ||
| 248 | |||
| 249 | if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale) | ||
| 250 | tcp_opt->wscale_ok = 1; | ||
| 251 | } | ||
| 252 | EXPORT_SYMBOL(cookie_check_timestamp); | ||
| 253 | |||
| 188 | struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | 254 | struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, |
| 189 | struct ip_options *opt) | 255 | struct ip_options *opt) |
| 190 | { | 256 | { |
| @@ -198,6 +264,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 198 | int mss; | 264 | int mss; |
| 199 | struct rtable *rt; | 265 | struct rtable *rt; |
| 200 | __u8 rcv_wscale; | 266 | __u8 rcv_wscale; |
| 267 | struct tcp_options_received tcp_opt; | ||
| 201 | 268 | ||
| 202 | if (!sysctl_tcp_syncookies || !th->ack) | 269 | if (!sysctl_tcp_syncookies || !th->ack) |
| 203 | goto out; | 270 | goto out; |
| @@ -210,6 +277,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 210 | 277 | ||
| 211 | NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); | 278 | NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); |
| 212 | 279 | ||
| 280 | /* check for timestamp cookie support */ | ||
| 281 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | ||
| 282 | tcp_parse_options(skb, &tcp_opt, 0); | ||
| 283 | |||
| 284 | if (tcp_opt.saw_tstamp) | ||
| 285 | cookie_check_timestamp(&tcp_opt); | ||
| 286 | |||
| 213 | ret = NULL; | 287 | ret = NULL; |
| 214 | req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */ | 288 | req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */ |
| 215 | if (!req) | 289 | if (!req) |
| @@ -228,6 +302,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 228 | ireq->loc_addr = ip_hdr(skb)->daddr; | 302 | ireq->loc_addr = ip_hdr(skb)->daddr; |
| 229 | ireq->rmt_addr = ip_hdr(skb)->saddr; | 303 | ireq->rmt_addr = ip_hdr(skb)->saddr; |
| 230 | ireq->opt = NULL; | 304 | ireq->opt = NULL; |
| 305 | ireq->snd_wscale = tcp_opt.snd_wscale; | ||
| 306 | ireq->rcv_wscale = tcp_opt.rcv_wscale; | ||
| 307 | ireq->sack_ok = tcp_opt.sack_ok; | ||
| 308 | ireq->wscale_ok = tcp_opt.wscale_ok; | ||
| 309 | ireq->tstamp_ok = tcp_opt.saw_tstamp; | ||
| 310 | req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; | ||
| 231 | 311 | ||
| 232 | /* We throwed the options of the initial SYN away, so we hope | 312 | /* We throwed the options of the initial SYN away, so we hope |
| 233 | * the ACK carries the same options again (see RFC1122 4.2.3.8) | 313 | * the ACK carries the same options again (see RFC1122 4.2.3.8) |
| @@ -242,8 +322,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 242 | } | 322 | } |
| 243 | } | 323 | } |
| 244 | 324 | ||
| 245 | ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0; | ||
| 246 | ireq->wscale_ok = ireq->sack_ok = 0; | ||
| 247 | req->expires = 0UL; | 325 | req->expires = 0UL; |
| 248 | req->retrans = 0; | 326 | req->retrans = 0; |
| 249 | 327 | ||
| @@ -272,11 +350,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
| 272 | } | 350 | } |
| 273 | 351 | ||
| 274 | /* Try to redo what tcp_v4_send_synack did. */ | 352 | /* Try to redo what tcp_v4_send_synack did. */ |
| 275 | req->window_clamp = dst_metric(&rt->u.dst, RTAX_WINDOW); | 353 | req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW); |
| 354 | |||
| 276 | tcp_select_initial_window(tcp_full_space(sk), req->mss, | 355 | tcp_select_initial_window(tcp_full_space(sk), req->mss, |
| 277 | &req->rcv_wnd, &req->window_clamp, | 356 | &req->rcv_wnd, &req->window_clamp, |
| 278 | 0, &rcv_wscale); | 357 | ireq->wscale_ok, &rcv_wscale); |
| 279 | /* BTW win scale with syncookies is 0 by definition */ | 358 | |
| 280 | ireq->rcv_wscale = rcv_wscale; | 359 | ireq->rcv_wscale = rcv_wscale; |
| 281 | 360 | ||
| 282 | ret = get_cookie_sock(sk, skb, req, &rt->u.dst); | 361 | ret = get_cookie_sock(sk, skb, req, &rt->u.dst); |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index df89a566a5a1..52e3ae603ca9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -1299,10 +1299,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1299 | 1299 | ||
| 1300 | tcp_parse_options(skb, &tmp_opt, 0); | 1300 | tcp_parse_options(skb, &tmp_opt, 0); |
| 1301 | 1301 | ||
| 1302 | if (want_cookie) { | 1302 | if (want_cookie && !tmp_opt.saw_tstamp) |
| 1303 | tcp_clear_options(&tmp_opt); | 1303 | tcp_clear_options(&tmp_opt); |
| 1304 | tmp_opt.saw_tstamp = 0; | ||
| 1305 | } | ||
| 1306 | 1304 | ||
| 1307 | if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) { | 1305 | if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) { |
| 1308 | /* Some OSes (unknown ones, but I see them on web server, which | 1306 | /* Some OSes (unknown ones, but I see them on web server, which |
| @@ -1330,6 +1328,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1330 | if (want_cookie) { | 1328 | if (want_cookie) { |
| 1331 | #ifdef CONFIG_SYN_COOKIES | 1329 | #ifdef CONFIG_SYN_COOKIES |
| 1332 | syn_flood_warning(skb); | 1330 | syn_flood_warning(skb); |
| 1331 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1333 | #endif | 1332 | #endif |
| 1334 | isn = cookie_v4_init_sequence(sk, skb, &req->mss); | 1333 | isn = cookie_v4_init_sequence(sk, skb, &req->mss); |
| 1335 | } else if (!isn) { | 1334 | } else if (!isn) { |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a627616314ba..76b3653e9b4c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -2233,7 +2233,11 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
| 2233 | 2233 | ||
| 2234 | /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ | 2234 | /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ |
| 2235 | th->window = htons(min(req->rcv_wnd, 65535U)); | 2235 | th->window = htons(min(req->rcv_wnd, 65535U)); |
| 2236 | 2236 | #ifdef CONFIG_SYN_COOKIES | |
| 2237 | if (unlikely(req->cookie_ts)) | ||
| 2238 | TCP_SKB_CB(skb)->when = cookie_init_timestamp(req); | ||
| 2239 | else | ||
| 2240 | #endif | ||
| 2237 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | 2241 | TCP_SKB_CB(skb)->when = tcp_time_stamp; |
| 2238 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, | 2242 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, |
| 2239 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, | 2243 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 3a622e7abc02..938ce4ecde55 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
| @@ -170,6 +170,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 170 | int mss; | 170 | int mss; |
| 171 | struct dst_entry *dst; | 171 | struct dst_entry *dst; |
| 172 | __u8 rcv_wscale; | 172 | __u8 rcv_wscale; |
| 173 | struct tcp_options_received tcp_opt; | ||
| 173 | 174 | ||
| 174 | if (!sysctl_tcp_syncookies || !th->ack) | 175 | if (!sysctl_tcp_syncookies || !th->ack) |
| 175 | goto out; | 176 | goto out; |
| @@ -182,6 +183,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 182 | 183 | ||
| 183 | NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); | 184 | NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); |
| 184 | 185 | ||
| 186 | /* check for timestamp cookie support */ | ||
| 187 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | ||
| 188 | tcp_parse_options(skb, &tcp_opt, 0); | ||
| 189 | |||
| 190 | if (tcp_opt.saw_tstamp) | ||
| 191 | cookie_check_timestamp(&tcp_opt); | ||
| 192 | |||
| 185 | ret = NULL; | 193 | ret = NULL; |
| 186 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); | 194 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); |
| 187 | if (!req) | 195 | if (!req) |
| @@ -216,8 +224,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 216 | 224 | ||
| 217 | req->expires = 0UL; | 225 | req->expires = 0UL; |
| 218 | req->retrans = 0; | 226 | req->retrans = 0; |
| 219 | ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0; | 227 | ireq->snd_wscale = tcp_opt.snd_wscale; |
| 220 | ireq->wscale_ok = ireq->sack_ok = 0; | 228 | ireq->rcv_wscale = tcp_opt.rcv_wscale; |
| 229 | ireq->sack_ok = tcp_opt.sack_ok; | ||
| 230 | ireq->wscale_ok = tcp_opt.wscale_ok; | ||
| 231 | ireq->tstamp_ok = tcp_opt.saw_tstamp; | ||
| 232 | req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; | ||
| 221 | treq->rcv_isn = ntohl(th->seq) - 1; | 233 | treq->rcv_isn = ntohl(th->seq) - 1; |
| 222 | treq->snt_isn = cookie; | 234 | treq->snt_isn = cookie; |
| 223 | 235 | ||
| @@ -253,10 +265,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 253 | goto out; | 265 | goto out; |
| 254 | } | 266 | } |
| 255 | 267 | ||
| 256 | req->window_clamp = dst_metric(dst, RTAX_WINDOW); | 268 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); |
| 257 | tcp_select_initial_window(tcp_full_space(sk), req->mss, | 269 | tcp_select_initial_window(tcp_full_space(sk), req->mss, |
| 258 | &req->rcv_wnd, &req->window_clamp, | 270 | &req->rcv_wnd, &req->window_clamp, |
| 259 | 0, &rcv_wscale); | 271 | ireq->wscale_ok, &rcv_wscale); |
| 260 | 272 | ||
| 261 | ireq->rcv_wscale = rcv_wscale; | 273 | ireq->rcv_wscale = rcv_wscale; |
| 262 | 274 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 378cc4002a76..8ebf6de29562 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -1290,10 +1290,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1290 | 1290 | ||
| 1291 | tcp_parse_options(skb, &tmp_opt, 0); | 1291 | tcp_parse_options(skb, &tmp_opt, 0); |
| 1292 | 1292 | ||
| 1293 | if (want_cookie) { | 1293 | if (want_cookie && !tmp_opt.saw_tstamp) |
| 1294 | tcp_clear_options(&tmp_opt); | 1294 | tcp_clear_options(&tmp_opt); |
| 1295 | tmp_opt.saw_tstamp = 0; | ||
| 1296 | } | ||
| 1297 | 1295 | ||
| 1298 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | 1296 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; |
| 1299 | tcp_openreq_init(req, &tmp_opt, skb); | 1297 | tcp_openreq_init(req, &tmp_opt, skb); |
| @@ -1307,6 +1305,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1307 | 1305 | ||
| 1308 | if (want_cookie) { | 1306 | if (want_cookie) { |
| 1309 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | 1307 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); |
| 1308 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1310 | } else if (!isn) { | 1309 | } else if (!isn) { |
| 1311 | if (ipv6_opt_accepted(sk, skb) || | 1310 | if (ipv6_opt_accepted(sk, skb) || |
| 1312 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1311 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
