forked from PinkD/nft-game
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetfilter.cpp
547 lines (489 loc) · 17.3 KB
/
netfilter.cpp
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
#include "netfilter.h"
#include <algorithm>
#include <map>
#include <mutex>
#include <regex>
#include <string>
#include <vector>
extern "C" void _handleICMP(cchar_t* buf, int len);
extern "C" void _handleUDP(EID id, cchar_t* ip, u_short port, cchar_t* buf,
int len);
extern "C" void _handleCloseUDP(EID id);
extern "C" void _handleDialTCP(EID id, u_short localPort, cchar_t* ip,
u_short port);
extern "C" void _handleTCP(EID id, cchar_t* buf, int len);
extern "C" void _handleCloseTCP(EID id, u_short localPort);
std::vector<std::string> processNames;
std::vector<NF_RULE_EX> processNameRules;
std::vector<NF_RULE_EX> portRules;
std::mutex ruleLock;
std::mutex udpOptionLock;
std::map<EID, PNF_UDP_OPTIONS> udpOptions;
std::mutex udpInfoLock;
std::map<EID, PNF_UDP_CONN_INFO> udpInfo;
std::mutex tcpInfoLock;
std::map<EID, PNF_TCP_CONN_INFO> tcpInfo;
DWORD currentPid = 0;
u_short tcpProxyPort = 0;
inline u_short convert_port(u_short port) { return port >> 8 | port << 8; }
void addRule(NF_RULE_EX rule) {
std::lock_guard<std::mutex> l(ruleLock);
processNameRules.push_back(rule);
}
void addTCPFilterForProcess(cchar_t* name) {
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.protocol = IPPROTO_TCP;
rule.direction = NF_D_OUT;
rule.filteringFlag = NF_INDICATE_CONNECT_REQUESTS;
// mbstowcs(rule.processName, name, strlen(name));
// printf("add tcp filter for process %s\n", name);
printf("add tcp filter\n");
addRule(rule);
}
void addUDPFilterForProcess(cchar_t* name) {
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.protocol = IPPROTO_UDP;
rule.direction = NF_D_OUT;
rule.filteringFlag = NF_FILTER;
// mbstowcs(rule.processName, name, strlen(name));
// printf("add udp filter for process %s\n", name);
printf("add udp filter\n");
addRule(rule);
}
void addConnectionFilterForProcess(cchar_t* name) {
processNames.push_back(name);
addTCPFilterForProcess(name);
addUDPFilterForProcess(name);
fflush(stdout);
}
void addICMPFilterForProcess(cchar_t* name) {
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.protocol = IPPROTO_ICMP;
rule.direction = NF_D_OUT;
rule.filteringFlag = NF_FILTER_AS_IP_PACKETS;
mbstowcs(rule.processName, name, strlen(name));
printf("add icmp filter for process %s\n", name);
fflush(stdout);
addRule(rule);
}
void addFilterForLoopback() {
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
auto size = 0;
WSAStringToAddressA((LPSTR)"127.0.0.1", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.0.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
void addFilterForReservedAddress() {
auto size = 0;
{
/* 10.0.0.0/8 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"10.0.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.0.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{
/* 100.64.0.0/10 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"100.64.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.192.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{ /* 169.254.0.0/16 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"169.254.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.255.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{ /* 172.16.0.0/12 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"100.64.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.240.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{ /* 192.0.0.0/24 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"192.0.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.255.255.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{ /* 192.168.0.0/16 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"192.168.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.255.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
{ /* 198.18.0.0/15 */
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.ip_family = AF_INET;
WSAStringToAddressA((LPSTR)"198.18.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddress, &size);
WSAStringToAddressA((LPSTR)"255.254.0.0", AF_INET, NULL,
(LPSOCKADDR)rule.remoteIpAddressMask, &size);
rule.filteringFlag = NF_ALLOW;
addRule(rule);
}
}
void flushRules() {
// always filter loopback and reserved address
addFilterForLoopback();
addFilterForReservedAddress();
std::lock_guard<std::mutex> l(ruleLock);
std::vector<NF_RULE_EX> rules;
std::for_each(processNameRules.begin(), processNameRules.end(),
[&rules](const auto& rule) { rules.push_back(rule); });
std::for_each(portRules.begin(), portRules.end(),
[&rules](const auto& rule) { rules.push_back(rule); });
nf_setRulesEx(rules.data(), rules.size());
}
void addFilterForProcess(cchar_t* name) {
addConnectionFilterForProcess(name);
addICMPFilterForProcess(name);
flushRules();
}
void operateFilterForPort(u_short port, int protocol, bool add) {
if (port == 0) {
printf("skip port 0\n");
fflush(stdout);
return;
}
if (add) {
NF_RULE_EX rule;
memset(&rule, 0, sizeof(NF_RULE_EX));
rule.direction = NF_D_OUT;
rule.protocol = protocol;
rule.localPort = port;
rule.filteringFlag = NF_FILTER_AS_IP_PACKETS;
std::lock_guard<std::mutex> l(ruleLock);
nf_addRuleEx(&rule, FALSE);
portRules.push_back(rule);
printf("add ip filter for port %d\n", port);
} else {
auto oldSize = portRules.size();
{
std::lock_guard<std::mutex> l(ruleLock);
std::remove_if(portRules.begin(), portRules.end(),
[port, protocol](const auto& rule) {
return rule.localPort == port &&
rule.protocol == protocol;
});
}
if (oldSize != portRules.size()) {
printf("remove ip filter for port %d\n", port);
flushRules();
}
}
fflush(stdout);
}
void addFilterForPort(u_short port, int protocol) {
operateFilterForPort(port, protocol, true);
}
void removeFilterForPort(u_short port, int protocol) {
operateFilterForPort(port, protocol, false);
}
std::string getProcessName(DWORD id) {
if (id == 0) {
return "Idle";
}
if (id == 4) {
return "System";
}
wchar_t name[MAX_PATH];
if (!nf_getProcessNameFromKernel(id, name, MAX_PATH)) {
if (!nf_getProcessNameW(id, name, MAX_PATH)) {
return "Unknown";
}
}
auto to_str = [](wchar_t* s) {
auto ws = std::wstring(s);
return std::string(ws.begin(), ws.end());
};
wchar_t data[MAX_PATH];
if (GetLongPathNameW(name, data, MAX_PATH)) {
return to_str(data);
}
return to_str(name);
}
bool checkProcessName(DWORD pid) {
auto targetName = getProcessName(pid);
// printf("name of %d is %s\n", pid, targetName.data());
auto match = false;
for (auto& name : processNames) {
if (regex_search(targetName, std::regex(name))) {
return true;
}
}
return false;
}
// API events handler
void threadStart() {
printf("threadStart\n");
fflush(stdout);
}
void threadEnd() { printf("threadEnd\n"); }
// TCP events
void tcpConnectRequest(EID id, PNF_TCP_CONN_INFO pConnInfo) {
auto pid = pConnInfo->processId;
if (currentPid == pid || !checkProcessName(pid)) {
nf_tcpDisableFiltering(id);
return;
}
auto loccalAddr = (struct sockaddr_in*)pConnInfo->localAddress;
u_short localPort = convert_port(loccalAddr->sin_port);
printf("local ip: %d.%d.%d.%d:%d\n", loccalAddr->sin_addr.S_un.S_un_b.s_b1,
loccalAddr->sin_addr.S_un.S_un_b.s_b2,
loccalAddr->sin_addr.S_un.S_un_b.s_b3,
loccalAddr->sin_addr.S_un.S_un_b.s_b4, localPort);
struct in_addr remoteAddr;
auto addr = (struct sockaddr_in*)pConnInfo->remoteAddress;
memcpy(&remoteAddr, &addr->sin_addr, sizeof(remoteAddr));
auto port = convert_port(addr->sin_port);
printf("remote ip: %d.%d.%d.%d:%d\n", addr->sin_addr.S_un.S_un_b.s_b1,
addr->sin_addr.S_un.S_un_b.s_b2, addr->sin_addr.S_un.S_un_b.s_b3,
addr->sin_addr.S_un.S_un_b.s_b4, port);
printf("tcpConnectRequest id=%I64u\n", id);
fflush(stdout);
if (pConnInfo->ip_family == AF_INET) {
auto addr = (struct sockaddr_in*)pConnInfo->remoteAddress;
addr->sin_family = AF_INET;
addr->sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
addr->sin_port = tcpProxyPort;
printf("redirect to 127.0.0.1:%d\n", tcpProxyPort);
}
if (pConnInfo->ip_family == AF_INET6) {
auto addr = (struct sockaddr_in6*)pConnInfo->remoteAddress;
IN6ADDR_SETLOOPBACK(addr);
addr->sin6_port = tcpProxyPort;
printf("redirect to [::1]:%d\n", tcpProxyPort);
}
fflush(stdout);
{
std::lock_guard<std::mutex> l(tcpInfoLock);
tcpInfo[id] = pConnInfo;
}
_handleDialTCP(id, localPort, (cchar_t*)&remoteAddr, port);
}
void tcpConnected(EID id, PNF_TCP_CONN_INFO pConnInfo) {
printf("tcpConnected id=%I64u\n", id);
fflush(stdout);
}
void tcpClosed(EID id, PNF_TCP_CONN_INFO pConnInfo) {
printf("tcpClosed id=%I64u\n", id);
fflush(stdout);
{
std::lock_guard<std::mutex> l(tcpInfoLock);
tcpInfo.erase(id);
}
struct sockaddr_in* loccalAddr =
(struct sockaddr_in*)pConnInfo->localAddress;
u_short localPort = convert_port(loccalAddr->sin_port);
_handleCloseTCP(id, localPort);
}
void tcpReceive(EID id, const char* buf, int len) {
printf("tcpReceive id=%I64u len=%d\n", id, len);
fflush(stdout);
nf_tcpPostReceive(id, buf, len);
}
void tcpSend(EID id, const char* buf, int len) {
printf("tcpSend id=%I64u len=%d\n", id, len);
fflush(stdout);
nf_tcpPostSend(id, buf, len);
}
void tcpCanReceive(EID id) {
// printf("tcpCanReceive id=%I64d\n", id);
// fflush(stdout);
}
void tcpCanSend(EID id) {
// printf("tcpCanSend id=%I64d\n", id);
// fflush(stdout);
}
// UDP events
void udpCreated(EID id, PNF_UDP_CONN_INFO pConnInfo) {
auto pid = pConnInfo->processId;
if (currentPid == pid || !checkProcessName(pid)) {
nf_udpDisableFiltering(id);
return;
}
auto addr = (struct sockaddr_in*)pConnInfo->localAddress;
auto port = convert_port(addr->sin_port);
printf("local ip: %d.%d.%d.%d:%d\n", addr->sin_addr.S_un.S_un_b.s_b1,
addr->sin_addr.S_un.S_un_b.s_b2, addr->sin_addr.S_un.S_un_b.s_b3,
addr->sin_addr.S_un.S_un_b.s_b4, port);
{
std::lock_guard<std::mutex> l(udpInfoLock);
udpInfo[id] = pConnInfo;
}
printf("udpCreated id=%I64d\n", id);
fflush(stdout);
}
void udpConnectRequest(EID id, PNF_UDP_CONN_REQUEST pConnReq) {
printf("udpConnectRequest id=%I64u\n", id);
fflush(stdout);
}
void udpClosed(EID id, PNF_UDP_CONN_INFO pConnInfo) {
printf("udpClosed id=%I64d\n", id);
fflush(stdout);
{
std::lock_guard<std::mutex> l(udpOptionLock);
auto option = udpOptions[id];
if (option != nullptr) {
delete option;
udpOptions.erase(id);
}
}
{
std::lock_guard<std::mutex> l(udpInfoLock);
udpInfo.erase(id);
}
_handleCloseUDP(id);
}
void udpReceive(EID id, const unsigned char* remoteAddress, const char* buf,
int len, PNF_UDP_OPTIONS options) {
printf("udpReceive id=%I64d\n", id);
fflush(stdout);
nf_udpPostReceive(id, remoteAddress, buf, len, options);
}
void udpSend(EID id, const unsigned char* remoteAddress, const char* buf,
int len, PNF_UDP_OPTIONS options) {
printf("udpSend id=%I64d\n", id);
struct sockaddr_in* addr = (struct sockaddr_in*)remoteAddress;
// ignore broadcast
if (addr->sin_port == 0) {
nf_udpPostSend(id, remoteAddress, buf, len, options);
return;
}
{
std::lock_guard<std::mutex> l(udpInfoLock);
if (udpInfo.find(id) == udpInfo.end()) {
nf_udpPostSend(id, remoteAddress, buf, len, options);
return;
}
}
u_short port = convert_port(addr->sin_port);
{
std::lock_guard<std::mutex> l(udpOptionLock);
if (udpOptions.find(id) == udpOptions.end()) {
printf("nf udp send to: %d.%d.%d.%d:%d\n",
addr->sin_addr.S_un.S_un_b.s_b1,
addr->sin_addr.S_un.S_un_b.s_b2,
addr->sin_addr.S_un.S_un_b.s_b3,
addr->sin_addr.S_un.S_un_b.s_b4, port);
auto option = (PNF_UDP_OPTIONS) new char[sizeof(NF_UDP_OPTIONS) +
options->optionsLength]();
memcpy(option, options,
sizeof(NF_UDP_OPTIONS) + options->optionsLength - 1);
udpOptions[id] = option;
}
}
_handleUDP(id, (cchar_t*)&addr->sin_addr, port, buf, len);
fflush(stdout);
}
void udpCanReceive(EID id) {
// printf("udpCanReceive id=%I64d\n", id);
// fflush(stdout);
}
void udpCanSend(EID id) {
// printf("udpCanSend id=%I64d\n", id);
// fflush(stdout);
}
// the ip packet won't change, we only need one
PNF_IP_PACKET_OPTIONS globalOption;
// API events handler for IP packets
void ipReceive(const char* buf, int len, PNF_IP_PACKET_OPTIONS options) {
nf_ipPostReceive(buf, len, options);
}
void ipSend(const char* buf, int len, PNF_IP_PACKET_OPTIONS options) {
if (globalOption == NULL) {
globalOption = options;
}
printf("ipSend: packet from nf\n");
fflush(stdout);
_handleICMP(buf, len);
}
NF_EventHandler eh = {
threadStart, threadEnd, tcpConnectRequest, tcpConnected,
tcpClosed, tcpReceive, tcpSend, tcpCanReceive,
tcpCanSend, udpCreated, udpConnectRequest, udpClosed,
udpReceive, udpSend, udpCanReceive, udpCanSend,
};
NF_IPEventHandler ipeh = {
ipReceive,
ipSend,
};
int initDriver(cchar_t* name, u_short port) {
printf("loading driver %s\n", name);
NF_STATUS status = nf_init(name, &eh);
if (status != NF_STATUS_SUCCESS) {
printf("load return status: %d\n", status);
return 1;
}
nf_setIPEventHandler(&ipeh);
currentPid = GetCurrentProcessId();
// convert to network port
tcpProxyPort = convert_port(port);
return 0;
}
void freeDriver() { nf_free(); }
void writeTCPData(EID id, cchar_t* buf, int len) {
printf("wg write tcp to eid: %d\n", id);
nf_tcpPostReceive(id, buf, len);
}
void writeUDPData(EID id, cchar_t* ip, u_short port, cuc_t* buf, int len) {
printf("wg write udp to eid: %d, len is %d\n", id, len);
fflush(stdout);
std::lock_guard<std::mutex> l(udpOptionLock);
auto option = udpOptions.find(id);
if (option != udpOptions.end()) {
struct sockaddr_in addr;
addr.sin_addr.S_un.S_addr = inet_addr(ip);
addr.sin_port = convert_port(port);
printf("wg udp from ip: %d.%d.%d.%d:%d\n",
addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2,
addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4,
convert_port(addr.sin_port));
// printf("data: %02x%02x%02x%02x%02x%02x%02x%02x\n", buf[0], buf[1],
// buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
// fflush(stdout);
nf_udpPostReceive(id, (cuc_t*)&addr, (cchar_t*)buf, len,
option->second);
}
}