|
@@ -19,6 +19,10 @@
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
#include <net/tcp.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;
|
|
extern int sysctl_tcp_syncookies;
|
|
|
|
|
|
__u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
|
|
__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,
|
|
return tmp[17];
|
|
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,
|
|
static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport,
|
|
__be16 dport, __u32 sseq, __u32 count,
|
|
__be16 dport, __u32 sseq, __u32 count,
|
|
__u32 data)
|
|
__u32 data)
|
|
@@ -185,6 +222,35 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
|
|
return child;
|
|
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 sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
|
struct ip_options *opt)
|
|
struct ip_options *opt)
|
|
{
|
|
{
|
|
@@ -198,6 +264,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
|
int mss;
|
|
int mss;
|
|
struct rtable *rt;
|
|
struct rtable *rt;
|
|
__u8 rcv_wscale;
|
|
__u8 rcv_wscale;
|
|
|
|
+ struct tcp_options_received tcp_opt;
|
|
|
|
|
|
if (!sysctl_tcp_syncookies || !th->ack)
|
|
if (!sysctl_tcp_syncookies || !th->ack)
|
|
goto out;
|
|
goto out;
|
|
@@ -210,6 +277,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
|
NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);
|
|
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;
|
|
ret = NULL;
|
|
req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */
|
|
req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */
|
|
if (!req)
|
|
if (!req)
|
|
@@ -228,6 +302,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
|
ireq->loc_addr = ip_hdr(skb)->daddr;
|
|
ireq->loc_addr = ip_hdr(skb)->daddr;
|
|
ireq->rmt_addr = ip_hdr(skb)->saddr;
|
|
ireq->rmt_addr = ip_hdr(skb)->saddr;
|
|
ireq->opt = NULL;
|
|
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
|
|
/* 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)
|
|
* 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,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
|
|
|
|
- ireq->wscale_ok = ireq->sack_ok = 0;
|
|
|
|
req->expires = 0UL;
|
|
req->expires = 0UL;
|
|
req->retrans = 0;
|
|
req->retrans = 0;
|
|
|
|
|
|
@@ -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. */
|
|
/* 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,
|
|
tcp_select_initial_window(tcp_full_space(sk), req->mss,
|
|
&req->rcv_wnd, &req->window_clamp,
|
|
&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;
|
|
ireq->rcv_wscale = rcv_wscale;
|
|
|
|
|
|
ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
|
|
ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
|