forked from mirrors/linux
		
	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: Petar Penkov <ppenkov@google.com> Suggested-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Lorenz Bauer <lmb@cloudflare.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									9349d600fb
								
							
						
					
					
						commit
						70d6624431
					
				
					 2 changed files with 102 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -2714,6 +2714,33 @@ union bpf_attr {
 | 
			
		|||
 *		**-EPERM** if no permission to send the *sig*.
 | 
			
		||||
 *
 | 
			
		||||
 *		**-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)		\
 | 
			
		||||
	FN(unspec),			\
 | 
			
		||||
| 
						 | 
				
			
			@ -2825,7 +2852,8 @@ union bpf_attr {
 | 
			
		|||
	FN(strtoul),			\
 | 
			
		||||
	FN(sk_storage_get),		\
 | 
			
		||||
	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
 | 
			
		||||
 * function eBPF program intends to call
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5855,6 +5855,75 @@ static const struct bpf_func_proto bpf_tcp_check_syncookie_proto = {
 | 
			
		|||
	.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 */
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		|||
		return &bpf_tcp_check_syncookie_proto;
 | 
			
		||||
	case BPF_FUNC_skb_ecn_set_ce:
 | 
			
		||||
		return &bpf_skb_ecn_set_ce_proto;
 | 
			
		||||
	case BPF_FUNC_tcp_gen_syncookie:
 | 
			
		||||
		return &bpf_tcp_gen_syncookie_proto;
 | 
			
		||||
#endif
 | 
			
		||||
	default:
 | 
			
		||||
		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)
 | 
			
		|||
		return &bpf_xdp_skc_lookup_tcp_proto;
 | 
			
		||||
	case BPF_FUNC_tcp_check_syncookie:
 | 
			
		||||
		return &bpf_tcp_check_syncookie_proto;
 | 
			
		||||
	case BPF_FUNC_tcp_gen_syncookie:
 | 
			
		||||
		return &bpf_tcp_gen_syncookie_proto;
 | 
			
		||||
#endif
 | 
			
		||||
	default:
 | 
			
		||||
		return bpf_base_func_proto(func_id);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue