Commit 70d66244 authored by Petar Penkov's avatar Petar Penkov Committed by Alexei Starovoitov

bpf: add bpf_tcp_gen_syncookie helper

This helper function allows BPF programs to try to generate SYN
cookies, given a reference to a listener socket. The function works
from XDP and with an skb context since bpf_skc_lookup_tcp can lookup a
socket in both cases.
Signed-off-by: default avatarPetar Penkov <ppenkov@google.com>
Suggested-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarLorenz Bauer <lmb@cloudflare.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 9349d600
...@@ -2714,6 +2714,33 @@ union bpf_attr { ...@@ -2714,6 +2714,33 @@ union bpf_attr {
* **-EPERM** if no permission to send the *sig*. * **-EPERM** if no permission to send the *sig*.
* *
* **-EAGAIN** if bpf program can try again. * **-EAGAIN** if bpf program can try again.
*
* s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
* Description
* Try to issue a SYN cookie for the packet with corresponding
* IP/TCP headers, *iph* and *th*, on the listening socket in *sk*.
*
* *iph* points to the start of the IPv4 or IPv6 header, while
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
* **sizeof**\ (**struct ip6hdr**).
*
* *th* points to the start of the TCP header, while *th_len*
* contains the length of the TCP header.
*
* Return
* On success, lower 32 bits hold the generated SYN cookie in
* followed by 16 bits which hold the MSS value for that cookie,
* and the top 16 bits are unused.
*
* On failure, the returned value is one of the following:
*
* **-EINVAL** SYN cookie cannot be issued due to error
*
* **-ENOENT** SYN cookie should not be issued (no SYN flood)
*
* **-EOPNOTSUPP** kernel configuration does not enable SYN cookies
*
* **-EPROTONOSUPPORT** IP packet version is not 4 or 6
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -2825,7 +2852,8 @@ union bpf_attr { ...@@ -2825,7 +2852,8 @@ union bpf_attr {
FN(strtoul), \ FN(strtoul), \
FN(sk_storage_get), \ FN(sk_storage_get), \
FN(sk_storage_delete), \ FN(sk_storage_delete), \
FN(send_signal), FN(send_signal), \
FN(tcp_gen_syncookie),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
...@@ -5855,6 +5855,75 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = { ...@@ -5855,6 +5855,75 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {
.arg5_type = ARG_CONST_SIZE, .arg5_type = ARG_CONST_SIZE,
}; };
BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
struct tcphdr *, th, u32, th_len)
{
#ifdef CONFIG_SYN_COOKIES
u32 cookie;
u16 mss;
if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
return -EINVAL;
if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
return -EINVAL;
if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
return -ENOENT;
if (!th->syn || th->ack || th->fin || th->rst)
return -EINVAL;
if (unlikely(iph_len < sizeof(struct iphdr)))
return -EINVAL;
/* Both struct iphdr and struct ipv6hdr have the version field at the
* same offset so we can cast to the shorter header (struct iphdr).
*/
switch (((struct iphdr *)iph)->version) {
case 4:
if (sk->sk_family == AF_INET6 && sk->sk_ipv6only)
return -EINVAL;
mss = tcp_v4_get_syncookie(sk, iph, th, &cookie);
break;
#if IS_BUILTIN(CONFIG_IPV6)
case 6:
if (unlikely(iph_len < sizeof(struct ipv6hdr)))
return -EINVAL;
if (sk->sk_family != AF_INET6)
return -EINVAL;
mss = tcp_v6_get_syncookie(sk, iph, th, &cookie);
break;
#endif /* CONFIG_IPV6 */
default:
return -EPROTONOSUPPORT;
}
if (mss <= 0)
return -ENOENT;
return cookie | ((u64)mss << 32);
#else
return -EOPNOTSUPP;
#endif /* CONFIG_SYN_COOKIES */
}
static const struct bpf_func_proto bpf_tcp_gen_syncookie_proto = {
.func = bpf_tcp_gen_syncookie,
.gpl_only = true, /* __cookie_v*_init_sequence() is GPL */
.pkt_access = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_SOCK_COMMON,
.arg2_type = ARG_PTR_TO_MEM,
.arg3_type = ARG_CONST_SIZE,
.arg4_type = ARG_PTR_TO_MEM,
.arg5_type = ARG_CONST_SIZE,
};
#endif /* CONFIG_INET */ #endif /* CONFIG_INET */
bool bpf_helper_changes_pkt_data(void *func) bool bpf_helper_changes_pkt_data(void *func)
...@@ -6144,6 +6213,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -6144,6 +6213,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_tcp_check_syncookie_proto; return &bpf_tcp_check_syncookie_proto;
case BPF_FUNC_skb_ecn_set_ce: case BPF_FUNC_skb_ecn_set_ce:
return &bpf_skb_ecn_set_ce_proto; return &bpf_skb_ecn_set_ce_proto;
case BPF_FUNC_tcp_gen_syncookie:
return &bpf_tcp_gen_syncookie_proto;
#endif #endif
default: default:
return bpf_base_func_proto(func_id); return bpf_base_func_proto(func_id);
...@@ -6183,6 +6254,8 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -6183,6 +6254,8 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_xdp_skc_lookup_tcp_proto; return &bpf_xdp_skc_lookup_tcp_proto;
case BPF_FUNC_tcp_check_syncookie: case BPF_FUNC_tcp_check_syncookie:
return &bpf_tcp_check_syncookie_proto; return &bpf_tcp_check_syncookie_proto;
case BPF_FUNC_tcp_gen_syncookie:
return &bpf_tcp_gen_syncookie_proto;
#endif #endif
default: default:
return bpf_base_func_proto(func_id); return bpf_base_func_proto(func_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment