元芳你怎么看

本网站主要用于记录我个人学习的内容,希望对你有所帮助

0%

简单防火墙

写一个简单的包过滤防火墙涉及到使用 netfilter 框架,netfilter 是 Linux 内核中的一个子系统,用于处理和过滤网络数据包。我们可以使用 iptables 来设置规则,但如果我们想要自己编写代码,则需要编写一个内核模块或使用 libnetfilter_queue 来处理用户空间的包过滤。这里我们使用 libnetfilter_queue 库来编写一个简单的包过滤防火墙。

环境设置

首先,确保你已经安装了必要的库和开发包。可以使用以下命令安装它们:

1
sudo apt-get install libnetfilter-queue-dev

防火墙代码

下面是一个简单的 C 代码示例,使用 libnetfilter_queue 来过滤数据包。这个防火墙只允许 ICMP(如 ping)和 TCP 数据包通过,拒绝其他类型的数据包。

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <linux/netfilter.h> /* for NF_ACCEPT */
#include <libnetfilter_queue/libnetfilter_queue.h>

/* Callback function to process packets */
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
struct nfqnl_msg_packet_hdr *ph;
unsigned char *payload;
int id = 0;

ph = nfq_get_msg_packet_hdr(nfa);
if (ph) {
id = ntohl(ph->packet_id);
}

int ret = nfq_get_payload(nfa, &payload);
if (ret >= 0) {
struct iphdr *ip_header = (struct iphdr *)payload;
if (ip_header->protocol == IPPROTO_ICMP || ip_header->protocol == IPPROTO_TCP) {
// Allow ICMP and TCP packets
return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
}
}

// Drop all other packets
return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);
}

int main(int argc, char **argv)
{
struct nfq_handle *h;
struct nfq_q_handle *qh;
struct nfnl_handle *nh;
int fd;
int rv;
char buf[4096] __attribute__ ((aligned));

printf("Opening library handle\n");
h = nfq_open();
if (!h) {
fprintf(stderr, "Error during nfq_open()\n");
exit(1);
}

printf("Unbinding existing nf_queue handler for AF_INET (if any)\n");
if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "Error during nfq_unbind_pf()\n");
exit(1);
}

printf("Binding nfnetlink_queue as nf_queue handler for AF_INET\n");
if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "Error during nfq_bind_pf()\n");
exit(1);
}

printf("Binding this socket to queue '0'\n");
qh = nfq_create_queue(h, 0, &cb, NULL);
if (!qh) {
fprintf(stderr, "Error during nfq_create_queue()\n");
exit(1);
}

printf("Setting copy_packet mode\n");
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "Can't set packet_copy mode\n");
exit(1);
}

fd = nfq_fd(h);

while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
nfq_handle_packet(h, buf, rv);
}

printf("Unbinding from queue 0\n");
nfq_destroy_queue(qh);

printf("Closing library handle\n");
nfq_close(h);

exit(0);
}

编译代码

将上述代码保存为 firewall.c,然后编译它:

1
gcc -o firewall firewall.c -lnetfilter_queue

设置 iptables 规则

为了让 iptables 将数据包传递到 NFQUEUE,使用以下命令:

1
2
sudo iptables -I INPUT -j NFQUEUE --queue-num 0
sudo iptables -I OUTPUT -j NFQUEUE --queue-num 0

运行防火墙

运行编译后的防火墙程序:

1
sudo ./firewall

测试防火墙

  1. 允许 ICMP 包(如 ping)

    打开一个终端,运行 ping 命令:

    1
    ping 8.8.8.8

    你应该看到 ping 包被允许通过。

  2. 允许 TCP 包

    打开一个终端,运行 curl 命令:

    1
    curl http://example.com

    你应该看到 curl 请求被允许通过。

  3. 拒绝其他包

    所有其他类型的数据包将被拒绝。

清理

完成测试后,清理 iptables 规则:

1
2
sudo iptables -D INPUT -j NFQUEUE --queue-num 0
sudo iptables -D OUTPUT -j NFQUEUE --queue-num 0

这就是一个简单的包过滤防火墙的实现,利用 libnetfilter_queue 来处理和过滤数据包。你可以根据需要进一步扩展和修改此代码以实现更复杂的防火墙功能。

要测试 iptables 防火墙规则,确认其是否正确拒绝和允许指定的服务,可以进行以下步骤:

1. 检查允许的服务

允许的服务包括:

  • 本地回环接口流量
  • 已建立和相关的连接
  • SSH (端口 22)
  • ICMP (ping)
  • HTTP (端口 80) 和 HTTPS (端口 443)

测试 SSH 连接

在本地或远程系统上,尝试通过 SSH 连接到配置了防火墙的机器:

1
ssh user@your_server_ip

应能够成功连接。

测试 HTTP 和 HTTPS

在本地或远程系统上,使用 curl 或浏览器访问 HTTP 和 HTTPS 服务:

1
2
curl http://your_server_ip
curl https://your_server_ip

应返回相应的网页内容或响应头。

测试 ICMP (ping)

在本地或远程系统上,尝试 ping 配置了防火墙的机器:

1
ping your_server_ip

应接收到来自目标机器的响应。

2. 检查拒绝的服务

未特别允许的服务应被拒绝。

测试其他端口

尝试访问未允许的端口(例如,端口 23),应该被拒绝:

1
telnet your_server_ip 23

或使用 nc (netcat):

1
nc -zv your_server_ip 23

应显示连接被拒绝或超时。

3. 使用日志检查拒绝的服务

防火墙脚本包含日志记录规则,可以通过系统日志检查被拒绝的连接:

1
sudo tail -f /var/log/syslog

或在某些系统上:

1
sudo journalctl -f

尝试连接未允许的服务,并在日志中查看记录的 IPTABLES-DROP 消息。

总结

以下是一个完整的测试步骤:

  1. 测试允许的服务

    • SSH 连接:
      1
      ssh user@your_server_ip
    • HTTP 和 HTTPS 访问:
      1
      2
      curl http://your_server_ip
      curl https://your_server_ip
    • ICMP (ping):
      1
      ping your_server_ip
  2. 测试拒绝的服务

    • 其他端口访问:
      1
      2
      telnet your_server_ip 23
      nc -zv your_server_ip 23
  3. 查看系统日志

    • 检查日志以确认拒绝的服务被记录:
      1
      sudo tail -f /var/log/syslog
      1
      sudo journalctl -f

通过这些测试,你可以确认防火墙规则是否正确应用,并确保只允许指定的服务。