0%

Firewall Exploration Lab

一.实验目标

本实验的学习目标有两个:了解防火墙如何工作,并建立一个简单的防火墙对于一个网络。学生们将首先实现一个简单的无状态包过滤防火墙,它检查数据包,并根据防火墙规则决定是否丢弃或转发数据包。通过这个实现任务,让学生了解防火墙的基本工作原理。

实际上,Linux已经有一个内置的防火墙,也是基于netfilter的。这个防火墙叫做iptables。学生将得到一个简单的网络拓扑,并被要求使用iptables进行设置防火墙规则保护网络。学生们还将接触到其他一些有趣的应用iptables。本实验涵盖以下主题:

•防火墙

•Netfilter

•可加载的内核模块

•使用iptables设置防火墙规则

•iptables的各种应用

二.实验原理

2.1 防火墙

在计算机领域中,防火墙是一种网络安全系统,它根据预定的安全规则监视和控制进出的网络流量。防火墙通常在可信网络和不可信网络(如Internet)之间建立一个屏障。

2.2 netfilter

Netfilter是Linux内核提供的一个框架,允许以定制处理程序的形式实现各种与网络相关的操作。Netfilter提供了包过滤、网络地址转换和端口转换的各种功能和操作,提供了在网络中定向数据包和禁止数据包到达网络中的敏感位置所需的功能。

Netfilter表示Linux内核中的一组钩子,允许特定的内核模块向内核的网络堆栈注册回调函数。这些函数通常以过滤和修改规则的形式应用于流量,在网络堆栈中对每个遍历各自钩子的数据包调用。

2.3 iptables

iptables是一个用户空间实用程序,允许系统管理员配置Linux内核防火墙的IP包过滤规则,实现为不同的Netfilter模块。过滤器被组织在不同的表中,其中包含如何处理网络流量数据包的规则链。不同的协议目前使用不同的内核模块和程序;iptables适用于IPv4, ip6tables适用于IPv6, arptables适用于ARP, ebtables适用于以太网帧。

2.4 拓扑搭建

在这个实验室里,我们需要使用多台机器。它们的设置如图1所示。我们将使用容器设置这个实验环境:

三.实验器材

1.Ubuntu20.04。

2.Docker.

四.实验步骤及运行结果

4.1 Task 1: Implementing a Simple Firewall

在这个任务中,我们将实现一个简单的包过滤类型的防火墙,它检查每个传入的和并执行管理员设置的防火墙策略。

4.1.1 Task 1.A: Implement a Simple Kernel Module

LKM允许我们在运行时向内核添加一个新模块。这个新模块使我们能够扩展内核的功能,而不需要重新构建内核,甚至不需要重新启动计算机。防火墙的包过滤部分可以实现为LKM。在这个任务中,我们将熟悉LKM。

首先使用make命令对 kernel_module 中的文件进行编译如下:

在该目录下,使用lsmod命令即可查看当前所生成的module 如下:

使用dmesg -w命令进行监听:

使用 insmod 命令,插入 hello.ko 如下:

使用rmmod命令移除 hello这个module,如下:

在使用dmesg监听的窗口可以观察内核中的输出结果如下:

4.1.2 Task 1.B: Implement a Simple Firewall Using Netfilter

本任务中需要使用LKM和Netfilter实现包过滤模块。这个模块将从数据结构中获取防火墙策略,并使用这些策略来决定数据包是否应该被挡。

实现两个更多的钩子,以达到以下目的:(1)防止其他计算机ping(2)防止其他计算机telnet到虚拟机。请实施两种不同的挂钩函数,但是将它们注册到同一个netfilter钩子。

首先利用dig去产生UDP包发送给8.8.8.8,可以发现其正常发送,如下:

编译packet_filter中的文件并且插入seedfilter.ko,如下:

在dmesg所监听的窗口中,可以观察到过滤文件被成功注册:

然后重新使用dig命令发送UDP包给8.8.8.8,观察到发送超时,服务不可达:

同时在监听窗口,可以观察到如下内容:

说明由当前主机发送8.8.8.8的UDP包均被丢弃,说明过滤规则生效。

移除当前的过滤器,把hook函数都添加到代码中后,重新编译并且添加module,如下:

重新使用dig @8.8.8.8 www.example.com命令发送UDP包,可以在dmesg的监听窗口观察到如下内容:

从中可以发现,POST_ROUTING,PRE_ROUTING在当前主机给8.8.8.8发送UDP数据包的时候被调用,而LOCAL_IN,LOCAL_OUT在8.8.8.8给当前主机发送响应UDP的时候被调用。

经过查询可以得到NF_INET_FORWARD函数的主要功能是查路由,决定数据包是输入到本地还是转发,因此可以推断得知其在发送给路由器的时候被调用。

移除当前的过滤器,在HOST-A主机中尝试ping命令和telnet命令与当前主机建立连接,发现均可以成功响应,如下:

修改代码添加过滤规则后重新编译,并且添加模块,如下图所示:

HOST-A主机中,重新向当前主机发送ping和telnet,均失败:

与此同时,在dmesg所监听的窗口中,可以观察到如下内容:

说明,当前发送给当前主机的ping响应和建立telnet连接的tcp包均被丢弃,设置的过滤规则成功生效。

4.2 Task 2: Experimenting with Stateless Firewall Rules

在前面的任务中,我们有机会使用netfilter构建一个简单的防火墙。实际上,Linux已经有内置防火墙,也是基于netfilter的。这个防火墙叫做iptables。从技术上讲,防火墙的内核部分实现被称为Xtables,而iptables是一个用户空间程序配置防火墙。然而,iptables通常用于指内核部分实现还有用户空间程序。

4.2.1 Task 2.A: Protecting the Router

在这个任务中,我们将设置规则来阻止外部机器访问路由器机器,ping除外。

根据实验所搭建的网络拓扑我们可以得知,路由器拥有两个IP地址,分别用于与其内网 192.168.60.00/24和外网10.9.0.0/24 进行通信。

在设置防火墙规则前,我们在host-a主机中,可以与路由器进行ping和telnet连接,如下图所示:

然后依次执行实验手册中所给出的四个指令:

查看iptables中过滤表中的规则:

重新在host-a主机中与路由器进行ping和telnet连接,如下:

发现ping可以成功,而telnet连接建立失败,说明所设置的防火墙过滤规则成功将外部机器所访问路由器的方式限制为了ping。原因在于所设置的规则,只允许路由器的输入为icmp echo-request类型的报文和输出为icmp echo-reply类型的报文被接收,其他报文均丢弃。

4.2.2 Task 2.B: Protecting the Internal Network

在这个任务中,我们想要实现一个防火墙来保护内部网络。更具体地说,我们需要对ICMP报文流量进行如下限制:

1. 外部主机无法ping通内部主机。

2. 外部主机可以ping通路由器。

3.内部主机可以ping外部主机。

4. 内部网络和外部网络之间的所有其他数据包都应该被阻止

实验步骤如下:

首先清空路由器中之前所设置的规则,然后重新在过滤表中设置规则如下:

解释说明,只允许eth1进行转发进来的icmp响应请求报文,只允许eth0进来的进行转发icmp响应回复报文,而响应请求报文均被丢弃,其他报文均不允许被转发。其中eth1所对应ip为内网,而eth1所对应ip为外网。

在host-a主机中,分别ping 路由器和host-1,以及与host-1建立telnet连接,可以观察到如下现象:

1主机中分别尝试ping host-a和telnet host-a,现象如下:

解释:

在外部主机中,可以成功ping路由器,但不可以与内部主机进行ping以及telnet连接,;在内部主机中,可以成功ping外部主机,但不能与外部主机建立telnet连接,符合任务中的要求。

4.2.3 Task 2.C: Protecting Internal Servers

在这个任务中,我们希望保护内部网络(192.168.60.0/24)内的TCP服务器。更多的

具体来说,我们要实现以下目标。

1. 所有内部主机都运行一个telnet服务器(监听端口23)。外部主机只能访问telnet服务器位于192.168.60.5,而不是其他内部主机

2. 外部主机无法访问其他内部服务器。

3.内部主机可以访问所有内部服务器。

4. 内部主机无法访问外部服务器。

实验步骤:

首先进行检查如下:

在host-a中分别与内网中的三台主机建立telnet连接,发现均可以成功。

在host-1中与外部主机建立telnet连接,也可以成功。

修改过滤表中的规则如下:

让所有从外部进来并且访问目的主机为host-1的 23端口的tcp报文被接收,让所有来自于内网host-1并且源端口为23的tcp报文被接受,其余报文均被丢弃

修改规则后,重新在各种主机中尝试建立telnet连接如下:

在host-1中,可以成功与内网中的其他主机以及外网主机建立连接:

在host-a中,只可以与内网中host-1建立连接:

在host2中,可以与内网中的其他主机建立连接,但不可以与外网主机建立连接:

尝试在主机a中采用其他的连接方式:

发现在主机1中不会收到信息。

因此证明符合任务中所给出的规则。

4.3 Task 3: Connection Tracking and Stateful Firewall

4.3.1 Task 3.A: Experiment with the Connection Tracking

为了支持有状态防火墙,我们需要能够跟踪连接。这是通过内核内部的conntrack机制实现的。在本次任务中,我们将进行与该模块相关的实验,并熟悉连接跟踪制。在我们的实验中,我们将检查连接跟踪路由器容器的信息。可以使用以下命令来成:

本任务的目标是通过一系列实验来帮助学生理解这种跟踪机制中的连接概念,特别是对于ICMP和UDP协议,因为与TCP不同,它们没有连接。请进行以下实验。对于每个实验,请描述你的观察结果,并附上解释。

ICMP实验,

在主机A中向主机1发送icmp报文如下:

然后在路由器中可以查看到信息如下:

可以观察到其中所保存的icmp信息会在一段时间后消失,其具体保留时间内,可以在路由器中的如下文件中得知:

可以发现其保留时间为30s

UDP实验:

在主机A和主机1中利用nc建立一个udp链接如下:

然后在路由器中可以观察到如下记录,及其保留时间:

可以得知udp报文在路由器中的保留时间为30s

TCP实验:

在主机A和主机1中建立TCP连接如下:

在路由器中可以观察到所保存的TCP报文信息如下:

保留时间如下:

建立连接时会保留432000s,断开连接后,路由器中信息如下:

可以观察到,断开连接后路由器中保留的信息会等待120s

4.3.2 Task 3.B: Setting Up a Stateful Firewall

请在Task 2.C中重写防火墙规则,但这一次,我们将添加一条允许内部主机访问任何外部服务器(这在任务2.C中不允许)。

在路由器的容器中修改防火墙规则如下:

然后再局域网中对所修改的规则及其作用进行验证如下:

外部主机只能连接主机1:

内网主机可以连接内网主机以及外网主机:

如果采用nc来在主机A和主机1中建立连接,可以观察到如下现象:

如果是TCP报文会被丢弃,但UDP报文则可以发送与接收

另一种实现的过滤规则如下:

通过测试同样可以,得到相同的效果

4.4 Task 4: Limiting Network Traffic

除了阻断数据包外,我们还可以限制可以通过防火墙的数据包数量。这可以使用iptables的limit模块来完成。在这个任务中,我们将使用这个模块来限制如何操作。请在路由器上运行以下命令,然后从10.9.0.5 ping 192.168.60.5。描述你的观察。请在有和没有第二条规则的情况下进行实验,然后解释第二条规则是否需要,以及为什么

首先根据实验手册设置过滤规则如下:

从主机A ping 主机1:

可以发现icmp报文的发送被限制了,一部分报文被丢弃

如果去掉第二条规则,就会得到如下结果:

Icmp报文的转发并不会被限制

原因在于第一条规则设置了来自于主机A流量的限制是允许接收这么多,如果不设置第二条规则,来自于主机A的流量仍然会全部接收并转发,因此要利用第二条规则使其他来自于主机A的流量全部被丢弃,才能够真正的限制流量的转发。

4.5 Task 5: Load Balancing

首先在三台主机中均打开如下服务:

Using the nth mode (round-robin).

在路由器中设置对于目的主机为主机1的报文限制如下:

同理设置对于对于主机2和主机3的报文限制分别为every2 packet0 和every1 packe0 ,即可对收到的报文均分,得到如下结果:

当从主机A向路由器不断发送报文时,在三台主机中接收到的效果如下:

在主机1中可以接收到每3个报文中的第一个报文:

在主机2中可以接收到每三个报文中的第二个报文:

在主机3中可以接收到每三个报文中的第三个报文

Using the random mode.

在路由其中设置如下规则:

其原理是通过得到的概率来进行报文的均分,分别讲三台主机得到报文的概率设置为1,0.5,和1/3即可以让每三个报文中的一个报文发给概率为1的主机,而其他两个报文根据概率分配给剩下两台主机,效果如下:

首先在主机A中向路由器发送六个UDP报文

如下图所示:

后在监听的三台主机中观察如下现象:

可以观察到报文被均分发送到三个主机。

五. 附件

5.1 Task 1.A—Hello.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <linux/module.h>
#include <linux/kernel.h>
int initialization(void)
{
printk(KERN_INFO "Hello World!\n");
return 0;
}
void cleanup(void)
{
printk(KERN_INFO "Bye-bye World!.\n");
}
module_init(initialization);
module_exit(cleanup);
MODULE_LICENSE("GPL");

5.2 Task1.B—SeedBlock.c

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
static struct nf_hook_ops hook1,hook2,hook3,hook4;
// block ping to 10.9.0.1
unsigned int blockICMP(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct icmphdr *icmph;
// u16 port = 53; // icmp no port
char ip[16] = "10.9.0.1";
u32 ip_addr;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
// Convert the IPv4 address from dotted decimal to 32-bit binary
in4_pton(ip, -1, (u8 *)&ip_addr, '\0', NULL);
if (iph->protocol == IPPROTO_ICMP) {
icmph = icmp_hdr(skb);
if (iph->daddr == ip_addr && icmph->type == ICMP_ECHO ) {//&&
ntohs(icmph->dest) == port){
printk(KERN_WARNING "*** Dropping %pI4 (ICMP/ping)",
&(iph->daddr));
return NF_DROP;
}
}
return NF_ACCEPT;
}

// block telnet to 10.9.0.1
unsigned int blockTelnet(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct tcphdr *tcph;
u16 port = 23; // telnet
char ip[16] = "10.9.0.1";
u32 ip_addr;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
// Convert the IPv4 address from dotted decimal to 32-bit binary
in4_pton(ip, -1, (u8 *)&ip_addr, '\0', NULL);
if (iph->protocol == IPPROTO_TCP) {
tcph = tcp_hdr(skb);
if (iph->daddr == ip_addr && ntohs(tcph->dest) == port){
printk(KERN_WARNING "*** Dropping %pI4 (TCP/telnet), port %d\n",
&(iph->daddr), port);
return NF_DROP;
}
}
return NF_ACCEPT;
}
// block udp to 8.8.8.8
unsigned int blockUDP(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct udphdr *udph;
u16 port = 53; // DNS
char ip[16] = "8.8.8.8";
u32 ip_addr;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
// Convert the IPv4 address from dotted decimal to 32-bit binary
in4_pton(ip, -1, (u8 *)&ip_addr, '\0', NULL);
if (iph->protocol == IPPROTO_UDP) {
udph = udp_hdr(skb);
if (iph->daddr == ip_addr && ntohs(udph->dest) == port){
printk(KERN_WARNING "*** Dropping %pI4 (UDP), port %d\n",
&(iph->daddr), port);
return NF_DROP;
}
}
return NF_ACCEPT;
}
unsigned int printInfo(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
char *hook;
char *protocol;
switch (state->hook){
case NF_INET_LOCAL_IN: hook = "LOCAL_IN"; break;
case NF_INET_LOCAL_OUT: hook = "LOCAL_OUT"; break;
case NF_INET_PRE_ROUTING: hook = "PRE_ROUTING"; break;
case NF_INET_POST_ROUTING: hook = "POST_ROUTING"; break;
case NF_INET_FORWARD: hook = "FORWARD"; break;
default: hook = "IMPOSSIBLE"; break;
}
printk(KERN_INFO "*** %s\n", hook); // Print out the hook info
iph = ip_hdr(skb);
switch (iph->protocol){
case IPPROTO_UDP: protocol = "UDP"; break;
case IPPROTO_TCP: protocol = "TCP"; break;
case IPPROTO_ICMP: protocol = "ICMP"; break;
default: protocol = "OTHER"; break;
}
// Print out the IP addresses and protocol
printk(KERN_INFO " %pI4 --> %pI4 (%s)\n",
&(iph->saddr), &(iph->daddr), protocol);
return NF_ACCEPT;
}
int registerFilter(void) {
printk(KERN_INFO "seedBlock:Registering filters.\n");
hook1.hook = printInfo;
hook1.hooknum = NF_INET_LOCAL_OUT;
hook1.pf = PF_INET;
hook1.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook1);
hook2.hook = blockUDP;
hook2.hooknum = NF_INET_POST_ROUTING;
hook2.pf = PF_INET;
hook2.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook2);

hook3.hook = blockICMP;
hook3.hooknum = NF_INET_PRE_ROUTING;
hook3.pf = PF_INET;
hook3.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook3);

hook4.hook = blockTelnet;
hook4.hooknum = NF_INET_PRE_ROUTING;
hook4.pf = PF_INET;
hook4.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook4);
return 0;
}
void removeFilter(void) {
printk(KERN_INFO "seedBlock:The filters are being removed.\n");
nf_unregister_net_hook(&init_net, &hook1);
nf_unregister_net_hook(&init_net, &hook2);
nf_unregister_net_hook(&init_net, &hook3);
nf_unregister_net_hook(&init_net, &hook4);
}
module_init(registerFilter);
module_exit(removeFilter);
MODULE_LICENSE("GPL");

5.3 Task1.B—SeedFilter.c

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
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
static struct nf_hook_ops hook1, hook2;
unsigned int blockUDP(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct udphdr *udph;
u16 port = 53; // DNS
char ip[16] = "8.8.8.8";
u32 ip_addr;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
// Convert the IPv4 address from dotted decimal to 32-bit binary
in4_pton(ip, -1, (u8 *)&ip_addr, '\0', NULL);
if (iph->protocol == IPPROTO_UDP) {
udph = udp_hdr(skb);
if (iph->daddr == ip_addr && ntohs(udph->dest) == port){
printk(KERN_WARNING "*** Dropping %pI4 (UDP), port %d\n",
&(iph->daddr), port);
return NF_DROP;
}
}
return NF_ACCEPT;
}
unsigned int printInfo(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
char *hook;
char *protocol;
switch (state->hook){
case NF_INET_LOCAL_IN: hook = "LOCAL_IN"; break;
case NF_INET_LOCAL_OUT: hook = "LOCAL_OUT"; break;
case NF_INET_PRE_ROUTING: hook = "PRE_ROUTING"; break;
case NF_INET_POST_ROUTING: hook = "POST_ROUTING"; break;
case NF_INET_FORWARD: hook = "FORWARD"; break;
default: hook = "IMPOSSIBLE"; break;
}
printk(KERN_INFO "*** %s\n", hook); // Print out the hook info
iph = ip_hdr(skb);
switch (iph->protocol){
case IPPROTO_UDP: protocol = "UDP"; break;
case IPPROTO_TCP: protocol = "TCP"; break;
case IPPROTO_ICMP: protocol = "ICMP"; break;
default: protocol = "OTHER"; break;
}
// Print out the IP addresses and protocol
printk(KERN_INFO " %pI4 --> %pI4 (%s)\n",
&(iph->saddr), &(iph->daddr), protocol);
return NF_ACCEPT;
}
int registerFilter(void) {
printk(KERN_INFO "Registering filters.\n");
hook1.hook = printInfo;
hook1.hooknum = NF_INET_LOCAL_OUT;
hook1.pf = PF_INET;
hook1.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook1);
hook2.hook = blockUDP;
hook2.hooknum = NF_INET_POST_ROUTING;
hook2.pf = PF_INET;
hook2.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook2);
return 0;
}
void removeFilter(void) {
printk(KERN_INFO "The filters are being removed.\n");
nf_unregister_net_hook(&init_net, &hook1);
nf_unregister_net_hook(&init_net, &hook2);
}
module_init(registerFilter);
module_exit(removeFilter);
MODULE_LICENSE("GPL");

5.4 Task1.B—SeedPrint.c

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
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
static struct nf_hook_ops hook1, hook2,hook3,hook4,hook5;
unsigned int blockUDP(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct udphdr *udph;
u16 port = 53; // DNS
char ip[16] = "8.8.8.8";
u32 ip_addr;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
// Convert the IPv4 address from dotted decimal to 32-bit binary
in4_pton(ip, -1, (u8 *)&ip_addr, '\0', NULL);
if (iph->protocol == IPPROTO_UDP) {
udph = udp_hdr(skb);
if (iph->daddr == ip_addr && ntohs(udph->dest) == port){
printk(KERN_WARNING "*** Dropping %pI4 (UDP), port %d\n",
&(iph->daddr), port);
return NF_DROP;
}
}
return NF_ACCEPT;
}
unsigned int printInfo(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
char *hook;
char *protocol;
switch (state->hook){
case NF_INET_LOCAL_IN: hook = "LOCAL_IN"; break;
case NF_INET_LOCAL_OUT: hook = "LOCAL_OUT"; break;
case NF_INET_PRE_ROUTING: hook = "PRE_ROUTING"; break;
case NF_INET_POST_ROUTING: hook = "POST_ROUTING"; break;
case NF_INET_FORWARD: hook = "FORWARD"; break;
default: hook = "IMPOSSIBLE"; break;
}
printk(KERN_INFO "*** %s\n", hook); // Print out the hook info
iph = ip_hdr(skb);
switch (iph->protocol){
case IPPROTO_UDP: protocol = "UDP"; break;
case IPPROTO_TCP: protocol = "TCP"; break;
case IPPROTO_ICMP: protocol = "ICMP"; break;
default: protocol = "OTHER"; break;
}
// Print out the IP addresses and protocol
printk(KERN_INFO " %pI4 --> %pI4 (%s)\n",
&(iph->saddr), &(iph->daddr), protocol);
return NF_ACCEPT;
}
int registerFilter(void) {
printk(KERN_INFO "seedPrint:Registering filters.\n");
// NF_INET_PRE_ROUTING
hook1.hook = printInfo;
hook1.hooknum = NF_INET_PRE_ROUTING;
hook1.pf = PF_INET;
hook1.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook1);

// NF_INET_LOCAL_IN
hook2.hook = printInfo;
hook2.hooknum = NF_INET_LOCAL_IN;
hook2.pf = PF_INET;
hook2.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook2);

// NF_INET_FORWARD
hook3.hook = printInfo;
hook3.hooknum = NF_INET_FORWARD;
hook3.pf = PF_INET;
hook3.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook3);
// NF_INET_LOCAL_OUT
hook4.hook = printInfo;
hook4.hooknum = NF_INET_LOCAL_OUT;
hook4.pf = PF_INET;
hook4.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook4);
// NF_INET_POST_ROUTING
hook5.hook = printInfo;
hook5.hooknum = NF_INET_POST_ROUTING;
hook5.pf = PF_INET;
hook5.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook5);
return 0;
}
void removeFilter(void) {
printk(KERN_INFO "seedPrint:The filters are being removed.\n");
nf_unregister_net_hook(&init_net, &hook1);
nf_unregister_net_hook(&init_net, &hook2);
nf_unregister_net_hook(&init_net, &hook3);
nf_unregister_net_hook(&init_net, &hook4);
nf_unregister_net_hook(&init_net, &hook5);
}
module_init(registerFilter);
module_exit(removeFilter);
MODULE_LICENSE("GPL");