Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 90613
b: refs/heads/master
c: 4dfc281
h: refs/heads/master
i:
  90611: 8180c74
v: v3
  • Loading branch information
Florian Westphal authored and David S. Miller committed Apr 10, 2008
1 parent c31472e commit 4b8e680
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 18 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 15be75cdb5db442d0e33d37b20832b88f3ccd383
refs/heads/master: 4dfc2817025965a2fc78a18c50f540736a6b5c24
2 changes: 1 addition & 1 deletion trunk/include/net/request_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct request_sock {
struct request_sock *dl_next; /* Must be first member! */
u16 mss;
u8 retrans;
u8 __pad;
u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */
/* The following two fields can be easily recomputed I think -AK */
u32 window_clamp; /* window clamp at creation time */
u32 rcv_wnd; /* rcv_wnd offered first time */
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,9 @@ extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mss);

extern __u32 cookie_init_timestamp(struct request_sock *req);
extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt);

/* From net/ipv6/syncookies.c */
extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb,
Expand Down Expand Up @@ -956,6 +959,7 @@ static inline void tcp_openreq_init(struct request_sock *req,
struct inet_request_sock *ireq = inet_rsk(req);

req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
req->cookie_ts = 0;
tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
req->mss = rx_opt->mss_clamp;
req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
Expand Down
89 changes: 84 additions & 5 deletions trunk/net/ipv4/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include <linux/kernel.h>
#include <net/tcp.h>

/* Timestamps: lowest 9 bits store TCP options */
#define TSBITS 9
#define TSMASK (((__u32)1 << TSBITS) - 1)

extern int sysctl_tcp_syncookies;

__u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
Expand Down Expand Up @@ -51,6 +55,39 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
return tmp[17];
}


/*
* when syncookies are in effect and tcp timestamps are enabled we encode
* tcp options in the lowest 9 bits of the timestamp value that will be
* sent in the syn-ack.
* Since subsequent timestamps use the normal tcp_time_stamp value, we
* must make sure that the resulting initial timestamp is <= tcp_time_stamp.
*/
__u32 cookie_init_timestamp(struct request_sock *req)
{
struct inet_request_sock *ireq;
u32 ts, ts_now = tcp_time_stamp;
u32 options = 0;

ireq = inet_rsk(req);
if (ireq->wscale_ok) {
options = ireq->snd_wscale;
options |= ireq->rcv_wscale << 4;
}
options |= ireq->sack_ok << 8;

ts = ts_now & ~TSMASK;
ts |= options;
if (ts > ts_now) {
ts >>= TSBITS;
ts--;
ts <<= TSBITS;
ts |= options;
}
return ts;
}


static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport,
__be16 dport, __u32 sseq, __u32 count,
__u32 data)
Expand Down Expand Up @@ -185,6 +222,35 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
return child;
}


/*
* when syncookies are in effect and tcp timestamps are enabled we stored
* additional tcp options in the timestamp.
* This extracts these options from the timestamp echo.
*
* The lowest 4 bits are for snd_wscale
* The next 4 lsb are for rcv_wscale
* The next lsb is for sack_ok
*/
void cookie_check_timestamp(struct tcp_options_received *tcp_opt)
{
/* echoed timestamp, 9 lowest bits contain options */
u32 options = tcp_opt->rcv_tsecr & TSMASK;

tcp_opt->snd_wscale = options & 0xf;
options >>= 4;
tcp_opt->rcv_wscale = options & 0xf;

tcp_opt->sack_ok = (options >> 4) & 0x1;

if (tcp_opt->sack_ok)
tcp_sack_reset(tcp_opt);

if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale)
tcp_opt->wscale_ok = 1;
}
EXPORT_SYMBOL(cookie_check_timestamp);

struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt)
{
Expand All @@ -198,6 +264,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
int mss;
struct rtable *rt;
__u8 rcv_wscale;
struct tcp_options_received tcp_opt;

if (!sysctl_tcp_syncookies || !th->ack)
goto out;
Expand All @@ -210,6 +277,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,

NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);

/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, 0);

if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);

ret = NULL;
req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */
if (!req)
Expand All @@ -228,6 +302,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
ireq->loc_addr = ip_hdr(skb)->daddr;
ireq->rmt_addr = ip_hdr(skb)->saddr;
ireq->opt = NULL;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->rcv_wscale = tcp_opt.rcv_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
ireq->tstamp_ok = tcp_opt.saw_tstamp;
req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;

/* We throwed the options of the initial SYN away, so we hope
* the ACK carries the same options again (see RFC1122 4.2.3.8)
Expand All @@ -242,8 +322,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
}
}

ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
ireq->wscale_ok = ireq->sack_ok = 0;
req->expires = 0UL;
req->retrans = 0;

Expand Down Expand Up @@ -272,11 +350,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
}

/* Try to redo what tcp_v4_send_synack did. */
req->window_clamp = dst_metric(&rt->u.dst, RTAX_WINDOW);
req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW);

tcp_select_initial_window(tcp_full_space(sk), req->mss,
&req->rcv_wnd, &req->window_clamp,
0, &rcv_wscale);
/* BTW win scale with syncookies is 0 by definition */
ireq->wscale_ok, &rcv_wscale);

ireq->rcv_wscale = rcv_wscale;

ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
Expand Down
5 changes: 2 additions & 3 deletions trunk/net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1299,10 +1299,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)

tcp_parse_options(skb, &tmp_opt, 0);

if (want_cookie) {
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
tmp_opt.saw_tstamp = 0;
}

if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) {
/* Some OSes (unknown ones, but I see them on web server, which
Expand Down Expand Up @@ -1330,6 +1328,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (want_cookie) {
#ifdef CONFIG_SYN_COOKIES
syn_flood_warning(skb);
req->cookie_ts = tmp_opt.tstamp_ok;
#endif
isn = cookie_v4_init_sequence(sk, skb, &req->mss);
} else if (!isn) {
Expand Down
6 changes: 5 additions & 1 deletion trunk/net/ipv4/tcp_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -2233,7 +2233,11 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,

/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
th->window = htons(min(req->rcv_wnd, 65535U));

#ifdef CONFIG_SYN_COOKIES
if (unlikely(req->cookie_ts))
TCP_SKB_CB(skb)->when = cookie_init_timestamp(req);
else
#endif
TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
Expand Down
20 changes: 16 additions & 4 deletions trunk/net/ipv6/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
int mss;
struct dst_entry *dst;
__u8 rcv_wscale;
struct tcp_options_received tcp_opt;

if (!sysctl_tcp_syncookies || !th->ack)
goto out;
Expand All @@ -182,6 +183,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)

NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);

/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, 0);

if (tcp_opt.saw_tstamp)
cookie_check_timestamp(&tcp_opt);

ret = NULL;
req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
if (!req)
Expand Down Expand Up @@ -216,8 +224,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)

req->expires = 0UL;
req->retrans = 0;
ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
ireq->wscale_ok = ireq->sack_ok = 0;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->rcv_wscale = tcp_opt.rcv_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
ireq->tstamp_ok = tcp_opt.saw_tstamp;
req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
treq->rcv_isn = ntohl(th->seq) - 1;
treq->snt_isn = cookie;

Expand Down Expand Up @@ -253,10 +265,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
goto out;
}

req->window_clamp = dst_metric(dst, RTAX_WINDOW);
req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW);
tcp_select_initial_window(tcp_full_space(sk), req->mss,
&req->rcv_wnd, &req->window_clamp,
0, &rcv_wscale);
ireq->wscale_ok, &rcv_wscale);

ireq->rcv_wscale = rcv_wscale;

Expand Down
5 changes: 2 additions & 3 deletions trunk/net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1290,10 +1290,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)

tcp_parse_options(skb, &tmp_opt, 0);

if (want_cookie) {
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
tmp_opt.saw_tstamp = 0;
}

tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
tcp_openreq_init(req, &tmp_opt, skb);
Expand All @@ -1307,6 +1305,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)

if (want_cookie) {
isn = cookie_v6_init_sequence(sk, skb, &req->mss);
req->cookie_ts = tmp_opt.tstamp_ok;
} else if (!isn) {
if (ipv6_opt_accepted(sk, skb) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
Expand Down

0 comments on commit 4b8e680

Please sign in to comment.