1. Define a set of hook functions for each network protocol (IPv4, IPv6, etc.) (IPv4 defines 5 hook functions). These hook functions are called at several key points where the datagram flows through the protocol stack. Among these points, the protocol stack will call the netfilter framework with the datagram and hook function labels as parameters.
2. Any module of the kernel can register one or more hooks of each protocol to implement hooking, so that when a data packet is passed to the netfilter framework, the kernel can detect whether any modules have registered the protocol and hook function. If registered, the callback function used when registering the module is called, so that the modules have the opportunity to check (and possibly modify) the packet, discard the packet, and instruct netfilter to pass the packet into the queue in the user space.
3. Those queued packets are processed asynchronously by passing to user space. A user process can check for packets, modify packets, and even reinject the packet into the kernel through the same hook function leaving the kernel.
4. Any IP packets that are to be discarded at the IP layer must be checked before they are truly discarded. For example, allow modules to check for ip-spoofed packages (distant by routes).
The locations of the five HOOK points in the layer are as follows:
1. NF_IP_PRE_ROUTING: The data packet that has just entered the network layer passes through this point (the version number, checksum, etc. have just been tested), and the source address is converted at this point; IP_rcv in ip_input.c is called.
2. NF_IP_LOCAL_IN: After routing search, the checkpoint sent to the machine passes through this checkpoint, and the INPUT packet filtering is performed at this point; it is called in ip_local_deliver
3. NF_IP_FORWARD: The packet to be forwarded passes through this detection point, and FORWORD packet filtering is performed at this point;
4. NF_IP_POST_ROUTING: All packets that are about to be exported through the network device will pass this detection point, and the built-in destination address conversion function (including address disguise) will be performed at this point;
5. NF_IP_LOCAL_OUT: The packets sent by the native process pass through this detection point, and the OUTPUT packet filtering is performed at this point.
These points are already defined in the kernel, and the kernel module can register the processing at these HOOK points, and can be specified using the nf_register_hook function. When the datagram passes through these hook functions, the module can modify these datagrams and return the following values to the netfilter:
NF_ACCEPT Continue to transmit datagrams normally
NF_DROP discards the datagram and no longer transmits it
The NF_STOLEN module takes over the datagram and does not continue to transmit the datagram.
NF_QUEUE queues the datagram (usually used to process the datagram to user space)
NF_REPEAT calls the hook function again
A datagram selection system called iptables based on the Netfilter framework is applied in the Linux 2.4 kernel. In fact, it is the successor to ipchains, but it has stronger scalability. The kernel module can register a new rule table and require the datagram to flow through the specified rule table. This datagram selection is used to implement datagram filtering (filter table), network address translation (Nat table) and datagram processing (mangle table). The three datagram processing functions provided by the Linux 2.4 kernel are all based on netfilter's hook function and IP table. They are independent modules and are independent of each other. They are all perfectly integrated into the framework provided by Netfileter.
Packet filtering
The filter table will not modify the datagram, but will only filter the datagram. One aspect of iptables over ipchains is that it is smaller and faster. It is connected to the netfilter framework through the hook functions NF_IP_LOCAL_IN, NF_IP_FORWARD and NF_IP_LOCAL_OUT. Therefore, there is only one place to filter any datagram. This is a huge improvement over ipchains, because a forwarded datagram in ipchains will traverse three chains.
NAT
The NAT table listens to three Netfilter hook functions: NF_IP_PRE_ROUTING, NF_IP_POST_ROUTING and NF_IP_LOCAL_OUT. NF_IP_PRE_ROUTING implements address translation of the source address of the datagram that needs to be forwarded, while NF_IP_POST_ROUTING converts address translation of the destination address of the data packet that needs to be forwarded. The conversion of the destination address of the local datagram is implemented by NF_IP_LOCAL_OUT. NAT tables are different from filter tables because only the first datagram of the newly connected will traverse the table, and the subsequent datagrams will perform the same conversion process based on the results of the first datagram. NAT tables are used in source NAT, destination NAT, camouflage (which is a special case of source NAT) and transparent proxy (which is a special case of destination NAT).
Datagram processing (Packet mangling)
The mangle table is registered in the NF_IP_PRE_ROUTING and NF_IP_LOCAL_OUT hooks. Using the mangle table, you can modify the datagram or attach some out-of-band data to the datagram. The current mangle table supports modifying the TOS bit and setting the nfmard field of skb.
Source code analysis
If we want to add our own code, we need to use the nf_register_hook function, and its function prototype is:
int nf_register_hook(struct nf_hook_ops *reg)
struct nf_hook_ops
{
struct list_head list;
/* User fills in from here down. */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority. */
int priority;
};
Our job is to generate an instance of the struct nf_hook_ops structure and HOOK it with nf_register_hook. Among them, we must initialize the list item to {NULL, NULL}; since generally working in the IP layer, pf is always PF_INET; hooknum is the HOOK point we choose; a HOOK point may hang multiple processing functions, and whoever comes first depends on the priority, that is, the priority is specified. In netfilter_ipv4.h, an enumeration type specifies the priority of the built-in processing function:
enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_LAST = INT_MAX,
};
Hook is the provided processing function, which is our main work, and its prototype is:
unsigned int nf_hookfn(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
Its five parameters will be passed in by the NFHOOK macro.
nf_register_hook finds the corresponding location in nf_hooks according to the protocol cluster type and priority registered in reg and inserts it into this table. struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS] is already initialized as an empty table when netfilter is initialized (netfilter_init/, which is called on sock_init) .
For example, when iptable is initialized (init/iptable_filter.c), it calls nf_register_hook to register its hook function.
static struct nf_hook_ops ipt_ops[]
= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_FILTER },
{ { NULL, NULL }, ipt_hook, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER },
{ { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
NF_IP_PRI_FILTER }
};
mangle registers its own hook function in init/iptable_mangle.c.
static struct nf_hook_ops ipt_ops[]
= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
{ { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
NF_IP_PRI_MANGLE }
};
NAT registers its own hook function in init/ip_nat_standalone.c
/* Before packet filtering, change the destination address*/
static struct nf_hook_ops ip_nat_in_ops