Task 1: Implementing a Simple Firewall
Task 1.A: Implement a Simple Kernel Module
首先使用make进行编译
可以看到hello.ko文件已经出现
使用
lsmod | grep hello
dmesg
查看Kernel module
Task 1.B: Implement a Simple Firewall Using Netfilter
1、
make
sudo insmod seedFilter.ko
dig @8.8.8.8 www.example.com
sudo rmmod seedFilter.ko
dig @8.8.8.8 www.example.com
执行上述命令
可以看到在挂载好seedFilter时向8.8.8.8发udp包是失败的,取消挂载后即可成功
2、
NF_INET_PRE_ROUTING
在包经过,进入路由前,经过NF_INET_PRE_ROUTING钩子点
NF_INET_LOCAL_OUT
从本机发出的数据包,在查询路由成功之后,经过NF_INET_LOCAL_OUT钩子点
NF_INET_FORWARD
经过了PRE_ROUTING钩子点之后,如果是路由到转发而不是本地,则经过NF_INET_FORWARD钩子点
NF_INET_POST_ROUTING
转发的数据包或者是本地输出的数据包,最后都会经过NF_INET_POST_ROUTING钩子点
NF_INET_LOCAL_IN
如果数据包发送到本地,经过NF_INET_LOCAL_IN钩子点
3、
实现VM不接受ping与telnet连接
改写样本代码。注:记得加 #include <linux/icmp.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>
#include <linux/icmp.h>
static struct nf_hook_ops hook1, hook2;
unsigned int blockTCP(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
struct tcphdr *tcph;
u16 port = 23;
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), 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;
struct icmphdr *icmph;
//u16 port = 23;
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 == 8){// Echo-request is 8
printk(KERN_WARNING "*** Dropping %pI4 (ICMP)\n", &(iph->daddr));
return NF_DROP;
}
}
return NF_ACCEPT;
}
int registerFilter(void) {
printk(KERN_INFO "Registering filters.\n");
hook1.hook = blockPing;
hook1.hooknum = NF_INET_LOCAL_IN;
hook1.pf = PF_INET;
hook1.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &hook1);
hook2.hook = blockTCP;
hook2.hooknum = NF_INET_LOCAL_IN;
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 myfilters 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");
编译运行该程序,可以1看到使用别的机器都没有办法ping通VM本机了。
Task 2: Experimenting with Stateless Firewall Rules
Task 2.A: Protecting the Router
执行以下指令后观察现象
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 Set default rule for OUTPUT
iptables -P INPUT DROP Set default rule for INPUT
ping得通但telnet连接不上,以下原理
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
使进入本机的包icmp包类型为echo-request可以放行
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
使出本机的icmp包类型为echo-reply放行
iptables -P OUTPUT DROP
默认规则下所有出本机的包drop掉
iptables -P INPUT DROP
默认规则下所有进入本机的包drop掉
Task 2.B: Protecting the Internal Network
实验要求:
\1. Outside hosts cannot ping internal hosts.
\2. Outside hosts can ping the router.
\3. Internal hosts can ping outside hosts.
\4. All other packets between the internal and external networks should be blocked.
使用如下代码
iptables -A FORWARD -d 192.168.60.0/24 -p icmp --icmp-type echo-reply -j ACCEPT
iptables -A FORWARD -s 192.168.60.0/24 -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD DROP
可以看到,实现了实验所要求的效果
Task 2.C: Protecting Internal Servers
实验要求如下:
\1. 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.
\2. Outside hosts cannot access other internal servers.
\3. Internal hosts can access all the internal servers.
\4. Internal hosts cannot access external servers.
\5. In this task, the connection tracking mechanism is not allowed. It will be used in a later task.
iptables -A FORWARD -d 192.168.60.5 -p tcp --dport 23 -j ACCEPT
iptables -A FORWARD -d 192.168.60.5 -p tcp --dport 80 -j ACCEPT
iptables -A FORWARD -s 192.168.60.5 -p tcp -j ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD DROP
使用以上代码,可达成实验要求效果,截图如下
Task 3: Connection Tracking and Stateful Firewall
Task 3.A: Experiment with the Connection Tracking
观察得ICMP与TCP连接都一直持续,UDP连接只持续很短一段时间
Task 3.B: Setting Up a Stateful Firewall
iptables -A FORWARD -d 192.168.60.5 -p tcp --dport 23 --syn -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -s 192.168.60.0/24 -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
执行以上命令,可使内部机器可连接外部机器。
Task 4: Limiting Network Traffific
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
分别执行命令1和两条命令,可以看到只有执行了两条命令,该规则才会对包数量进行限制,原因是默认规则就是通过,不走限制规则也可直接通过路由到达192.168.60.5机器
Task 5: Load Balancing
Using the nth mode (round-robin)
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
启用上述规则,在192.168.60.0/24的三台机器中启用 nc -luk 8080
使用10.9.0.5机器 echo hello |nc -u 10.9.0.11 8080
可以看到将hello平均的分配到了三台机器中
Using the random mode
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode random --probability 0.333 -j DNAT --to-destination 192.168.60.5:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode random --probability 0.5 -j DNAT --to-destination 192.168.60.6:8080
iptables -t nat -A PREROUTING -p udp --dport 8080 -m statistic --mode random --probability 1 -j DNAT --to-destination 192.168.60.7:8080
可以看到,hello等几率的分配到了三个机器中,相比于上面的nth mode的平均分配 ,random mode是随机分配