133965Sjdp// SPDX-License-Identifier: GPL-2.0-only
2218822Sdim/* (C) 1999-2001 Paul `Rusty' Russell
3218822Sdim * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
433965Sjdp */
5130561Sobrien
633965Sjdp#include <linux/module.h>
7130561Sobrien#include <net/ip.h>
8130561Sobrien#include <net/tcp.h>
9130561Sobrien#include <net/route.h>
10130561Sobrien#include <net/dst.h>
1133965Sjdp#include <net/netfilter/ipv4/nf_reject.h>
12130561Sobrien#include <linux/netfilter_ipv4.h>
13130561Sobrien#include <linux/netfilter_bridge.h>
14130561Sobrien
15130561Sobrienstatic int nf_reject_iphdr_validate(struct sk_buff *skb)
1633965Sjdp{
17130561Sobrien	struct iphdr *iph;
18130561Sobrien	u32 len;
19218822Sdim
2033965Sjdp	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
2138889Sjdp		return 0;
22218822Sdim
2338889Sjdp	iph = ip_hdr(skb);
2460484Sobrien	if (iph->ihl < 5 || iph->version != 4)
2533965Sjdp		return 0;
2660484Sobrien
2785815Sobrien	len = ntohs(iph->tot_len);
2833965Sjdp	if (skb->len < len)
29218822Sdim		return 0;
30218822Sdim	else if (len < (iph->ihl*4))
31218822Sdim		return 0;
32218822Sdim
33218822Sdim	if (!pskb_may_pull(skb, iph->ihl*4))
34218822Sdim		return 0;
35218822Sdim
36218822Sdim	return 1;
37218822Sdim}
38218822Sdim
39218822Sdimstruct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net,
40218822Sdim					   struct sk_buff *oldskb,
41218822Sdim					   const struct net_device *dev,
42218822Sdim					   int hook)
43218822Sdim{
44218822Sdim	const struct tcphdr *oth;
45218822Sdim	struct sk_buff *nskb;
46218822Sdim	struct iphdr *niph;
47218822Sdim	struct tcphdr _oth;
48218822Sdim
49218822Sdim	if (!nf_reject_iphdr_validate(oldskb))
50130561Sobrien		return NULL;
5189857Sobrien
5260484Sobrien	oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
5360484Sobrien	if (!oth)
5460484Sobrien		return NULL;
5560484Sobrien
5633965Sjdp	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
5733965Sjdp			 LL_MAX_HEADER, GFP_ATOMIC);
5833965Sjdp	if (!nskb)
5933965Sjdp		return NULL;
6033965Sjdp
6133965Sjdp	nskb->dev = (struct net_device *)dev;
6285815Sobrien
6360484Sobrien	skb_reserve(nskb, LL_MAX_HEADER);
6433965Sjdp	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
6533965Sjdp				   READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
6633965Sjdp	nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
6733965Sjdp	niph->tot_len = htons(nskb->len);
6885815Sobrien	ip_send_check(niph);
6933965Sjdp
7033965Sjdp	return nskb;
7133965Sjdp}
7233965SjdpEXPORT_SYMBOL_GPL(nf_reject_skb_v4_tcp_reset);
7333965Sjdp
7433965Sjdpstruct sk_buff *nf_reject_skb_v4_unreach(struct net *net,
7533965Sjdp					 struct sk_buff *oldskb,
7633965Sjdp					 const struct net_device *dev,
7733965Sjdp					 int hook, u8 code)
7833965Sjdp{
7933965Sjdp	struct sk_buff *nskb;
8033965Sjdp	struct iphdr *niph;
8133965Sjdp	struct icmphdr *icmph;
82130561Sobrien	unsigned int len;
83130561Sobrien	int dataoff;
8460484Sobrien	__wsum csum;
8560484Sobrien	u8 proto;
8633965Sjdp
87218822Sdim	if (!nf_reject_iphdr_validate(oldskb))
88218822Sdim		return NULL;
8933965Sjdp
9033965Sjdp	/* IP header checks: fragment. */
9185815Sobrien	if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
9260484Sobrien		return NULL;
9333965Sjdp
9433965Sjdp	/* RFC says return as much as we can without exceeding 576 bytes. */
9533965Sjdp	len = min_t(unsigned int, 536, oldskb->len);
9633965Sjdp
9733965Sjdp	if (!pskb_may_pull(oldskb, len))
9860484Sobrien		return NULL;
9933965Sjdp
10033965Sjdp	if (pskb_trim_rcsum(oldskb, ntohs(ip_hdr(oldskb)->tot_len)))
10133965Sjdp		return NULL;
10233965Sjdp
10333965Sjdp	dataoff = ip_hdrlen(oldskb);
10433965Sjdp	proto = ip_hdr(oldskb)->protocol;
10538889Sjdp
10660484Sobrien	if (!skb_csum_unnecessary(oldskb) &&
10738889Sjdp	    nf_reject_verify_csum(oldskb, dataoff, proto) &&
10885815Sobrien	    nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), proto))
10938889Sjdp		return NULL;
11033965Sjdp
11133965Sjdp	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) +
11260484Sobrien			 LL_MAX_HEADER + len, GFP_ATOMIC);
11360484Sobrien	if (!nskb)
11485815Sobrien		return NULL;
11533965Sjdp
11638889Sjdp	nskb->dev = (struct net_device *)dev;
11738889Sjdp
11833965Sjdp	skb_reserve(nskb, LL_MAX_HEADER);
11933965Sjdp	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
12089857Sobrien				   READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
12189857Sobrien
12289857Sobrien	skb_reset_transport_header(nskb);
12389857Sobrien	icmph = skb_put_zero(nskb, sizeof(struct icmphdr));
12489857Sobrien	icmph->type     = ICMP_DEST_UNREACH;
12589857Sobrien	icmph->code	= code;
12689857Sobrien
12789857Sobrien	skb_put_data(nskb, skb_network_header(oldskb), len);
12838889Sjdp
129104834Sobrien	csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0);
130104834Sobrien	icmph->checksum = csum_fold(csum);
13189857Sobrien
13260484Sobrien	niph->tot_len	= htons(nskb->len);
13389857Sobrien	ip_send_check(niph);
13489857Sobrien
13589857Sobrien	return nskb;
136130561Sobrien}
13789857SobrienEXPORT_SYMBOL_GPL(nf_reject_skb_v4_unreach);
13889857Sobrien
13989857Sobrienconst struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
14089857Sobrien					     struct tcphdr *_oth, int hook)
14189857Sobrien{
14289857Sobrien	const struct tcphdr *oth;
14389857Sobrien
14489857Sobrien	/* IP header checks: fragment. */
14589857Sobrien	if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
14689857Sobrien		return NULL;
14789857Sobrien
14889857Sobrien	if (ip_hdr(oldskb)->protocol != IPPROTO_TCP)
14989857Sobrien		return NULL;
15089857Sobrien
15189857Sobrien	oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
15289857Sobrien				 sizeof(struct tcphdr), _oth);
15389857Sobrien	if (oth == NULL)
154130561Sobrien		return NULL;
155130561Sobrien
15689857Sobrien	/* No RST for RST. */
15789857Sobrien	if (oth->rst)
15889857Sobrien		return NULL;
15989857Sobrien
16089857Sobrien	/* Check checksum */
16189857Sobrien	if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
16238889Sjdp		return NULL;
16389857Sobrien
16438889Sjdp	return oth;
16589857Sobrien}
16685815SobrienEXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_get);
16789857Sobrien
16889857Sobrienstruct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
16989857Sobrien				  const struct sk_buff *oldskb,
17038889Sjdp				  __u8 protocol, int ttl)
17189857Sobrien{
17289857Sobrien	struct iphdr *niph, *oiph = ip_hdr(oldskb);
17389857Sobrien
17489857Sobrien	skb_reset_network_header(nskb);
17589857Sobrien	niph = skb_put(nskb, sizeof(struct iphdr));
17689857Sobrien	niph->version	= 4;
17789857Sobrien	niph->ihl	= sizeof(struct iphdr) / 4;
17889857Sobrien	niph->tos	= 0;
17989857Sobrien	niph->id	= 0;
18089857Sobrien	niph->frag_off	= htons(IP_DF);
18189857Sobrien	niph->protocol	= protocol;
18289857Sobrien	niph->check	= 0;
18389857Sobrien	niph->saddr	= oiph->daddr;
18438889Sjdp	niph->daddr	= oiph->saddr;
18538889Sjdp	niph->ttl	= ttl;
18638889Sjdp
18738889Sjdp	nskb->protocol = htons(ETH_P_IP);
18889857Sobrien
18989857Sobrien	return niph;
19038889Sjdp}
19189857SobrienEXPORT_SYMBOL_GPL(nf_reject_iphdr_put);
19289857Sobrien
19389857Sobrienvoid nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
19489857Sobrien			  const struct tcphdr *oth)
19589857Sobrien{
19685815Sobrien	struct iphdr *niph = ip_hdr(nskb);
19789857Sobrien	struct tcphdr *tcph;
198104834Sobrien
19989857Sobrien	skb_reset_transport_header(nskb);
20089857Sobrien	tcph = skb_put_zero(nskb, sizeof(struct tcphdr));
20138889Sjdp	tcph->source	= oth->dest;
20238889Sjdp	tcph->dest	= oth->source;
20338889Sjdp	tcph->doff	= sizeof(struct tcphdr) / 4;
20489857Sobrien
20589857Sobrien	if (oth->ack) {
20638889Sjdp		tcph->seq = oth->ack_seq;
20789857Sobrien	} else {
20889857Sobrien		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
20989857Sobrien				      oldskb->len - ip_hdrlen(oldskb) -
21089857Sobrien				      (oth->doff << 2));
21189857Sobrien		tcph->ack = 1;
21238889Sjdp	}
21338889Sjdp
21489857Sobrien	tcph->rst	= 1;
21589857Sobrien	tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
21689857Sobrien				    niph->daddr, 0);
21789857Sobrien	nskb->ip_summed = CHECKSUM_PARTIAL;
21889857Sobrien	nskb->csum_start = (unsigned char *)tcph - nskb->head;
21938889Sjdp	nskb->csum_offset = offsetof(struct tcphdr, check);
22038889Sjdp}
22189857SobrienEXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
22289857Sobrien
22389857Sobrienstatic int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
22489857Sobrien{
22589857Sobrien	struct dst_entry *dst = NULL;
22638889Sjdp	struct flowi fl;
22785815Sobrien
22860484Sobrien	memset(&fl, 0, sizeof(struct flowi));
22938889Sjdp	fl.u.ip4.daddr = ip_hdr(skb_in)->saddr;
23089857Sobrien	nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
23189857Sobrien	if (!dst)
23289857Sobrien		return -1;
23338889Sjdp
23438889Sjdp	skb_dst_set(skb_in, dst);
23538889Sjdp	return 0;
23638889Sjdp}
23733965Sjdp
23833965Sjdp/* Send RST reply */
23933965Sjdpvoid nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
24033965Sjdp		   int hook)
24133965Sjdp{
24233965Sjdp	struct sk_buff *nskb;
24333965Sjdp	struct iphdr *niph;
24433965Sjdp	const struct tcphdr *oth;
24533965Sjdp	struct tcphdr _oth;
24633965Sjdp
24733965Sjdp	oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
248218822Sdim	if (!oth)
24933965Sjdp		return;
25033965Sjdp
25160484Sobrien	if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) &&
25238889Sjdp	    nf_reject_fill_skb_dst(oldskb) < 0)
25338889Sjdp		return;
25438889Sjdp
25538889Sjdp	if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
25638889Sjdp		return;
25738889Sjdp
25838889Sjdp	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
25938889Sjdp			 LL_MAX_HEADER, GFP_ATOMIC);
26033965Sjdp	if (!nskb)
26185815Sobrien		return;
26233965Sjdp
26333965Sjdp	/* ip_route_me_harder expects skb->dst to be set */
26433965Sjdp	skb_dst_set_noref(nskb, skb_dst(oldskb));
26533965Sjdp
26660484Sobrien	nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
26760484Sobrien
26860484Sobrien	skb_reserve(nskb, LL_MAX_HEADER);
26960484Sobrien	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
27060484Sobrien				   ip4_dst_hoplimit(skb_dst(nskb)));
27160484Sobrien	nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
272218822Sdim	if (ip_route_me_harder(net, sk, nskb, RTN_UNSPEC))
273218822Sdim		goto free_nskb;
27433965Sjdp
27533965Sjdp	niph = ip_hdr(nskb);
27633965Sjdp
27733965Sjdp	/* "Never happens" */
27833965Sjdp	if (nskb->len > dst_mtu(skb_dst(nskb)))
27933965Sjdp		goto free_nskb;
28033965Sjdp
28133965Sjdp	nf_ct_attach(nskb, oldskb);
28233965Sjdp	nf_ct_set_closing(skb_nfct(oldskb));
28333965Sjdp
28433965Sjdp#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
28533965Sjdp	/* If we use ip_local_out for bridged traffic, the MAC source on
28633965Sjdp	 * the RST will be ours, instead of the destination's.  This confuses
28733965Sjdp	 * some routers/firewalls, and they drop the packet.  So we need to
28833965Sjdp	 * build the eth header using the original destination's MAC as the
289218822Sdim	 * source, and send the RST packet directly.
29033965Sjdp	 */
29133965Sjdp	if (nf_bridge_info_exists(oldskb)) {
29260484Sobrien		struct ethhdr *oeth = eth_hdr(oldskb);
29338889Sjdp		struct net_device *br_indev;
29438889Sjdp
29538889Sjdp		br_indev = nf_bridge_get_physindev(oldskb, net);
29638889Sjdp		if (!br_indev)
29738889Sjdp			goto free_nskb;
29838889Sjdp
29938889Sjdp		nskb->dev = br_indev;
30033965Sjdp		niph->tot_len = htons(nskb->len);
30185815Sobrien		ip_send_check(niph);
30233965Sjdp		if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
30333965Sjdp				    oeth->h_source, oeth->h_dest, nskb->len) < 0)
30433965Sjdp			goto free_nskb;
30533965Sjdp		dev_queue_xmit(nskb);
30660484Sobrien	} else
30760484Sobrien#endif
30860484Sobrien		ip_local_out(net, nskb->sk, nskb);
30960484Sobrien
31060484Sobrien	return;
31160484Sobrien
312218822Sdim free_nskb:
313218822Sdim	kfree_skb(nskb);
31433965Sjdp}
31533965SjdpEXPORT_SYMBOL_GPL(nf_send_reset);
31633965Sjdp
31733965Sjdpvoid nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
318218822Sdim{
319218822Sdim	struct iphdr *iph = ip_hdr(skb_in);
320218822Sdim	int dataoff = ip_hdrlen(skb_in);
321218822Sdim	u8 proto = iph->protocol;
322218822Sdim
323218822Sdim	if (iph->frag_off & htons(IP_OFFSET))
324218822Sdim		return;
325218822Sdim
326218822Sdim	if ((hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) &&
327218822Sdim	    nf_reject_fill_skb_dst(skb_in) < 0)
328218822Sdim		return;
329218822Sdim
330218822Sdim	if (skb_csum_unnecessary(skb_in) ||
331218822Sdim	    !nf_reject_verify_csum(skb_in, dataoff, proto)) {
33238889Sjdp		icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
33338889Sjdp		return;
33485815Sobrien	}
33538889Sjdp
33633965Sjdp	if (nf_ip_checksum(skb_in, hook, dataoff, proto) == 0)
33733965Sjdp		icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
33833965Sjdp}
33933965SjdpEXPORT_SYMBOL_GPL(nf_send_unreach);
34033965Sjdp
34133965SjdpMODULE_LICENSE("GPL");
34233965SjdpMODULE_DESCRIPTION("IPv4 packet rejection core");
34333965Sjdp