aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Allen Simpson <william.allen.simpson@gmail.com>2009-12-02 13:17:05 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-03 01:07:25 -0500
commit435cf559f02ea3a3159eb316f97dc88bdebe9432 (patch)
tree0b2a7e9110c46b193176b0a59fe5689eae7c18f3
parent519855c508b9a17878c0977a3cdefc09b59b30df (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>
-rw-r--r--include/linux/tcp.h29
-rw-r--r--include/net/tcp.h83
-rw-r--r--net/ipv4/tcp_ipv4.c20
-rw-r--r--net/ipv4/tcp_minisocks.c46
-rw-r--r--net/ipv6/tcp_ipv6.c13
5 files changed, 177 insertions, 14 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index eaa3113b3786..7fee8a4df931 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -247,31 +247,38 @@ struct tcp_options_received {
247 sack_ok : 4, /* SACK seen on SYN packet */ 247 sack_ok : 4, /* SACK seen on SYN packet */
248 snd_wscale : 4, /* Window scaling received from sender */ 248 snd_wscale : 4, /* Window scaling received from sender */
249 rcv_wscale : 4; /* Window scaling to send to receiver */ 249 rcv_wscale : 4; /* Window scaling to send to receiver */
250/* SACKs data */ 250 u8 cookie_plus:6, /* bytes in authenticator/cookie option */
251 cookie_out_never:1,
252 cookie_in_always:1;
251 u8 num_sacks; /* Number of SACK blocks */ 253 u8 num_sacks; /* Number of SACK blocks */
252 u16 user_mss; /* mss requested by user in ioctl */ 254 u16 user_mss; /* mss requested by user in ioctl */
253 u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ 255 u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
254}; 256};
255 257
256static inline void tcp_clear_options(struct tcp_options_received *rx_opt) 258static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
257{ 259{
258 rx_opt->tstamp_ok = rx_opt->sack_ok = rx_opt->wscale_ok = rx_opt->snd_wscale = 0; 260 rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
261 rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
262 rx_opt->cookie_plus = 0;
259} 263}
260 264
261/* This is the max number of SACKS that we'll generate and process. It's safe 265/* This is the max number of SACKS that we'll generate and process. It's safe
262 * to increse this, although since: 266 * to increase this, although since:
263 * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8) 267 * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8)
264 * only four options will fit in a standard TCP header */ 268 * only four options will fit in a standard TCP header */
265#define TCP_NUM_SACKS 4 269#define TCP_NUM_SACKS 4
266 270
271struct tcp_cookie_values;
272struct tcp_request_sock_ops;
273
267struct tcp_request_sock { 274struct tcp_request_sock {
268 struct inet_request_sock req; 275 struct inet_request_sock req;
269#ifdef CONFIG_TCP_MD5SIG 276#ifdef CONFIG_TCP_MD5SIG
270 /* Only used by TCP MD5 Signature so far. */ 277 /* Only used by TCP MD5 Signature so far. */
271 const struct tcp_request_sock_ops *af_specific; 278 const struct tcp_request_sock_ops *af_specific;
272#endif 279#endif
273 u32 rcv_isn; 280 u32 rcv_isn;
274 u32 snt_isn; 281 u32 snt_isn;
275}; 282};
276 283
277static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) 284static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
@@ -441,6 +448,12 @@ struct tcp_sock {
441/* TCP MD5 Signature Option information */ 448/* TCP MD5 Signature Option information */
442 struct tcp_md5sig_info *md5sig_info; 449 struct tcp_md5sig_info *md5sig_info;
443#endif 450#endif
451
452 /* When the cookie options are generated and exchanged, then this
453 * object holds a reference to them (cookie_values->kref). Also
454 * contains related tcp_cookie_transactions fields.
455 */
456 struct tcp_cookie_values *cookie_values;
444}; 457};
445 458
446static inline struct tcp_sock *tcp_sk(const struct sock *sk) 459static inline struct tcp_sock *tcp_sk(const struct sock *sk)
@@ -459,6 +472,10 @@ struct tcp_timewait_sock {
459 u16 tw_md5_keylen; 472 u16 tw_md5_keylen;
460 u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN]; 473 u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN];
461#endif 474#endif
475 /* Few sockets in timewait have cookies; in that case, then this
476 * object holds a reference to them (tw_cookie_values->kref).
477 */
478 struct tcp_cookie_values *tw_cookie_values;
462}; 479};
463 480
464static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) 481static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 738b65f01e26..f9abd9becabd 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -30,6 +30,7 @@
30#include <linux/dmaengine.h> 30#include <linux/dmaengine.h>
31#include <linux/crypto.h> 31#include <linux/crypto.h>
32#include <linux/cryptohash.h> 32#include <linux/cryptohash.h>
33#include <linux/kref.h>
33 34
34#include <net/inet_connection_sock.h> 35#include <net/inet_connection_sock.h>
35#include <net/inet_timewait_sock.h> 36#include <net/inet_timewait_sock.h>
@@ -164,6 +165,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
164#define TCPOPT_SACK 5 /* SACK Block */ 165#define TCPOPT_SACK 5 /* SACK Block */
165#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ 166#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
166#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ 167#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
168#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
167 169
168/* 170/*
169 * TCP option lengths 171 * TCP option lengths
@@ -174,6 +176,10 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
174#define TCPOLEN_SACK_PERM 2 176#define TCPOLEN_SACK_PERM 2
175#define TCPOLEN_TIMESTAMP 10 177#define TCPOLEN_TIMESTAMP 10
176#define TCPOLEN_MD5SIG 18 178#define TCPOLEN_MD5SIG 18
179#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
180#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
181#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
182#define TCPOLEN_COOKIE_MAX (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
177 183
178/* But this is what stacks really send out. */ 184/* But this is what stacks really send out. */
179#define TCPOLEN_TSTAMP_ALIGNED 12 185#define TCPOLEN_TSTAMP_ALIGNED 12
@@ -1482,6 +1488,83 @@ struct tcp_request_sock_ops {
1482 1488
1483extern int tcp_cookie_generator(u32 *bakery); 1489extern int tcp_cookie_generator(u32 *bakery);
1484 1490
1491/**
1492 * struct tcp_cookie_values - each socket needs extra space for the
1493 * cookies, together with (optional) space for any SYN data.
1494 *
1495 * A tcp_sock contains a pointer to the current value, and this is
1496 * cloned to the tcp_timewait_sock.
1497 *
1498 * @cookie_pair: variable data from the option exchange.
1499 *
1500 * @cookie_desired: user specified tcpct_cookie_desired. Zero
1501 * indicates default (sysctl_tcp_cookie_size).
1502 * After cookie sent, remembers size of cookie.
1503 * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX.
1504 *
1505 * @s_data_desired: user specified tcpct_s_data_desired. When the
1506 * constant payload is specified (@s_data_constant),
1507 * holds its length instead.
1508 * Range 0 to TCP_MSS_DESIRED.
1509 *
1510 * @s_data_payload: constant data that is to be included in the
1511 * payload of SYN or SYNACK segments when the
1512 * cookie option is present.
1513 */
1514struct tcp_cookie_values {
1515 struct kref kref;
1516 u8 cookie_pair[TCP_COOKIE_PAIR_SIZE];
1517 u8 cookie_pair_size;
1518 u8 cookie_desired;
1519 u16 s_data_desired:11,
1520 s_data_constant:1,
1521 s_data_in:1,
1522 s_data_out:1,
1523 s_data_unused:2;
1524 u8 s_data_payload[0];
1525};
1526
1527static inline void tcp_cookie_values_release(struct kref *kref)
1528{
1529 kfree(container_of(kref, struct tcp_cookie_values, kref));
1530}
1531
1532/* The length of constant payload data. Note that s_data_desired is
1533 * overloaded, depending on s_data_constant: either the length of constant
1534 * data (returned here) or the limit on variable data.
1535 */
1536static inline int tcp_s_data_size(const struct tcp_sock *tp)
1537{
1538 return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant)
1539 ? tp->cookie_values->s_data_desired
1540 : 0;
1541}
1542
1543/**
1544 * struct tcp_extend_values - tcp_ipv?.c to tcp_output.c workspace.
1545 *
1546 * As tcp_request_sock has already been extended in other places, the
1547 * only remaining method is to pass stack values along as function
1548 * parameters. These parameters are not needed after sending SYNACK.
1549 *
1550 * @cookie_bakery: cryptographic secret and message workspace.
1551 *
1552 * @cookie_plus: bytes in authenticator/cookie option, copied from
1553 * struct tcp_options_received (above).
1554 */
1555struct tcp_extend_values {
1556 struct request_values rv;
1557 u32 cookie_bakery[COOKIE_WORKSPACE_WORDS];
1558 u8 cookie_plus:6,
1559 cookie_out_never:1,
1560 cookie_in_always:1;
1561};
1562
1563static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp)
1564{
1565 return (struct tcp_extend_values *)rvp;
1566}
1567
1485extern void tcp_v4_init(void); 1568extern void tcp_v4_init(void);
1486extern void tcp_init(void); 1569extern void tcp_init(void);
1487 1570
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
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index da6e24416d75..f2ec38289a4a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1864,6 +1864,19 @@ static int tcp_v6_init_sock(struct sock *sk)
1864 tp->af_specific = &tcp_sock_ipv6_specific; 1864 tp->af_specific = &tcp_sock_ipv6_specific;
1865#endif 1865#endif
1866 1866
1867 /* TCP Cookie Transactions */
1868 if (sysctl_tcp_cookie_size > 0) {
1869 /* Default, cookies without s_data_payload. */
1870 tp->cookie_values =
1871 kzalloc(sizeof(*tp->cookie_values),
1872 sk->sk_allocation);
1873 if (tp->cookie_values != NULL)
1874 kref_init(&tp->cookie_values->kref);
1875 }
1876 /* Presumed zeroed, in order of appearance:
1877 * cookie_in_always, cookie_out_never,
1878 * s_data_constant, s_data_in, s_data_out
1879 */
1867 sk->sk_sndbuf = sysctl_tcp_wmem[1]; 1880 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1868 sk->sk_rcvbuf = sysctl_tcp_rmem[1]; 1881 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1869 1882