Skip to content

Instantly share code, notes, and snippets.

@nkapliev
Last active March 19, 2020 12:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nkapliev/781f10187bf136d9a133e25f4d12d196 to your computer and use it in GitHub Desktop.
Save nkapliev/781f10187bf136d9a133e25f4d12d196 to your computer and use it in GitHub Desktop.
Linux kernel 4.4+ netfilter packet capturing boilerplate.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
//#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
//#define __KERNEL__
// I am using this code on my VM. Was interested in capturing only non-bridge packets
const __be32 HOST_IP_ADDR = 20687040;
const __be32 LOCAL_IP_ADDR = 171681984;
static struct nf_hook_ops nfin;
static struct nf_hook_ops nfout;
// In every netfilter guid you will find Linux kernel 2.x version of netfilter:
//typedef 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 *))
//{
// In 4.3- it was look like this:
//typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
// struct sk_buff *skb,
// const struct nf_hook_state *state);
// Since 4.4+ it was generalised:
static unsigned int hook_func_in(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct ethhdr *eth;
struct iphdr *ip_header;
eth = (struct ethhdr*)skb_mac_header(skb);
ip_header = (struct iphdr *)skb_network_header(skb);
if (HOST_IP_ADDR == ip_header->saddr)
return NF_ACCEPT;
printk("NF_IP_LOCAL_IN hook:\n");
printk("src mac %pM, dst mac %pM\n", eth->h_source, eth->h_dest);
printk("src IP addr:=%pI4\n", &ip_header->saddr);
return NF_ACCEPT;
}
static unsigned int hook_func_in(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct ethhdr *eth;
struct iphdr *ip_header;
eth = (struct ethhdr*)skb_mac_header(skb);
ip_header = (struct iphdr *)skb_network_header(skb);
if (LOCAL_IP_ADDR == ip_header->saddr)
return NF_ACCEPT;
printk("NF_IP_LOCAL_OUT hook:\n");
printk("src mac %pM, dst mac %pM\n", eth->h_source, eth->h_dest);
printk("src IP addr:=%pI4\n", &ip_header->saddr);
return NF_ACCEPT;
}
static int __init init_main(void)
{
nfin.hook = hook_func_in;
nfin.hooknum = 1; // NF_IP_LOCAL_IN // TODO
nfin.pf = PF_INET;
nfin.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfin);
nfout.hook = hook_func_out;
nfout.hooknum = 3; // NF_IP_LOCAL_OUT // TODO
nfout.pf = PF_INET;
nfout.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfout);
return 0;
}
static void __exit cleanup_main(void)
{
nf_unregister_hook(&nfin);
nf_unregister_hook(&nfout);
}
module_init(init_main);
module_exit(cleanup_main);
obj-m += ip_mac_packet_logger.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install:
insmod ip_mac_packet_logger.ko
remove:
rmmod ip_mac_packet_logger.ko
@nkapliev
Copy link
Author

$ tail -f /var/log/syslog

Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.760790] src IP addr:=192.168.0.66
Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.809431] NF_IP_LOCAL_IN hook:
Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.809456] src mac 54:67:51:55:e1:68, dst mac 08:00:27:79:87:63
Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.809464] src IP addr:=192.168.0.1
Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.809746] NF_IP_LOCAL_OUT hook:
Jul 23 09:00:50 nkapliev-vb kernel: [ 4866.809749] src mac 00:00:00:00:00:00, dst mac 00:00:00:00:00:00

@nkapliev
Copy link
Author

I still have no idea how to import netfilter_ipv4.h in a way to define NF_IP_LOCAL_IN and NF_IP_LOCAL_OUT.
It seems like I need to be in user-space mode.
But when I tried to wrap import like this:

#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
#define __KERNEL__

it says that it does not know where to find limits.h, which is used inside netfilter_ipv4.h.
I need to move forward so decided to leave it as it is.

@BugsBountyHunter
Copy link

can you help me with what I do if I need to print packets like in Wireshark application?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment