Reading Notes: Netfilter and iptables (1)

reading notes of Understanding Linux Network Internals

Posted by Henry Du on Saturday, January 13, 2024

Reading Notes: Netfilter and iptables

Netfilter is firewalling subsystem in the Linux kernel as a modular[1]. For example, some fields are included in the sk_buf data structure only if the kernel is compiled with support for Netfilter feature.

struct sk_buff is defined in linux/include/skbuff.h. There is a well defined document on the top of the file. It include the netfilter common header file

#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <linux/netfilter/nf_conntrack_common.h>
#endif

Firewalling, essentially, hooks into certain places in the network stack code that packets always pass through when the packets or the kernel meet certain conditions. For different protocols, such as IPv4, IPv6 and ARP, the Netfilter firewall subsystem can be invoked at many points in the packet’s history and can change its destiny.

The following header file is include/uapi/linux/netfilter.h

enum nf_inet_hooks {
	NF_INET_PRE_ROUTING,
	NF_INET_LOCAL_IN,
	NF_INET_FORWARD,
	NF_INET_LOCAL_OUT,
	NF_INET_POST_ROUTING,
	NF_INET_NUMHOOKS,
	NF_INET_INGRESS = NF_INET_NUMHOOKS,
};
  • NF_INET_PRE_ROUTING: this hook will be invoked in IPv4 stack ip_rcv() or IPv6 stack ipv6_rcv(). This is the first hook that every ingress package passes through.
  • NF_INET_LOCAL_IN: this hook will be invoked in IPv4 stack ip_local_deliver() or IPv6 stack ip6_input(). After routing decision, all packages which destination is local host will trigger this hook.
  • NF_INET_FORWARD: this hook will be invoked in IPv4 stack ip_forward() or IPv6 stack ip6_forward(). After routing decision, all packages which designation is NOT local host will trigger this hook.
  • NF_INET_LOCAL_OUT: this hook will be invoked in IPv4 stack __ip_local_out() or IPv6 protocol stack __ip6_local_out(). For all packages which generated in local host will pass through this hook.
  • NF_INET_POST_ROUTING: this hook will be invoked in IPv4 protocol stack ip_output() or IPv6 protocol stack ip6_finish_output2(). Both local host generated packages and forwarded packages will pass through this hook after routing decision.

The ip_rcv() example from net/ipv4/ipinput.c

/*
 * IP receive entry point
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
	   struct net_device *orig_dev)
{
	struct net *net = dev_net(dev);

	skb = ip_rcv_core(skb, net);
	if (skb == NULL)
		return NET_RX_DROP;

	return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
		       net, NULL, skb, dev, NULL,
		       ip_rcv_finish);
}

The macro NF_HOOK is defined in include/linux/netfilter.h.

static inline int
NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
	struct sk_buff *skb, struct net_device *in, struct net_device *out,
	int (*okfn)(struct net *, struct sock *, struct sk_buff *))
{
	return okfn(net, sk, skb);
}
  • pf: Protocol Family, for IPv4, it is NFPROTO_IPV4.
  • hook: enum value of hook object, e.g. NF_INET_PRE_ROUTING.
  • skb: socket buffer object.
  • in and out: network device object.
  • okfn: function pointer. It will be invoked right before the NF_HOOK returns. It is normally will be do_somthing_finish.

Reference

[1] Christian Benvenuti, Understanding Linux Network Internals, 2006 O’REILLY Media