(CN) Firewall Exploration Lab
Firewall Exploration Lab
Task 1 Implementing a Simple Firewall
Task A Implement a Simple Kernel Module
Task B Implement a Simple Firewall Using Netfilter
- load
unload:
2.
3.
#include <linux/in.h>
#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;
static struct nf_hook_ops hooks[NF_INET_NUMHOOKS];
unsigned int blockUDP(void *priv, struct sk_buff *skb,const struct nf_hook_state *state)
{
struct iphdr *iph;
struct udphdr *udph;
u16 port = 53;
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 blockPing(void *priv, struct sk_buff *skb,const struct nf_hook_state *state)
{
struct iphdr *iph;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_ICMP) {
printk(KERN_WARNING "*** Dropping ICMP from %pI4 to %pI4\n", &(iph->saddr), &(iph->daddr));
return NF_DROP;
}
return NF_ACCEPT;
}
unsigned int blockTelnet(void *priv, struct sk_buff *skb,const struct nf_hook_state *state)
{
struct iphdr *iph;
struct tcphdr *tcph;
u16 port = 23;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_TCP) {
tcph = tcp_hdr(skb);
if (ntohs(tcph->dest) == port) {
printk(KERN_WARNING "*** Dropping Telnet from %pI4:%d to %pI4:%d\n", &(iph->saddr), ntohs(tcph->source), &(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) {
int i;
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);
hook3.hook = blockPing;
hook3.hooknum = NF_INET_LOCAL_IN;
hook3.pf = PF_INET;
hook3.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook3);
hook4.hook = blockTelnet;
hook4.hooknum = NF_INET_LOCAL_IN;
hook4.pf = PF_INET;
hook4.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook4);
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
hooks[i].hook = printInfo;
hooks[i].hooknum = i;
hooks[i].pf = PF_INET;
hooks[i].priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hooks[i]);
}
return 0;
}
void removeFilter(void) {
int i;
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);
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
nf_unregister_net_hook(&init_net, &hooks[i]);
}
}
module_init(registerFilter);
module_exit(removeFilter);
MODULE_LICENSE("GPL");
Task 2 Experimenting with Stateless Firewall Rules
Task A Protecting the Router
INPUT 和 OUTPUT 的默认 policy 为 DROP,仅仅对于ICMP可行,对于ping可以,但是无法telnet到seed-router
Task B Protecting the Internal Network
要实现路由器所连的两网的相互隔离,仅允许内部主机ping 外部主机,需要添加FORWARD规则,用 -d/-s 参数指定来去的ip段
//task2 b
iptables -A FORWARD -p icmp --icmp-type echo-reply -d 192.168.60.0/24 -j ACCEPT
iptables -A FORWARD -p icmp --icmp-type echo-request -s 192.168.60.0/24 -j ACCEPT
iptables -A FORWARD -j DROP
测试是否成功:
udp报文也被drop
tcp报文也被drop
Task C Protecting Internal Servers
// task2 c
iptables -A FORWARD -p tcp -s 10.9.0.0/24 --dport 23 -d 192.168.60.5 -j ACCEPT
iptables -A FORWARD -p tcp -s 192.168.60.0/24 --dport 23 -d 192.168.60.0/24 -j ACCEPT
iptables -P FORWARD DROP
- All the internal hosts run a telnet server (listening to port 23). Outside hosts can only access the telnet server on 192.168.60.5, not the other internal hosts.
- Outside hosts cannot access other internal servers.
- Internal hosts can access all the internal servers.
- Internal hosts cannot access external servers.
Task 3 Connection Tracking and Stateful Firewall
Task A Experiment with the Connection Tracking
icmp 30s左右
udp 30s左右
TCP在连接ESTABLISHED后,状态持续时间为432000秒,断开连接进入TIME_WAIT状态,持续时间为120秒。
Task B Setting Up a Stateful Firewall
iptables -A FORWARD -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -p tcp -i eth0 --dport 23 --syn -m conntrack --ctstate NEW -d 192.168.60.5 -j ACCEPT
iptables -A FORWARD -p tcp -i eth1 --dport 23 --syn -m conntrack --ctstate NEW -j ACCEPT
iptables -P FORWARD DROP
- All the internal hosts run a telnet server (listening to port 23). Outside hosts can only access the telnetserver on 192.168.60.5, not the other internal hosts.
- Outside hosts cannot access other internal servers.
- Internal hosts can access all the internal servers.
- Internal hosts can access external servers.
- In this task, the connection tracking mechanism is allowed
我们将添加一条允许内部主机访问任何外部服务器的规则。使用conntrack模块,只放行新的TCP/SYN包和已有TCP连接的数据包,否则无法确定需要放行哪些传入内网的数据包。
Task 4 Limiting Network Traffic
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
设置了drop
查看效果,可以看到前5个数据包都可以正常接收,那是因为limit默认初始包就是5个,因此没有任何问题,从第六个数据包开始后,每隔6秒才会正常处理一个数据包,因为1分钟限制10次数据包的接收,那就表示6秒收一个,效果如下图所示。也可以理解为是一开始可以快速通过5个数据报文,后面的数据报文是每分钟通过10个。
未设置drop:
添加第二条drop规则,超出10个报文后,其余的报文全部丢弃;不添加的话,对于超出的报文没有处理.
Task 5 Load Balancing
使用statistic模块负载均衡,使用-j DNAT –to-destination ip:port指定负载均衡目标,由于是UDP所以只用改destination。
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode random --probability 0.33 -j DNAT --to-destination 192.168.60.5:8080