aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorWilliam Allen Simpson <william.allen.simpson@gmail.com>2009-12-02 13:23:05 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-03 01:07:26 -0500
commitbd0388ae77075026d6a9f9eb6026dfd1d52ce0e9 (patch)
treeb2262d2bf3f60e42f8c3573c89e6a47042b20122 /net/ipv4/tcp_output.c
parente56fb50f2b7958b931c8a2fc0966061b3f3c8f3a (diff)
TCPCT part 1f: Initiator Cookie => Responder
Calculate and format <SYN> TCP_COOKIE option. This is a significantly revised implementation of an earlier (year-old) patch that no longer applies cleanly, with permission of the original author (Adam Langley): http://thread.gmane.org/gmane.linux.network/102586 Requires: TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS TCPCT part 1d: define TCP cookie option, extend existing struct's Signed-off-by: William.Allen.Simpson@gmail.com Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c193
1 files changed, 163 insertions, 30 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 307f318fe931..35dd983a8a99 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -365,15 +365,45 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp)
365#define OPTION_TS (1 << 1) 365#define OPTION_TS (1 << 1)
366#define OPTION_MD5 (1 << 2) 366#define OPTION_MD5 (1 << 2)
367#define OPTION_WSCALE (1 << 3) 367#define OPTION_WSCALE (1 << 3)
368#define OPTION_COOKIE_EXTENSION (1 << 4)
368 369
369struct tcp_out_options { 370struct tcp_out_options {
370 u8 options; /* bit field of OPTION_* */ 371 u8 options; /* bit field of OPTION_* */
371 u8 ws; /* window scale, 0 to disable */ 372 u8 ws; /* window scale, 0 to disable */
372 u8 num_sack_blocks; /* number of SACK blocks to include */ 373 u8 num_sack_blocks; /* number of SACK blocks to include */
374 u8 hash_size; /* bytes in hash_location */
373 u16 mss; /* 0 to disable */ 375 u16 mss; /* 0 to disable */
374 __u32 tsval, tsecr; /* need to include OPTION_TS */ 376 __u32 tsval, tsecr; /* need to include OPTION_TS */
377 __u8 *hash_location; /* temporary pointer, overloaded */
375}; 378};
376 379
380/* The sysctl int routines are generic, so check consistency here.
381 */
382static u8 tcp_cookie_size_check(u8 desired)
383{
384 if (desired > 0) {
385 /* previously specified */
386 return desired;
387 }
388 if (sysctl_tcp_cookie_size <= 0) {
389 /* no default specified */
390 return 0;
391 }
392 if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) {
393 /* value too small, specify minimum */
394 return TCP_COOKIE_MIN;
395 }
396 if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) {
397 /* value too large, specify maximum */
398 return TCP_COOKIE_MAX;
399 }
400 if (0x1 & sysctl_tcp_cookie_size) {
401 /* 8-bit multiple, illegal, fix it */
402 return (u8)(sysctl_tcp_cookie_size + 0x1);
403 }
404 return (u8)sysctl_tcp_cookie_size;
405}
406
377/* Write previously computed TCP options to the packet. 407/* Write previously computed TCP options to the packet.
378 * 408 *
379 * Beware: Something in the Internet is very sensitive to the ordering of 409 * Beware: Something in the Internet is very sensitive to the ordering of
@@ -388,17 +418,34 @@ struct tcp_out_options {
388 * (but it may well be that other scenarios fail similarly). 418 * (but it may well be that other scenarios fail similarly).
389 */ 419 */
390static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, 420static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
391 const struct tcp_out_options *opts, 421 struct tcp_out_options *opts)
392 __u8 **md5_hash) { 422{
393 if (unlikely(OPTION_MD5 & opts->options)) { 423 u8 options = opts->options; /* mungable copy */
394 *ptr++ = htonl((TCPOPT_NOP << 24) | 424
395 (TCPOPT_NOP << 16) | 425 /* Having both authentication and cookies for security is redundant,
396 (TCPOPT_MD5SIG << 8) | 426 * and there's certainly not enough room. Instead, the cookie-less
397 TCPOLEN_MD5SIG); 427 * extension variant is proposed.
398 *md5_hash = (__u8 *)ptr; 428 *
429 * Consider the pessimal case with authentication. The options
430 * could look like:
431 * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
432 */
433 if (unlikely(OPTION_MD5 & options)) {
434 if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
435 *ptr++ = htonl((TCPOPT_COOKIE << 24) |
436 (TCPOLEN_COOKIE_BASE << 16) |
437 (TCPOPT_MD5SIG << 8) |
438 TCPOLEN_MD5SIG);
439 } else {
440 *ptr++ = htonl((TCPOPT_NOP << 24) |
441 (TCPOPT_NOP << 16) |
442 (TCPOPT_MD5SIG << 8) |
443 TCPOLEN_MD5SIG);
444 }
445 options &= ~OPTION_COOKIE_EXTENSION;
446 /* overload cookie hash location */
447 opts->hash_location = (__u8 *)ptr;
399 ptr += 4; 448 ptr += 4;
400 } else {
401 *md5_hash = NULL;
402 } 449 }
403 450
404 if (unlikely(opts->mss)) { 451 if (unlikely(opts->mss)) {
@@ -407,12 +454,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
407 opts->mss); 454 opts->mss);
408 } 455 }
409 456
410 if (likely(OPTION_TS & opts->options)) { 457 if (likely(OPTION_TS & options)) {
411 if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { 458 if (unlikely(OPTION_SACK_ADVERTISE & options)) {
412 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | 459 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
413 (TCPOLEN_SACK_PERM << 16) | 460 (TCPOLEN_SACK_PERM << 16) |
414 (TCPOPT_TIMESTAMP << 8) | 461 (TCPOPT_TIMESTAMP << 8) |
415 TCPOLEN_TIMESTAMP); 462 TCPOLEN_TIMESTAMP);
463 options &= ~OPTION_SACK_ADVERTISE;
416 } else { 464 } else {
417 *ptr++ = htonl((TCPOPT_NOP << 24) | 465 *ptr++ = htonl((TCPOPT_NOP << 24) |
418 (TCPOPT_NOP << 16) | 466 (TCPOPT_NOP << 16) |
@@ -423,15 +471,52 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
423 *ptr++ = htonl(opts->tsecr); 471 *ptr++ = htonl(opts->tsecr);
424 } 472 }
425 473
426 if (unlikely(OPTION_SACK_ADVERTISE & opts->options && 474 /* Specification requires after timestamp, so do it now.
427 !(OPTION_TS & opts->options))) { 475 *
476 * Consider the pessimal case without authentication. The options
477 * could look like:
478 * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
479 */
480 if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
481 __u8 *cookie_copy = opts->hash_location;
482 u8 cookie_size = opts->hash_size;
483
484 /* 8-bit multiple handled in tcp_cookie_size_check() above,
485 * and elsewhere.
486 */
487 if (0x2 & cookie_size) {
488 __u8 *p = (__u8 *)ptr;
489
490 /* 16-bit multiple */
491 *p++ = TCPOPT_COOKIE;
492 *p++ = TCPOLEN_COOKIE_BASE + cookie_size;
493 *p++ = *cookie_copy++;
494 *p++ = *cookie_copy++;
495 ptr++;
496 cookie_size -= 2;
497 } else {
498 /* 32-bit multiple */
499 *ptr++ = htonl(((TCPOPT_NOP << 24) |
500 (TCPOPT_NOP << 16) |
501 (TCPOPT_COOKIE << 8) |
502 TCPOLEN_COOKIE_BASE) +
503 cookie_size);
504 }
505
506 if (cookie_size > 0) {
507 memcpy(ptr, cookie_copy, cookie_size);
508 ptr += (cookie_size / 4);
509 }
510 }
511
512 if (unlikely(OPTION_SACK_ADVERTISE & options)) {
428 *ptr++ = htonl((TCPOPT_NOP << 24) | 513 *ptr++ = htonl((TCPOPT_NOP << 24) |
429 (TCPOPT_NOP << 16) | 514 (TCPOPT_NOP << 16) |
430 (TCPOPT_SACK_PERM << 8) | 515 (TCPOPT_SACK_PERM << 8) |
431 TCPOLEN_SACK_PERM); 516 TCPOLEN_SACK_PERM);
432 } 517 }
433 518
434 if (unlikely(OPTION_WSCALE & opts->options)) { 519 if (unlikely(OPTION_WSCALE & options)) {
435 *ptr++ = htonl((TCPOPT_NOP << 24) | 520 *ptr++ = htonl((TCPOPT_NOP << 24) |
436 (TCPOPT_WINDOW << 16) | 521 (TCPOPT_WINDOW << 16) |
437 (TCPOLEN_WINDOW << 8) | 522 (TCPOLEN_WINDOW << 8) |
@@ -466,14 +551,18 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
466 struct tcp_out_options *opts, 551 struct tcp_out_options *opts,
467 struct tcp_md5sig_key **md5) { 552 struct tcp_md5sig_key **md5) {
468 struct tcp_sock *tp = tcp_sk(sk); 553 struct tcp_sock *tp = tcp_sk(sk);
469 unsigned size = 0; 554 struct tcp_cookie_values *cvp = tp->cookie_values;
470 struct dst_entry *dst = __sk_dst_get(sk); 555 struct dst_entry *dst = __sk_dst_get(sk);
556 unsigned remaining = MAX_TCP_OPTION_SPACE;
557 u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ?
558 tcp_cookie_size_check(cvp->cookie_desired) :
559 0;
471 560
472#ifdef CONFIG_TCP_MD5SIG 561#ifdef CONFIG_TCP_MD5SIG
473 *md5 = tp->af_specific->md5_lookup(sk, sk); 562 *md5 = tp->af_specific->md5_lookup(sk, sk);
474 if (*md5) { 563 if (*md5) {
475 opts->options |= OPTION_MD5; 564 opts->options |= OPTION_MD5;
476 size += TCPOLEN_MD5SIG_ALIGNED; 565 remaining -= TCPOLEN_MD5SIG_ALIGNED;
477 } 566 }
478#else 567#else
479 *md5 = NULL; 568 *md5 = NULL;
@@ -489,7 +578,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
489 * SACKs don't matter, we never delay an ACK when we have any of those 578 * SACKs don't matter, we never delay an ACK when we have any of those
490 * going out. */ 579 * going out. */
491 opts->mss = tcp_advertise_mss(sk); 580 opts->mss = tcp_advertise_mss(sk);
492 size += TCPOLEN_MSS_ALIGNED; 581 remaining -= TCPOLEN_MSS_ALIGNED;
493 582
494 if (likely(sysctl_tcp_timestamps && 583 if (likely(sysctl_tcp_timestamps &&
495 !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) && 584 !dst_feature(dst, RTAX_FEATURE_NO_TSTAMP) &&
@@ -497,22 +586,68 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
497 opts->options |= OPTION_TS; 586 opts->options |= OPTION_TS;
498 opts->tsval = TCP_SKB_CB(skb)->when; 587 opts->tsval = TCP_SKB_CB(skb)->when;
499 opts->tsecr = tp->rx_opt.ts_recent; 588 opts->tsecr = tp->rx_opt.ts_recent;
500 size += TCPOLEN_TSTAMP_ALIGNED; 589 remaining -= TCPOLEN_TSTAMP_ALIGNED;
501 } 590 }
502 if (likely(sysctl_tcp_window_scaling && 591 if (likely(sysctl_tcp_window_scaling &&
503 !dst_feature(dst, RTAX_FEATURE_NO_WSCALE))) { 592 !dst_feature(dst, RTAX_FEATURE_NO_WSCALE))) {
504 opts->ws = tp->rx_opt.rcv_wscale; 593 opts->ws = tp->rx_opt.rcv_wscale;
505 opts->options |= OPTION_WSCALE; 594 opts->options |= OPTION_WSCALE;
506 size += TCPOLEN_WSCALE_ALIGNED; 595 remaining -= TCPOLEN_WSCALE_ALIGNED;
507 } 596 }
508 if (likely(sysctl_tcp_sack && 597 if (likely(sysctl_tcp_sack &&
509 !dst_feature(dst, RTAX_FEATURE_NO_SACK))) { 598 !dst_feature(dst, RTAX_FEATURE_NO_SACK))) {
510 opts->options |= OPTION_SACK_ADVERTISE; 599 opts->options |= OPTION_SACK_ADVERTISE;
511 if (unlikely(!(OPTION_TS & opts->options))) 600 if (unlikely(!(OPTION_TS & opts->options)))
512 size += TCPOLEN_SACKPERM_ALIGNED; 601 remaining -= TCPOLEN_SACKPERM_ALIGNED;
513 } 602 }
514 603
515 return size; 604 /* Note that timestamps are required by the specification.
605 *
606 * Odd numbers of bytes are prohibited by the specification, ensuring
607 * that the cookie is 16-bit aligned, and the resulting cookie pair is
608 * 32-bit aligned.
609 */
610 if (*md5 == NULL &&
611 (OPTION_TS & opts->options) &&
612 cookie_size > 0) {
613 int need = TCPOLEN_COOKIE_BASE + cookie_size;
614
615 if (0x2 & need) {
616 /* 32-bit multiple */
617 need += 2; /* NOPs */
618
619 if (need > remaining) {
620 /* try shrinking cookie to fit */
621 cookie_size -= 2;
622 need -= 4;
623 }
624 }
625 while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
626 cookie_size -= 4;
627 need -= 4;
628 }
629 if (TCP_COOKIE_MIN <= cookie_size) {
630 opts->options |= OPTION_COOKIE_EXTENSION;
631 opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
632 opts->hash_size = cookie_size;
633
634 /* Remember for future incarnations. */
635 cvp->cookie_desired = cookie_size;
636
637 if (cvp->cookie_desired != cvp->cookie_pair_size) {
638 /* Currently use random bytes as a nonce,
639 * assuming these are completely unpredictable
640 * by hostile users of the same system.
641 */
642 get_random_bytes(&cvp->cookie_pair[0],
643 cookie_size);
644 cvp->cookie_pair_size = cookie_size;
645 }
646
647 remaining -= need;
648 }
649 }
650 return MAX_TCP_OPTION_SPACE - remaining;
516} 651}
517 652
518/* Set up TCP options for SYN-ACKs. */ 653/* Set up TCP options for SYN-ACKs. */
@@ -627,7 +762,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
627 struct tcp_out_options opts; 762 struct tcp_out_options opts;
628 unsigned tcp_options_size, tcp_header_size; 763 unsigned tcp_options_size, tcp_header_size;
629 struct tcp_md5sig_key *md5; 764 struct tcp_md5sig_key *md5;
630 __u8 *md5_hash_location;
631 struct tcphdr *th; 765 struct tcphdr *th;
632 int err; 766 int err;
633 767
@@ -698,7 +832,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
698 } 832 }
699 } 833 }
700 834
701 tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); 835 tcp_options_write((__be32 *)(th + 1), tp, &opts);
702 if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0)) 836 if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0))
703 TCP_ECN_send(sk, skb, tcp_header_size); 837 TCP_ECN_send(sk, skb, tcp_header_size);
704 838
@@ -706,7 +840,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
706 /* Calculate the MD5 hash, as we have all we need now */ 840 /* Calculate the MD5 hash, as we have all we need now */
707 if (md5) { 841 if (md5) {
708 sk->sk_route_caps &= ~NETIF_F_GSO_MASK; 842 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
709 tp->af_specific->calc_md5_hash(md5_hash_location, 843 tp->af_specific->calc_md5_hash(opts.hash_location,
710 md5, sk, NULL, skb); 844 md5, sk, NULL, skb);
711 } 845 }
712#endif 846#endif
@@ -2230,14 +2364,13 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2230 struct request_sock *req, 2364 struct request_sock *req,
2231 struct request_values *rvp) 2365 struct request_values *rvp)
2232{ 2366{
2367 struct tcp_out_options opts;
2233 struct inet_request_sock *ireq = inet_rsk(req); 2368 struct inet_request_sock *ireq = inet_rsk(req);
2234 struct tcp_sock *tp = tcp_sk(sk); 2369 struct tcp_sock *tp = tcp_sk(sk);
2235 struct tcphdr *th; 2370 struct tcphdr *th;
2236 int tcp_header_size;
2237 struct tcp_out_options opts;
2238 struct sk_buff *skb; 2371 struct sk_buff *skb;
2239 struct tcp_md5sig_key *md5; 2372 struct tcp_md5sig_key *md5;
2240 __u8 *md5_hash_location; 2373 int tcp_header_size;
2241 int mss; 2374 int mss;
2242 2375
2243 skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); 2376 skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
@@ -2298,14 +2431,14 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2298 2431
2299 /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ 2432 /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
2300 th->window = htons(min(req->rcv_wnd, 65535U)); 2433 th->window = htons(min(req->rcv_wnd, 65535U));
2301 tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); 2434 tcp_options_write((__be32 *)(th + 1), tp, &opts);
2302 th->doff = (tcp_header_size >> 2); 2435 th->doff = (tcp_header_size >> 2);
2303 TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); 2436 TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
2304 2437
2305#ifdef CONFIG_TCP_MD5SIG 2438#ifdef CONFIG_TCP_MD5SIG
2306 /* Okay, we have all we need - do the md5 hash if needed */ 2439 /* Okay, we have all we need - do the md5 hash if needed */
2307 if (md5) { 2440 if (md5) {
2308 tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location, 2441 tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
2309 md5, NULL, req, skb); 2442 md5, NULL, req, skb);
2310 } 2443 }
2311#endif 2444#endif