@@ -64,7 +64,7 @@ func (r *autoRedirect) setupNFTables() error {
6464 if ! r .shouldSkipOutputChain () {
6565 outputNATPriority := nftables .ChainPriorityMangle
6666 if r .nfqueueEnabled {
67- outputNATPriority = nftables .ChainPriorityRef (* nftables .ChainPriorityMangle + 1 )
67+ outputNATPriority = nftables .ChainPriorityRef (* nftables .ChainPriorityMangle + 2 )
6868 }
6969 chainOutput := nft .AddChain (& nftables.Chain {
7070 Name : "output" ,
@@ -88,7 +88,7 @@ func (r *autoRedirect) setupNFTables() error {
8888 Name : "output_route" ,
8989 Table : table ,
9090 Hooknum : nftables .ChainHookOutput ,
91- Priority : nftables . ChainPriorityMangle ,
91+ Priority : outputNATPriority ,
9292 Type : nftables .ChainTypeRoute ,
9393 })
9494 err = r .nftablesCreateLoopbackReroute (nft , table , chainOutputRoute )
@@ -100,7 +100,7 @@ func (r *autoRedirect) setupNFTables() error {
100100 Name : "output_udp_icmp" ,
101101 Table : table ,
102102 Hooknum : nftables .ChainHookOutput ,
103- Priority : nftables . ChainPriorityMangle ,
103+ Priority : outputNATPriority ,
104104 Type : nftables .ChainTypeRoute ,
105105 })
106106 err = r .nftablesCreateExcludeRules (nft , table , chainOutputUDP )
@@ -135,11 +135,17 @@ func (r *autoRedirect) setupNFTables() error {
135135 r .nftablesCreateRedirectPortReject (nft , table , chainInput )
136136 }
137137
138+ preroutingNATPriority := nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest + 1 )
139+ preroutingRoutePriority := nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest + 2 )
140+ if r .nfqueueEnabled {
141+ preroutingNATPriority = nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest + 2 )
142+ preroutingRoutePriority = nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest + 3 )
143+ }
138144 chainPreRouting := nft .AddChain (& nftables.Chain {
139145 Name : "prerouting" ,
140146 Table : table ,
141147 Hooknum : nftables .ChainHookPrerouting ,
142- Priority : nftables . ChainPriorityRef ( * nftables . ChainPriorityNATDest + 1 ) ,
148+ Priority : preroutingNATPriority ,
143149 Type : nftables .ChainTypeNAT ,
144150 })
145151 err = r .nftablesCreateExcludeRules (nft , table , chainPreRouting )
@@ -158,7 +164,7 @@ func (r *autoRedirect) setupNFTables() error {
158164 Name : "prerouting_filter" ,
159165 Table : table ,
160166 Hooknum : nftables .ChainHookPrerouting ,
161- Priority : nftables . ChainPriorityRef ( * nftables . ChainPriorityNATDest + 1 ) ,
167+ Priority : preroutingNATPriority ,
162168 Type : nftables .ChainTypeFilter ,
163169 })
164170 err = r .nftablesCreateLoopbackReroute (nft , table , chainPreRoutingFilter )
@@ -170,7 +176,7 @@ func (r *autoRedirect) setupNFTables() error {
170176 Name : "prerouting_udp_icmp" ,
171177 Table : table ,
172178 Hooknum : nftables .ChainHookPrerouting ,
173- Priority : nftables . ChainPriorityRef ( * nftables . ChainPriorityNATDest + 2 ) ,
179+ Priority : preroutingRoutePriority ,
174180 Type : nftables .ChainTypeFilter ,
175181 })
176182 ipProto := & nftables.Set {
@@ -331,7 +337,6 @@ func (r *autoRedirect) updateNetworkAddresses() error {
331337 return err
332338}
333339
334- // TODO: test if this works
335340func (r * autoRedirect ) nftablesUpdateLocalAddressSet () error {
336341 err := r .interfaceFinder .Update ()
337342 if err != nil {
@@ -414,20 +419,20 @@ func (r *autoRedirect) nftablesCreatePreMatchChains(nft *nftables.Conn, table *n
414419 Name : "prerouting_prematch" ,
415420 Table : table ,
416421 Hooknum : nftables .ChainHookPrerouting ,
417- Priority : nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest - 1 ),
422+ Priority : nftables .ChainPriorityRef (* nftables .ChainPriorityNATDest + 1 ),
418423 Type : nftables .ChainTypeFilter ,
419424 })
420425 err := r .nftablesAddPreMatchRules (nft , table , chainPreroutingPreMatch , true )
421426 if err != nil {
422427 return err
423428 }
424429
425- if ! r .shouldSkipOutputChain () {
430+ if r . tunOptions . AutoRedirectMarkMode && ! r .shouldSkipOutputChain () {
426431 chainOutputPreMatch := nft .AddChain (& nftables.Chain {
427432 Name : "output_prematch" ,
428433 Table : table ,
429434 Hooknum : nftables .ChainHookOutput ,
430- Priority : nftables .ChainPriorityRef (* nftables .ChainPriorityMangle - 1 ),
435+ Priority : nftables .ChainPriorityRef (* nftables .ChainPriorityMangle + 1 ),
431436 Type : nftables .ChainTypeFilter ,
432437 })
433438 err = r .nftablesAddPreMatchRules (nft , table , chainOutputPreMatch , false )
@@ -440,19 +445,33 @@ func (r *autoRedirect) nftablesCreatePreMatchChains(nft *nftables.Conn, table *n
440445}
441446
442447func (r * autoRedirect ) nftablesAddPreMatchRules (nft * nftables.Conn , table * nftables.Table , chain * nftables.Chain , isPrerouting bool ) error {
443- ifnameKey := expr .MetaKeyOIFNAME
444- if isPrerouting {
445- ifnameKey = expr .MetaKeyIIFNAME
448+ if ! isPrerouting {
449+ nft .AddRule (& nftables.Rule {
450+ Table : table ,
451+ Chain : chain ,
452+ Exprs : []expr.Any {
453+ & expr.Meta {Key : expr .MetaKeyOIFNAME , Register : 1 },
454+ & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : nftablesIfname (r .tunOptions .Name )},
455+ & expr.Verdict {Kind : expr .VerdictReturn },
456+ },
457+ })
458+ }
459+
460+ if r .enableIPv4 != r .enableIPv6 {
461+ disabledFamily := nftables .TableFamilyIPv6
462+ if r .enableIPv6 {
463+ disabledFamily = nftables .TableFamilyIPv4
464+ }
465+ nft .AddRule (& nftables.Rule {
466+ Table : table ,
467+ Chain : chain ,
468+ Exprs : []expr.Any {
469+ & expr.Meta {Key : expr .MetaKeyNFPROTO , Register : 1 },
470+ & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : []byte {uint8 (disabledFamily )}},
471+ & expr.Verdict {Kind : expr .VerdictReturn },
472+ },
473+ })
446474 }
447- nft .AddRule (& nftables.Rule {
448- Table : table ,
449- Chain : chain ,
450- Exprs : []expr.Any {
451- & expr.Meta {Key : ifnameKey , Register : 1 },
452- & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : nftablesIfname (r .tunOptions .Name )},
453- & expr.Verdict {Kind : expr .VerdictReturn },
454- },
455- })
456475
457476 preMatchProtocols := & nftables.Set {
458477 Table : table ,
@@ -487,12 +506,31 @@ func (r *autoRedirect) nftablesAddPreMatchRules(nft *nftables.Conn, table *nftab
487506 },
488507 })
489508
490- // Bypass mark: save to conntrack and return.
491- // When the NFQUEUE handler returns NF_REPEAT with the output mark,
492- // the packet re-enters this chain from the beginning. This rule
493- // catches it, saves the mark to conntrack (so subsequent packets
494- // of the same connection are bypassed via ct mark check below),
495- // and returns.
509+ nft .AddRule (& nftables.Rule {
510+ Table : table ,
511+ Chain : chain ,
512+ Exprs : []expr.Any {
513+ & expr.Meta {Key : expr .MetaKeyL4PROTO , Register : 1 },
514+ & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : []byte {unix .IPPROTO_TCP }},
515+ & expr.Payload {
516+ OperationType : expr .PayloadLoad ,
517+ DestRegister : 1 ,
518+ Base : expr .PayloadBaseTransportHeader ,
519+ Offset : 13 ,
520+ Len : 1 ,
521+ },
522+ & expr.Bitwise {
523+ SourceRegister : 1 ,
524+ DestRegister : 1 ,
525+ Len : 1 ,
526+ Mask : []byte {0x12 },
527+ Xor : []byte {0x00 },
528+ },
529+ & expr.Cmp {Op : expr .CmpOpNeq , Register : 1 , Data : []byte {0x02 }},
530+ & expr.Verdict {Kind : expr .VerdictReturn },
531+ },
532+ })
533+
496534 nft .AddRule (& nftables.Rule {
497535 Table : table ,
498536 Chain : chain ,
@@ -505,9 +543,6 @@ func (r *autoRedirect) nftablesAddPreMatchRules(nft *nftables.Conn, table *nftab
505543 },
506544 })
507545
508- // Reset mark: reject with TCP RST.
509- // When the NFQUEUE handler returns NF_REPEAT with the reset mark,
510- // the packet re-enters this chain and is rejected here.
511546 nft .AddRule (& nftables.Rule {
512547 Table : table ,
513548 Chain : chain ,
@@ -521,7 +556,6 @@ func (r *autoRedirect) nftablesAddPreMatchRules(nft *nftables.Conn, table *nftab
521556 },
522557 })
523558
524- // Already-tracked bypass connections: return immediately.
525559 nft .AddRule (& nftables.Rule {
526560 Table : table ,
527561 Chain : chain ,
@@ -544,35 +578,24 @@ func (r *autoRedirect) nftablesAddPreMatchRules(nft *nftables.Conn, table *nftab
544578 })
545579 }
546580
581+ err = r .nftablesCreateExcludeRules (nft , table , chain )
582+ if err != nil {
583+ return err
584+ }
585+
547586 queueExpression := func () * expr.Queue {
548587 return & expr.Queue {
549588 Num : r .effectiveNFQueue (),
550589 Flag : expr .QueueFlagBypass ,
551590 }
552591 }
553592
554- // TCP SYN: send to NFQUEUE for pre-match evaluation.
555593 nft .AddRule (& nftables.Rule {
556594 Table : table ,
557595 Chain : chain ,
558596 Exprs : []expr.Any {
559597 & expr.Meta {Key : expr .MetaKeyL4PROTO , Register : 1 },
560598 & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : []byte {unix .IPPROTO_TCP }},
561- & expr.Payload {
562- OperationType : expr .PayloadLoad ,
563- DestRegister : 1 ,
564- Base : expr .PayloadBaseTransportHeader ,
565- Offset : 13 ,
566- Len : 1 ,
567- },
568- & expr.Bitwise {
569- SourceRegister : 1 ,
570- DestRegister : 1 ,
571- Len : 1 ,
572- Mask : []byte {0x12 },
573- Xor : []byte {0x00 },
574- },
575- & expr.Cmp {Op : expr .CmpOpEq , Register : 1 , Data : []byte {0x02 }},
576599 & expr.Counter {},
577600 queueExpression (),
578601 },
0 commit comments