@@ -56,6 +56,7 @@ static int g_exit = 0;
5656static int g_daemon = 0 ;
5757static int g_silent = 0 ;
5858static int g_killproc = 0 ;
59+ static int g_use_iptables = 0 ;
5960static int g_repeat = 3 ;
6061static uint32_t g_fwmark = 0x8000 ;
6162static 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+
321462static 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
11271297destroy_queue :
11281298 nfq_destroy_queue (qh );
0 commit comments