Skip to content

Commit 02b4f50

Browse files
feat: Add support for nft commands
1 parent e6dfb07 commit 02b4f50

2 files changed

Lines changed: 187 additions & 15 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Options:
2929
-t <ttl> TTL for generated packets
3030
-w <file> write log to <file> instead of stderr
3131
-x <mask> set the mask for fwmark
32+
-z use iptables commands instead of nft
33+
3234
```
3335

3436

src/fakehttp.c

Lines changed: 185 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static int g_exit = 0;
5656
static int g_daemon = 0;
5757
static int g_silent = 0;
5858
static int g_killproc = 0;
59+
static int g_use_iptables = 0;
5960
static int g_repeat = 3;
6061
static uint32_t g_fwmark = 0x8000;
6162
static uint32_t g_fwmask = 0;
@@ -82,6 +83,7 @@ static void print_usage(const char *name)
8283
" -t <ttl> TTL for generated packets\n"
8384
" -w <file> write log to <file> instead of stderr\n"
8485
" -x <mask> set the mask for fwmark\n"
86+
" -z use iptables commands instead of nft\n"
8587
"\n"
8688
"FakeHTTP version " VERSION "\n",
8789
name);
@@ -318,6 +320,145 @@ static int execute_command(char **argv, int silent)
318320
}
319321

320322

323+
static int nft_is_working(void)
324+
{
325+
char *nft_ver_cmd[] = {"nft", "--version", NULL};
326+
327+
return !execute_command(nft_ver_cmd, 1);
328+
}
329+
330+
331+
static int nft_rules_flush(int auto_create)
332+
{
333+
int res;
334+
size_t i, cnt;
335+
char *nft_argv[] = {"nft", NULL, NULL};
336+
char *nft_flush_cmd = "flush chain ip mangle FAKEHTTP";
337+
char *nft_create_cmds[] = {"add chain ip mangle FAKEHTTP",
338+
"flush chain ip mangle FAKEHTTP",
339+
"insert rule ip mangle INPUT jump FAKEHTTP",
340+
"insert rule ip mangle FORWARD jump FAKEHTTP"};
341+
342+
nft_argv[1] = nft_flush_cmd;
343+
res = execute_command(nft_argv, 1);
344+
if (res < 0) {
345+
if (!auto_create) {
346+
return -1;
347+
}
348+
349+
cnt = sizeof(nft_create_cmds) / sizeof(*nft_create_cmds);
350+
for (i = 0; i < cnt; i++) {
351+
nft_argv[1] = nft_create_cmds[i];
352+
res = execute_command(nft_argv, 0);
353+
if (res) {
354+
E("ERROR: execute_command()");
355+
return -1;
356+
}
357+
}
358+
}
359+
360+
return 0;
361+
}
362+
363+
364+
static int nft_rules_setup(void)
365+
{
366+
char mark_cmd_01[256], mark_cmd_02[256], mark_cmd_03[256];
367+
char queue_cmd_01[256], *fmt;
368+
size_t i, nft_cmds_cnt, nft_opt_cmds_cnt;
369+
int res;
370+
371+
char *nft_argv[] = {"nft", NULL, NULL};
372+
char *nft_cmds[] = {
373+
/*
374+
exclude marked packets
375+
*/
376+
mark_cmd_01, mark_cmd_02, mark_cmd_03,
377+
378+
/*
379+
exclude local IPs
380+
*/
381+
"add rule ip mangle FAKEHTTP ip saddr 0.0.0.0/8 return",
382+
"add rule ip mangle FAKEHTTP ip saddr 10.0.0.0/8 return",
383+
"add rule ip mangle FAKEHTTP ip saddr 100.64.0.0/10 return",
384+
"add rule ip mangle FAKEHTTP ip saddr 127.0.0.0/8 return",
385+
"add rule ip mangle FAKEHTTP ip saddr 169.254.0.0/16 return",
386+
"add rule ip mangle FAKEHTTP ip saddr 172.16.0.0/12 return",
387+
"add rule ip mangle FAKEHTTP ip saddr 192.168.0.0/16 return",
388+
"add rule ip mangle FAKEHTTP ip saddr 224.0.0.0/3 return",
389+
390+
/*
391+
send to nfqueue
392+
*/
393+
queue_cmd_01};
394+
395+
char *nft_opt_cmds[] = {
396+
/*
397+
exclude packets from connections with more than 32 packets
398+
*/
399+
"insert rule ip mangle FAKEHTTP ct packets > 32 return",
400+
401+
/*
402+
exclude big packets
403+
*/
404+
"insert rule ip mangle FAKEHTTP meta length > 120 return"};
405+
406+
nft_cmds_cnt = sizeof(nft_cmds) / sizeof(*nft_cmds);
407+
nft_opt_cmds_cnt = sizeof(nft_opt_cmds) / sizeof(*nft_opt_cmds);
408+
409+
fmt = "add rule ip mangle FAKEHTTP meta mark and %" PRIu32 " == %" PRIu32
410+
" ct mark set ct mark and %" PRIu32 " xor %" PRIu32;
411+
res = snprintf(mark_cmd_01, sizeof(mark_cmd_01), fmt, g_fwmask, g_fwmark,
412+
~g_fwmask, g_fwmark);
413+
if (res < 0 || (size_t) res >= sizeof(mark_cmd_01)) {
414+
E("ERROR: snprintf()");
415+
return -1;
416+
}
417+
418+
fmt = "add rule ip mangle FAKEHTTP ct mark and %" PRIu32 " == %" PRIu32
419+
" meta mark set mark and %" PRIu32 " xor %" PRIu32;
420+
res = snprintf(mark_cmd_02, sizeof(mark_cmd_02), fmt, g_fwmask, g_fwmark,
421+
~g_fwmask, g_fwmark);
422+
if (res < 0 || (size_t) res >= sizeof(mark_cmd_02)) {
423+
E("ERROR: snprintf()");
424+
return -1;
425+
}
426+
427+
428+
fmt = "add rule ip mangle FAKEHTTP meta mark and %" PRIu32 " == %" PRIu32
429+
" return";
430+
res = snprintf(mark_cmd_03, sizeof(mark_cmd_03), fmt, g_fwmask, g_fwmark);
431+
if (res < 0 || (size_t) res >= sizeof(mark_cmd_03)) {
432+
E("ERROR: snprintf()");
433+
return -1;
434+
}
435+
436+
fmt = "add rule ip mangle FAKEHTTP iifname \"%s\" tcp flags & (fin | rst "
437+
"| ack) == ack queue num %" PRIu32 " bypass";
438+
res = snprintf(queue_cmd_01, sizeof(queue_cmd_01), fmt, g_iface, g_nfqnum);
439+
if (res < 0 || (size_t) res >= sizeof(queue_cmd_01)) {
440+
E("ERROR: snprintf()");
441+
return -1;
442+
}
443+
444+
for (i = 0; i < nft_cmds_cnt; i++) {
445+
nft_argv[1] = nft_cmds[i];
446+
res = execute_command(nft_argv, 0);
447+
if (res) {
448+
E("ERROR: execute_command()");
449+
return -1;
450+
}
451+
}
452+
453+
for (i = 0; i < nft_opt_cmds_cnt; i++) {
454+
nft_argv[1] = nft_opt_cmds[i];
455+
execute_command(nft_argv, 1);
456+
}
457+
458+
return 0;
459+
}
460+
461+
321462
static int ipt_rules_flush(int auto_create)
322463
{
323464
int res;
@@ -792,7 +933,7 @@ int main(int argc, char *argv[])
792933
return EXIT_FAILURE;
793934
}
794935

795-
while ((opt = getopt(argc, argv, "dh:i:km:n:r:st:w:x:")) != -1) {
936+
while ((opt = getopt(argc, argv, "dh:i:km:n:r:st:w:x:z")) != -1) {
796937
switch (opt) {
797938
case 'd':
798939
g_daemon = 1;
@@ -874,6 +1015,9 @@ int main(int argc, char *argv[])
8741015
}
8751016
g_fwmask = tmp;
8761017
break;
1018+
case 'z':
1019+
g_use_iptables = 1;
1020+
break;
8771021
default:
8781022
print_usage(argv[0]);
8791023
return EXIT_FAILURE;
@@ -1045,18 +1189,40 @@ int main(int argc, char *argv[])
10451189
}
10461190

10471191
/*
1048-
Iptables
1192+
Firewall
10491193
*/
1050-
res = ipt_rules_flush(1);
1051-
if (res) {
1052-
E("ERROR: ipt_rules_flush()");
1053-
goto destroy_queue;
1194+
if (!g_use_iptables) {
1195+
if (!nft_is_working()) {
1196+
E("WARNING: Falling back to iptables command, as nft command is "
1197+
"not working.");
1198+
g_use_iptables = 1;
1199+
}
10541200
}
10551201

1056-
res = ipt_rules_setup();
1057-
if (res) {
1058-
E("ERROR: ipt_rules_setup()");
1059-
goto flush_iptables;
1202+
if (g_use_iptables) {
1203+
res = ipt_rules_flush(1);
1204+
if (res) {
1205+
E("ERROR: ipt_rules_flush()");
1206+
goto destroy_queue;
1207+
}
1208+
1209+
res = ipt_rules_setup();
1210+
if (res) {
1211+
E("ERROR: ipt_rules_setup()");
1212+
goto flush_rules;
1213+
}
1214+
} else {
1215+
res = nft_rules_flush(1);
1216+
if (res) {
1217+
E("ERROR: nft_rules_flush()");
1218+
goto destroy_queue;
1219+
}
1220+
1221+
res = nft_rules_setup();
1222+
if (res) {
1223+
E("ERROR: nft_rules_setup()");
1224+
goto flush_rules;
1225+
}
10601226
}
10611227

10621228
/*
@@ -1074,7 +1240,7 @@ int main(int argc, char *argv[])
10741240
res = signal_setup();
10751241
if (res) {
10761242
E("ERROR: signal_setup()");
1077-
goto flush_iptables;
1243+
goto flush_rules;
10781244
}
10791245

10801246
E("listening on %s, netfilter queue number %" PRIu32 "...", g_iface,
@@ -1087,7 +1253,7 @@ int main(int argc, char *argv[])
10871253
while (!g_exit) {
10881254
if (err_cnt >= 20) {
10891255
E("too many errors, exiting...");
1090-
goto flush_iptables;
1256+
goto flush_rules;
10911257
}
10921258

10931259
recv_len = recv(fd, buff, buffsize, 0);
@@ -1104,7 +1270,7 @@ int main(int argc, char *argv[])
11041270
default:
11051271
E("ERROR: recv(): %s", strerror(errno));
11061272
err_cnt++;
1107-
goto flush_iptables;
1273+
goto flush_rules;
11081274
}
11091275
}
11101276

@@ -1121,8 +1287,12 @@ int main(int argc, char *argv[])
11211287
E("exiting normally...");
11221288
exitcode = EXIT_SUCCESS;
11231289

1124-
flush_iptables:
1125-
ipt_rules_flush(0);
1290+
flush_rules:
1291+
if (g_use_iptables) {
1292+
ipt_rules_flush(0);
1293+
} else {
1294+
nft_rules_flush(0);
1295+
}
11261296

11271297
destroy_queue:
11281298
nfq_destroy_queue(qh);

0 commit comments

Comments
 (0)