summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetar Penkov <ppenkov@google.com>2019-07-29 12:59:14 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-07-31 00:03:05 -0400
commit9349d600fb6a1ca0aaeb515523e1bb5409483d76 (patch)
tree214a3a4b68356a5977e75afe2117538810b64d10
parent965112785e4bd4355262c6c5a32ea8f349adb401 (diff)
tcp: add skb-less helpers to retrieve SYN cookie
This patch allows generation of a SYN cookie before an SKB has been allocated, as is the case at XDP. Signed-off-by: Petar Penkov <ppenkov@google.com> Reviewed-by: Lorenz Bauer <lmb@cloudflare.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--include/net/tcp.h10
-rw-r--r--net/ipv4/tcp_input.c73
-rw-r--r--net/ipv4/tcp_ipv4.c15
-rw-r--r--net/ipv6/tcp_ipv6.c15
4 files changed, 113 insertions, 0 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e5cf514ba118..fb7e153aecc5 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -415,6 +415,16 @@ void tcp_parse_options(const struct net *net, const struct sk_buff *skb,
415const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); 415const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
416 416
417/* 417/*
418 * BPF SKB-less helpers
419 */
420u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
421 struct tcphdr *th, u32 *cookie);
422u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph,
423 struct tcphdr *th, u32 *cookie);
424u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
425 const struct tcp_request_sock_ops *af_ops,
426 struct sock *sk, struct tcphdr *th);
427/*
418 * TCP v4 functions exported for the inet6 API 428 * TCP v4 functions exported for the inet6 API
419 */ 429 */
420 430
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 8892df6de1d4..706cbb3b2986 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3782,6 +3782,49 @@ static void smc_parse_options(const struct tcphdr *th,
3782#endif 3782#endif
3783} 3783}
3784 3784
3785/* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped
3786 * value on success.
3787 */
3788static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
3789{
3790 const unsigned char *ptr = (const unsigned char *)(th + 1);
3791 int length = (th->doff * 4) - sizeof(struct tcphdr);
3792 u16 mss = 0;
3793
3794 while (length > 0) {
3795 int opcode = *ptr++;
3796 int opsize;
3797
3798 switch (opcode) {
3799 case TCPOPT_EOL:
3800 return mss;
3801 case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
3802 length--;
3803 continue;
3804 default:
3805 if (length < 2)
3806 return mss;
3807 opsize = *ptr++;
3808 if (opsize < 2) /* "silly options" */
3809 return mss;
3810 if (opsize > length)
3811 return mss; /* fail on partial options */
3812 if (opcode == TCPOPT_MSS && opsize == TCPOLEN_MSS) {
3813 u16 in_mss = get_unaligned_be16(ptr);
3814
3815 if (in_mss) {
3816 if (user_mss && user_mss < in_mss)
3817 in_mss = user_mss;
3818 mss = in_mss;
3819 }
3820 }
3821 ptr += opsize - 2;
3822 length -= opsize;
3823 }
3824 }
3825 return mss;
3826}
3827
3785/* Look for tcp options. Normally only called on SYN and SYNACK packets. 3828/* Look for tcp options. Normally only called on SYN and SYNACK packets.
3786 * But, this can also be called on packets in the established flow when 3829 * But, this can also be called on packets in the established flow when
3787 * the fast version below fails. 3830 * the fast version below fails.
@@ -6464,6 +6507,36 @@ static void tcp_reqsk_record_syn(const struct sock *sk,
6464 } 6507 }
6465} 6508}
6466 6509
6510/* If a SYN cookie is required and supported, returns a clamped MSS value to be
6511 * used for SYN cookie generation.
6512 */
6513u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
6514 const struct tcp_request_sock_ops *af_ops,
6515 struct sock *sk, struct tcphdr *th)
6516{
6517 struct tcp_sock *tp = tcp_sk(sk);
6518 u16 mss;
6519
6520 if (sock_net(sk)->ipv4.sysctl_tcp_syncookies != 2 &&
6521 !inet_csk_reqsk_queue_is_full(sk))
6522 return 0;
6523
6524 if (!tcp_syn_flood_action(sk, rsk_ops->slab_name))
6525 return 0;
6526
6527 if (sk_acceptq_is_full(sk)) {
6528 NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
6529 return 0;
6530 }
6531
6532 mss = tcp_parse_mss_option(th, tp->rx_opt.user_mss);
6533 if (!mss)
6534 mss = af_ops->mss_clamp;
6535
6536 return mss;
6537}
6538EXPORT_SYMBOL_GPL(tcp_get_syncookie_mss);
6539
6467int tcp_conn_request(struct request_sock_ops *rsk_ops, 6540int tcp_conn_request(struct request_sock_ops *rsk_ops,
6468 const struct tcp_request_sock_ops *af_ops, 6541 const struct tcp_request_sock_ops *af_ops,
6469 struct sock *sk, struct sk_buff *skb) 6542 struct sock *sk, struct sk_buff *skb)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d57641cb3477..10217393cda6 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1515,6 +1515,21 @@ static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb)
1515 return sk; 1515 return sk;
1516} 1516}
1517 1517
1518u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
1519 struct tcphdr *th, u32 *cookie)
1520{
1521 u16 mss = 0;
1522#ifdef CONFIG_SYN_COOKIES
1523 mss = tcp_get_syncookie_mss(&tcp_request_sock_ops,
1524 &tcp_request_sock_ipv4_ops, sk, th);
1525 if (mss) {
1526 *cookie = __cookie_v4_init_sequence(iph, th, &mss);
1527 tcp_synq_overflow(sk);
1528 }
1529#endif
1530 return mss;
1531}
1532
1518/* The socket must have it's spinlock held when we get 1533/* The socket must have it's spinlock held when we get
1519 * here, unless it is a TCP_LISTEN socket. 1534 * here, unless it is a TCP_LISTEN socket.
1520 * 1535 *
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5da069e91cac..87f44d3250ee 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1063,6 +1063,21 @@ static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb)
1063 return sk; 1063 return sk;
1064} 1064}
1065 1065
1066u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph,
1067 struct tcphdr *th, u32 *cookie)
1068{
1069 u16 mss = 0;
1070#ifdef CONFIG_SYN_COOKIES
1071 mss = tcp_get_syncookie_mss(&tcp6_request_sock_ops,
1072 &tcp_request_sock_ipv6_ops, sk, th);
1073 if (mss) {
1074 *cookie = __cookie_v6_init_sequence(iph, th, &mss);
1075 tcp_synq_overflow(sk);
1076 }
1077#endif
1078 return mss;
1079}
1080
1066static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) 1081static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1067{ 1082{
1068 if (skb->protocol == htons(ETH_P_IP)) 1083 if (skb->protocol == htons(ETH_P_IP))