Seed Lab 实验 Firewall
Seed Lab 实验 Firewall
Task 1 使用LKM和Netfilter分别实现一个简单的防火墙
Task 1.A: Implement a Simple Kernel Module
(1)编译内核文件Makefile
在make的时候遇到一些问题,如果直接使用SeedLab给的hello.c进行make,会出现如下报错

这是由于内核模块的代码缺少 MODULE_LICENSE() 宏。MODULE_LICENSE() 是一个必须包含的宏,用于指示该模块的许可证类型。在大多数情况下,内核模块必须指定许可证类型,以便内核能够正确地处理和加载模块。如果没有提供许可证类型,内核会认为模块是“非自由”的,这会导致一些限制(例如,某些内核符号将无法访问)
解决方法:
在源代码中添加MODULE_LICENSE() 宏,在头文件声明后加入以下代码即可:
MODULE_LICENSE("GPL"); // 可以根据你的需要选择适当的许可证类型
然后就可以正常make了。

(2)生成的内核模块在hello.ko中,可以进行查看删除模块
lsmod

(3)把hello.ko插入到内核中,再开启一个窗口进行监控内核。
sudo insmod hello.ko
demsg -k -w

(4)从内核中删除hello。
sudo rmmod hello
demsg -k -w

Task 1.B: Implement a Simple Firewall Using Netfilter
(1) 先make

(2) 测试网络,可以连上8.8.8.8.
dig @8.8.8.8 www.example.com

(3) 运行实验中给定的内核程序,并插入到内核中
sudo insmod seedFilter.ko
lsmod | grep seedFilter

dmesg -k -w

(4) 查看防火墙是否可以使用
dig @8.8.8.8 www.example.com

可以使用了。
(5) 增加钩子的数量和位置
#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/if_ether.h>
#include <linux/inet.h>
static struct nf_hook_ops hook1, hook2,hook3,hook4,hook5;
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 = printInfo;
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 = printInfo;
hook3.hooknum = NF_INET_FORWARD;
hook3.pf = PF_INET;
hook3.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook3);
hook4.hook = printInfo;
hook4.hooknum = NF_INET_LOCAL_IN;
hook4.pf = PF_INET;
hook4.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook4);
hook5.hook = printInfo;
hook5.hooknum = NF_INET_PRE_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 "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");

(6) 禁止ping和telnet
#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 preventPing(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph; //取出ip头
struct tcphdr *tcph; //取出tcp头
struct icmphdr *icmph;
iph = ip_hdr(skb);
tcph = tcp_hdr(skb);
icmph = icmp_hdr(skb);
unsigned char* saddr = (unsigned char*)&iph->saddr; //源IP地址
if (iph->protocol == IPPROTO_ICMP && icmph->type==ICMP_ECHO &&
(int)saddr[0] == 10 && saddr[1] == 0 && saddr[2] == 2 && saddr[3] == 6)
{
printk(KERN_INFO "丢弃ping包\n");
return NF_DROP;
}
return NF_ACCEPT;
}
unsigned int preventTelnet(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph; //取出ip头
struct tcphdr *tcph; //取出tcp头
iph = ip_hdr(skb);
tcph = tcp_hdr(skb);
unsigned char* saddr = (unsigned char*)&iph->saddr; //源IP地址
if (iph->protocol == IPPROTO_TCP && tcph->dest == htons(23) &&
(int)saddr[0] == 10 && saddr[1] == 0 && saddr[2] == 2 && saddr[3] == 6)
{
printk(KERN_INFO "丢弃telnet包\n");
return NF_DROP;
}
return NF_ACCEPT;
}
int registerFilter(void) {
printk(KERN_INFO "Registering filters.\n");
hook1.hook = preventPing;
hook1.hooknum = NF_INET_PRE_ROUTING;
hook1.pf = PF_INET;
hook1.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook1);
hook2.hook = preventTelnet;
hook2.hooknum = NF_INET_PRE_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");
然后
make
sudo insmod seedFilter.ko
lsmod | grep seedFilter

ping不通,telnet不通
卸载内核模块之后可以ping和telnet
Task 2 使用Linux自带的iptables建立防火墙
Task 2.A: Protecting the Router
启动docker

可以直接使用样例代码
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -P OUTPUT DROP
iptables -P INPUT DROP
# 清除我们定义的规则
iptables -F
iptables -P FORWARD ACCEPT
允许icmp数据包的发送和接受,其他的输入输出数据包全部丢弃
进入路由器配置上述代码
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -P OUTPUT DROP
iptables -P INPUT DROP

进入hostA
ping 10.9.0.11
可以ping
telnet 10.9.0.11
不可以telnet

Task 2.B: Protecting the Internal Network
这个任务的要求是;外网机器不能ping内网;外网机器能ping路由器;内网机器能ping外网机器;内网与外网之间的其他数据包需要被丢弃
外网的icmp请求丢弃;内网的icmp请求放行;外网的icmp回复放行;其他数据包都丢弃
iptables -A FORWARD -i eth0 -p icmp --icmp-type echo-request -j DROP
iptables -A FORWARD -i eth1 -p icmp --icmp-type echo-request -j ACCEPT
iptables -A FORWARD -i eth0 -p icmp --icmp-type echo-reply -j ACCEPT
iptables -P FORWARD DROP
# 清除我们定义的规则
iptables -F
iptables -P FORWARD ACCEPT

进host1 内部主机
可以ping外部主机

进hostA
外部主机ping不通内部主机,但是ping的通路由器


内网与外网之间的其他数据包需要被丢弃

Task 2.C: Protecting Internal Servers
任务要求:外网只能远程登陆192.168.60.5,不能登陆其他内网机子;外网机子不能连接内网服务;内网机子可以使用其他内网机子的服务;内网机子无法连接外网服务
外网可以远程登陆192.168.60.5(第一行是远程登陆请求以及命令传输可以,第二行是192.168.60.5数据返回可以);其他数据包被丢弃
iptables -A FORWARD -i eth0 -p tcp -d 192.168.60.5 --dport 23 -j ACCEPT
iptables -A FORWARD -i eth1 -p tcp -s 192.168.60.5 --sport 23 -j ACCEPT
iptables -P FORWARD DROP
# 清除我们定义的规则
iptables -F
iptables -P FORWARD ACCEPT

外部机子可以连接上192.168.60.5,但是连接不上其他内部机子


内部机子可以连接其他内部机子,但是无法连接外部机子


Task 3 记录链接及建立状态防火墙
Task 3.A: Experiment with the Connection Tracking
hostA上pinghost1,host1连接跟踪信息
conntrack -L
连接前没有跟踪信息,连接时有,连接后20秒后消失

UDP:
hostA:
nc -u 192.168.60.5 9090
host1:
nc -lu 9090
两台机子上输入一些东西
在hostA上追踪
conntrack -L

一分钟左右后消失
TCP:
HOSTA:
nc 192.168.60.5 9090
HOST1:
nc -l 9090

TCP的追踪信息在建立起连接之后就已经存在,发送消息之后追踪信息不变,发送消息之后一段时间追踪信息依旧存在,并且状态是ESTABLISHED,于是关闭TCP连接,发现追踪信息状态转变为TIME_WAIT并且持续两到三分钟之后消失。
Task 3.B: Setting Up a Stateful Firewall
任务要求:外网只能远程登陆192.168.60.5,不能登陆其他内网机子;外网机子不能连接内网服务;内网机子可以使用其他内网机子的服务;内网机子可以连接外网服务
iptables -A FORWARD -i eth0 -p tcp -d 192.168.60.5 --dport 23 --syn -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i eth1 -p tcp --syn -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -p tcp -j DROP
iptables -P FORWARD ACCEPT
iptables -F
iptables -P FORWARD ACCEPT
和2.c除了最后一点都一样
Task 4 限制网络数据传输
样例代码
iptables -A FORWARD -s 10.9.0.5 -m limit \
--limit 10/minute --limit-burst 5 -j ACCEPT
iptables -A FORWARD -s 10.9.0.5 -j DROP
一开始较快,后面放缓

这是因为有了第二条命令,超过限制的数据包直接丢弃了。
Task 5 负载平衡
均匀分配:
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode nth --every 3 --packet 0 -j DNAT --to-destination 192.168.60.5:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode nth --every 2 --packet 0 -j DNAT --to-destination 192.168.60.6:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode nth --every 1 --packet 0 -j DNAT --to-destination 192.168.60.7:8080
host123上监听
nc -luk 8080
hostA上nc
echo hello | nc -u 10.9.0.11 8080

host1,2,3:



还有一种按照概率分配的
iptables -t nat -A PREROUTING -p udp --dport 8080 \
-m statistic --mode random --probability 0.1 \
-j DNAT --to-destination 192.168.60.5:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 \
-m statistic --mode random --probability 0.3 \
-j DNAT --to-destination 192.168.60.6:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 \
-m statistic --mode random --probability 0.6 \
-j DNAT --to-destination 192.168.60.7:8080
结果大致同上,就是按照概率分配。

浙公网安备 33010602011771号