diff options
author | William Allen Simpson <william.allen.simpson@gmail.com> | 2009-12-02 13:17:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-03 01:07:25 -0500 |
commit | 435cf559f02ea3a3159eb316f97dc88bdebe9432 (patch) | |
tree | 0b2a7e9110c46b193176b0a59fe5689eae7c18f3 /net/ipv4 | |
parent | 519855c508b9a17878c0977a3cdefc09b59b30df (diff) |
TCPCT part 1d: define TCP cookie option, extend existing struct's
Data structures are carefully composed to require minimal additions.
For example, the struct tcp_options_received cookie_plus variable fits
between existing 16-bit and 8-bit variables, requiring no additional
space (taking alignment into consideration). There are no additions to
tcp_request_sock, and only 1 pointer in tcp_sock.
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
The principle difference is using a TCP option to carry the cookie nonce,
instead of a user configured offset in the data. This is more flexible and
less subject to user configuration error. Such a cookie option has been
suggested for many years, and is also useful without SYN data, allowing
several related concepts to use the same extension option.
"Re: SYN floods (was: does history repeat itself?)", September 9, 1996.
http://www.merit.net/mail.archives/nanog/1996-09/msg00235.html
"Re: what a new TCP header might look like", May 12, 1998.
ftp://ftp.isi.edu/end2end/end2end-interest-1998.mail
These functions will also be used in subsequent patches that implement
additional features.
Requires:
TCPCT part 1a: add request_values parameter for sending SYNACK
TCPCT part 1b: generate Responder Cookie secret
TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
Signed-off-by: William.Allen.Simpson@gmail.com
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 20 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 46 |
2 files changed, 58 insertions, 8 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 649a36d99c73..a2bcac9b388e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1833,6 +1833,19 @@ static int tcp_v4_init_sock(struct sock *sk) | |||
1833 | tp->af_specific = &tcp_sock_ipv4_specific; | 1833 | tp->af_specific = &tcp_sock_ipv4_specific; |
1834 | #endif | 1834 | #endif |
1835 | 1835 | ||
1836 | /* TCP Cookie Transactions */ | ||
1837 | if (sysctl_tcp_cookie_size > 0) { | ||
1838 | /* Default, cookies without s_data_payload. */ | ||
1839 | tp->cookie_values = | ||
1840 | kzalloc(sizeof(*tp->cookie_values), | ||
1841 | sk->sk_allocation); | ||
1842 | if (tp->cookie_values != NULL) | ||
1843 | kref_init(&tp->cookie_values->kref); | ||
1844 | } | ||
1845 | /* Presumed zeroed, in order of appearance: | ||
1846 | * cookie_in_always, cookie_out_never, | ||
1847 | * s_data_constant, s_data_in, s_data_out | ||
1848 | */ | ||
1836 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; | 1849 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; |
1837 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; | 1850 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; |
1838 | 1851 | ||
@@ -1886,6 +1899,13 @@ void tcp_v4_destroy_sock(struct sock *sk) | |||
1886 | sk->sk_sndmsg_page = NULL; | 1899 | sk->sk_sndmsg_page = NULL; |
1887 | } | 1900 | } |
1888 | 1901 | ||
1902 | /* TCP Cookie Transactions */ | ||
1903 | if (tp->cookie_values != NULL) { | ||
1904 | kref_put(&tp->cookie_values->kref, | ||
1905 | tcp_cookie_values_release); | ||
1906 | tp->cookie_values = NULL; | ||
1907 | } | ||
1908 | |||
1889 | percpu_counter_dec(&tcp_sockets_allocated); | 1909 | percpu_counter_dec(&tcp_sockets_allocated); |
1890 | } | 1910 | } |
1891 | 1911 | ||
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index d3f6bbfc76f0..96852af43ca7 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -383,14 +383,43 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
383 | const struct inet_request_sock *ireq = inet_rsk(req); | 383 | const struct inet_request_sock *ireq = inet_rsk(req); |
384 | struct tcp_request_sock *treq = tcp_rsk(req); | 384 | struct tcp_request_sock *treq = tcp_rsk(req); |
385 | struct inet_connection_sock *newicsk = inet_csk(newsk); | 385 | struct inet_connection_sock *newicsk = inet_csk(newsk); |
386 | struct tcp_sock *newtp; | 386 | struct tcp_sock *newtp = tcp_sk(newsk); |
387 | struct tcp_sock *oldtp = tcp_sk(sk); | ||
388 | struct tcp_cookie_values *oldcvp = oldtp->cookie_values; | ||
389 | |||
390 | /* TCP Cookie Transactions require space for the cookie pair, | ||
391 | * as it differs for each connection. There is no need to | ||
392 | * copy any s_data_payload stored at the original socket. | ||
393 | * Failure will prevent resuming the connection. | ||
394 | * | ||
395 | * Presumed copied, in order of appearance: | ||
396 | * cookie_in_always, cookie_out_never | ||
397 | */ | ||
398 | if (oldcvp != NULL) { | ||
399 | struct tcp_cookie_values *newcvp = | ||
400 | kzalloc(sizeof(*newtp->cookie_values), | ||
401 | GFP_ATOMIC); | ||
402 | |||
403 | if (newcvp != NULL) { | ||
404 | kref_init(&newcvp->kref); | ||
405 | newcvp->cookie_desired = | ||
406 | oldcvp->cookie_desired; | ||
407 | newtp->cookie_values = newcvp; | ||
408 | } else { | ||
409 | /* Not Yet Implemented */ | ||
410 | newtp->cookie_values = NULL; | ||
411 | } | ||
412 | } | ||
387 | 413 | ||
388 | /* Now setup tcp_sock */ | 414 | /* Now setup tcp_sock */ |
389 | newtp = tcp_sk(newsk); | ||
390 | newtp->pred_flags = 0; | 415 | newtp->pred_flags = 0; |
391 | newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1; | 416 | |
392 | newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = treq->snt_isn + 1; | 417 | newtp->rcv_wup = newtp->copied_seq = |
393 | newtp->snd_up = treq->snt_isn + 1; | 418 | newtp->rcv_nxt = treq->rcv_isn + 1; |
419 | |||
420 | newtp->snd_sml = newtp->snd_una = | ||
421 | newtp->snd_nxt = newtp->snd_up = | ||
422 | treq->snt_isn + 1 + tcp_s_data_size(oldtp); | ||
394 | 423 | ||
395 | tcp_prequeue_init(newtp); | 424 | tcp_prequeue_init(newtp); |
396 | 425 | ||
@@ -423,8 +452,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
423 | tcp_set_ca_state(newsk, TCP_CA_Open); | 452 | tcp_set_ca_state(newsk, TCP_CA_Open); |
424 | tcp_init_xmit_timers(newsk); | 453 | tcp_init_xmit_timers(newsk); |
425 | skb_queue_head_init(&newtp->out_of_order_queue); | 454 | skb_queue_head_init(&newtp->out_of_order_queue); |
426 | newtp->write_seq = treq->snt_isn + 1; | 455 | newtp->write_seq = newtp->pushed_seq = |
427 | newtp->pushed_seq = newtp->write_seq; | 456 | treq->snt_isn + 1 + tcp_s_data_size(oldtp); |
428 | 457 | ||
429 | newtp->rx_opt.saw_tstamp = 0; | 458 | newtp->rx_opt.saw_tstamp = 0; |
430 | 459 | ||
@@ -590,7 +619,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, | |||
590 | * Invalid ACK: reset will be sent by listening socket | 619 | * Invalid ACK: reset will be sent by listening socket |
591 | */ | 620 | */ |
592 | if ((flg & TCP_FLAG_ACK) && | 621 | if ((flg & TCP_FLAG_ACK) && |
593 | (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1)) | 622 | (TCP_SKB_CB(skb)->ack_seq != |
623 | tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk)))) | ||
594 | return sk; | 624 | return sk; |
595 | 625 | ||
596 | /* Also, it would be not so bad idea to check rcv_tsecr, which | 626 | /* Also, it would be not so bad idea to check rcv_tsecr, which |