-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathmain.c
More file actions
executable file
·141 lines (117 loc) · 4.16 KB
/
Copy pathmain.c
File metadata and controls
executable file
·141 lines (117 loc) · 4.16 KB
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
/*
* main.cxx
*
* Created on: 2012年4月20日
* Author: Fifi Lyu
*/
#include "issue.h"
#include "common/file.h"
#include "common/host.h"
#include "common/misc.h"
#include "common/network.h"
#include <linux/version.h> // for LINUX_VERSION_CODE KERNEL_VERSION
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
#include <linux/in.h> // for IPPROTO_TCP
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
MODULE_LICENSE(LICENSE);
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
static char *g_hosts = NULL;
static loff_t g_hosts_size = 0;
static network_t *g_net_array = NULL;
static size_t g_net_array_size = 0;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)
unsigned int nf_hook_func(
unsigned int hooknum, struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, int (*okfn)(struct sk_buff *)) {
struct sk_buff *skb_ = skb;
#else
unsigned int nf_hook_func(
unsigned int hooknum, struct sk_buff **skb, const struct net_device *in,
const struct net_device *out, int (*okfn)(struct sk_buff *)) {
struct sk_buff *skb_ = *skb;
#endif
struct iphdr *ip_header_ = NULL;
struct tcphdr *tcp_header_ = NULL;
unsigned char *tcp_data_ = NULL;
if (!skb_)
return NF_ACCEPT;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
ip_header_ = ip_hdr(skb_);
#else
ip_header_ = skb_->h.ipiph;
#endif
// 仅仅过滤 TCP 协议
if (!ip_header_ || ip_header_->protocol != IPPROTO_TCP)
return NF_ACCEPT;
// 已知在 2.6.18/3.19.2 上,tcp_hdr(skb_) 会返回预期的 tcp 头偏移量。
// 已知在 2.6.32 上,tcp_hdr(skb_) 与 ip_hdr(skb_) 会返回相同的指针地址。
//
// 2.6.32:
// TCP 包来自 1/2 层,netfilter/ipv4 钩子会在第 3 层被注入。
// 因此,此时使用 tcp_hdr 函数不会获得预期的 tcp 头偏移量。
// 直接根据 IP 头偏移量计算 TCP 头偏移量是最合适的
tcp_header_ = (struct tcphdr *)((__u32 *)ip_header_ + ip_header_->ihl);
// 仅仅过滤指定的 HTTP 端口
if (htons(tcp_header_->dest) != HTTP_PORT)
return NF_ACCEPT;
// 如果是信任的网络,则放行。不做任何过滤
// 因此,如果本机作为转发网关,必须添加内网网段,内网网络才能访问公网。
if (check_net(ip_header_->saddr, g_net_array, g_net_array_size))
return NF_ACCEPT;
// GET / HTTP/1.1\r\n
// User-Agent: curl/7.41.0\r\n
// Host: abc.com\r\n
// Accept: */*\r\n
// \r\n
tcp_data_ = get_tcp_data(skb_, ip_header_, tcp_header_);
// 跳过非 HTTP 头相关包
if (!check_http_header(tcp_data_))
return NF_ACCEPT;
// 如果是信任的主机,则放行
if (check_host(tcp_data_, g_hosts, g_hosts_size))
return NF_ACCEPT;
return NF_DROP;
}
static struct nf_hook_ops g_nf_hook = {
.hook = (nf_hookfn*) nf_hook_func,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
.hooknum = NF_INET_PRE_ROUTING,
#else
.hooknum = NF_IP_PRE_ROUTING,
#endif
.pf = PF_INET,
.priority = NF_IP_PRI_FIRST
};
int init_module() {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
pr_err("[%s] Linux Kernel Version does not supported.\n", MODOUBLE_NAME);
return -1;
#endif
pr_info("Loading module \"%s\"\n", MODOUBLE_NAME);
if (!init_host_str(&g_hosts, &g_hosts_size)) {
pr_err("Cannot initialize host whitelist.\n");
pr_err("Cannot load module \"%s\"\n", MODOUBLE_NAME);
return -1;
}
if (!init_net_array(&g_net_array, &g_net_array_size)) {
pr_err("Cannot initialize network whitelist.\n");
pr_err("Cannot load module \"%s\"\n", MODOUBLE_NAME);
return -1;
}
if (nf_register_hook(&g_nf_hook) < 0) {
pr_err("Cannot register netfilter hook.\n");
pr_err("Cannot load module \"%s\"\n", MODOUBLE_NAME);
return -1;
}
return 0;
}
void cleanup_module() {
pr_info("Unloading module \"%s\"\n", MODOUBLE_NAME);
if (g_hosts) kfree(g_hosts);
if (g_net_array) kfree(g_net_array);
nf_unregister_hook(&g_nf_hook);
}