netfilter-like kernel module to get source and destination address
This article is a little outdated now. Text that you don't understand is only applicable to kernel versions below 3.11.
For new kernels (>= 3.11)
If you are sure that your code will only be used with kernels >= 3.11, you can use next code for both input and output packets:
udp_header = (struct udphdr *)skb_transport_header(skb);
Or more elegant:
udp_header = udp_hdr(skb);
It's because transport header is already set up for you in ip_rcv():
skb->transport_header = skb->network_header + iph->ihl*4;
This change was brought by this commit.
For old kernels (< 3.11)
Outgoing packets (NF_INET_POST_ROUTING
)
In this case .transport_header
field set up correctly in sk_buffer
, so it points to actual transport layer header (UDP/TCP). So you can use code like this:
udp_header = (struct udphdr *)skb_transport_header(skb);
or better looking (but actually the same):
udp_header = udp_hdr(skb);
Incoming packets (NF_INET_PRE_ROUTING
)
This is the tricky part.
In this case the .transport_header
field is not set to the actual transport layer header (UDP or TCP) in sk_buffer
structure (that you get in your netfilter hook function). Instead, .transport_header
points to IP header (which is network layer header).
So you need to calculate address of transport header by your own. To do so you need to skip IP header (i.e. add IP header length to your .transport_header
address). That's why you can see next code in the article:
udp_header = (struct udphdr *)(skb_transport_header(skb) + 20);
So 20
here is just the length of IP header.
It can be done more elegant in this way:
struct iphdr *iph;
struct udphdr *udph;
iph = ip_hdr(skb);
/* If transport header is not set for this kernel version */
if (skb_transport_header(skb) == (unsigned char *)iph)
udph = (unsigned char *)iph + (iph->ihl * 4); /* skip IP header */
else
udph = udp_hdr(skb);
In this code we use an actual IP header size (which is iph->ihl * 4
, in bytes) instead of magic number 20
.
Another magic number in the article is 17
in next code:
if (ip_header->protocol == 17) {
In this code you should use IPPROTO_UDP
instead of 17
:
#include <linux/udp.h>
if (ip_header->protocol == IPPROTO_UDP) {
Netfilter input/output packets explanation
If you need some reference about difference between incoming and outgoing packets in netfilter, see the picture below.
Details:
[1]: Some useful code from GitHub
[2]: "Linux Kernel Networking: Implementation and Theory" by Rami Rosen
[3]: This answer may be also useful
How to write a linux kernel module to modify source MAC address of a packet?
As its name suggests, NF_INET_POST_ROUTING
is an INET
layer hook. I think that you need NF_BR_POST_ROUTING
which lives in netfilter_bridge.h
(source):
/* Bridge Hooks */
/* After promisc drops, checksum checks. */
#define NF_BR_PRE_ROUTING 0
/* If the packet is destined for this box. */
#define NF_BR_LOCAL_IN 1
/* If the packet is destined for another interface. */
#define NF_BR_FORWARD 2
/* Packets coming from a local process. */
#define NF_BR_LOCAL_OUT 3
/* Packets about to hit the wire. */
#define NF_BR_POST_ROUTING 4
How to print correctly a IP using NETFILTER in C
Use %pI4
for the format specifier.
e.g. printk(KERN_DEBUG "IPs: %pI4 \t to \t %pI4 \n", &src_ip, &dest_ip);
This is documented in Documentation/printk-formats.txt.
Netfilter kernel module migrating to 4.1.23 - cannot retrieve ip header
Try extract this way:
struct iphdr *ip_hdr = (struct iphdr *)skb_network_header(skb);
and access this way:
printk("IP addres = %u DEST = %u\n", ip_hdr->saddr, ip_hdr->daddr);
Related Topics
History Command Works in a Terminal, But Doesn't When Written as a Bash Script
Sed: Insert a Line in a Certain Position
Tiny "Manually" Created Elf Giving Segmentation Fault
Cuda Compiler Not Working with Gcc 4.5 +
Automatic Login on Angstrom Linux
How to Put the Current Running Linux Process in Background
How to Use Linux 'Perf' Tool to Generate "Off-Cpu" Profile
Isolate Kernel Module to a Specific Core Using Cpuset
Why Does '/Proc/Meminfo' Show 32Gb When Aws Instance Has Only 16Gb
Squid: How to Disable Authentication
Why Didn't I Get Segmentation Fault When Storing Past the End of the Bss
What Is Difference Between Arm64 and Armhf