用于网络包检查的简单内核模块¶
@2012-03-13 新版功能: 创建
非常简单的网络包检查的内核模块,基于此可以做更多有意义的事情。基于内核 3.2 测试通过。
最新代码请参考 这里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /**
* @file
* @author Z. Liu <liuzx@knownsec.com>
*
* @brief kernel module for packet inspection
*/
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Z. Liu <liuzx@knownsec.com>");
MODULE_DESCRIPTION("demo of packet inspection");
static unsigned int pkt_chk_out(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct tcphdr *th;
struct udphdr *uh;
uint16_t sport = 0, dport = 0;
struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
switch (iph->protocol) {
case IPPROTO_UDP:
uh = (struct udphdr *)skb_transport_header(skb);
sport = (unsigned int)ntohs(uh->source);
dport = (unsigned int)ntohs(uh->dest);
break;
case IPPROTO_TCP:
th = (struct tcphdr *)skb_transport_header(skb);
sport = (unsigned int)ntohs(th->source);
dport = (unsigned int)ntohs(th->dest);
break;
default:
break;
}
pr_info("OUT: %pI4:%u -> %pI4:%u, proto: %u\n", &iph->saddr, sport, &iph->daddr, dport, iph->protocol);
return NF_ACCEPT;
}
static unsigned int pkt_chk_in(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
struct tcphdr *th;
struct udphdr *uh;
uint16_t sport = 0, dport = 0;
struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
const char *indev;
indev = in ? in->name : nulldevname;
// @note when a packet goes in from wire, it travels from physical layer,
// data link layer, network layer upwards, therefore it might not go
// through the functions for skb_transport_header to work as expected.
// so we need a hack: skip the ip header.
switch (iph->protocol) {
case IPPROTO_UDP:
uh = (struct udphdr *)(skb_transport_header(skb) + (iph->ihl << 2));
sport = (unsigned int)ntohs(uh->source);
dport = (unsigned int)ntohs(uh->dest);
break;
case IPPROTO_TCP:
th = (struct tcphdr *)(skb_transport_header(skb) + (iph->ihl << 2));
sport = (unsigned int)ntohs(th->source);
dport = (unsigned int)ntohs(th->dest);
break;
default:
break;
}
pr_info("IN: %pI4:%u -> %pI4:%u, proto: %u\n", &iph->saddr, sport, &iph->daddr, dport, iph->protocol);
return NF_ACCEPT;
}
static struct nf_hook_ops packet_ops[] __read_mostly = {
{
.hook = pkt_chk_in,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = pkt_chk_out,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_FIRST,
},
};
static int __init pkt_chk_init(void)
{
int ret;
pr_info("initialize of packet inspection module\n");
ret = nf_register_hooks(packet_ops, ARRAY_SIZE(packet_ops));
if (ret < 0) {
return ret;
}
return 0;
}
static void __exit pkt_chk_exit(void)
{
nf_unregister_hooks(packet_ops, ARRAY_SIZE(packet_ops));
pr_info("packet inspection module unloaded.\n");
}
module_init(pkt_chk_init);
module_exit(pkt_chk_exit);
|
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
.PHONY: modules clean
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
@rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
@rm -rf modules.order Module.symvers
else
obj-m := pkt_chk.o
endif