net/ipv4/netfilter/nf_reject_ipv4.c

Source file repositories/reference/linux-study-clean/net/ipv4/netfilter/nf_reject_ipv4.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/netfilter/nf_reject_ipv4.c
Extension
.c
Size
9167 bytes
Lines
371
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/* (C) 1999-2001 Paul `Rusty' Russell
 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
 */

#include <linux/module.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/route.h>
#include <net/dst.h>
#include <net/netfilter/ipv4/nf_reject.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_bridge.h>

static struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
					 const struct sk_buff *oldskb,
					 __u8 protocol, int ttl);
static void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
				    const struct tcphdr *oth);
static const struct tcphdr *
nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
			struct tcphdr *_oth, int hook);

static int nf_reject_iphdr_validate(struct sk_buff *skb)
{
	struct iphdr *iph;
	u32 len;

	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
		return 0;

	iph = ip_hdr(skb);
	if (iph->ihl < 5 || iph->version != 4)
		return 0;

	len = ntohs(iph->tot_len);
	if (skb->len < len)
		return 0;
	else if (len < (iph->ihl*4))
		return 0;

	if (!pskb_may_pull(skb, iph->ihl*4))
		return 0;

	return 1;
}

struct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net,
					   struct sk_buff *oldskb,
					   const struct net_device *dev,
					   int hook)
{
	const struct tcphdr *oth;
	struct sk_buff *nskb;
	struct iphdr *niph;
	struct tcphdr _oth;

	if (!nf_reject_iphdr_validate(oldskb))
		return NULL;

	oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
	if (!oth)
		return NULL;

	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
			 LL_MAX_HEADER, GFP_ATOMIC);
	if (!nskb)
		return NULL;

	nskb->dev = (struct net_device *)dev;

	skb_reserve(nskb, LL_MAX_HEADER);
	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
				   READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
	nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
	niph->tot_len = htons(nskb->len);
	ip_send_check(niph);

	return nskb;
}
EXPORT_SYMBOL_GPL(nf_reject_skb_v4_tcp_reset);

static bool nf_skb_is_icmp_unreach(const struct sk_buff *skb)
{
	const struct iphdr *iph = ip_hdr(skb);
	u8 *tp, _type;
	int thoff;

	if (iph->protocol != IPPROTO_ICMP)
		return false;

Annotation

Implementation Notes