//go:build linux package tun import ( "github.com/sagernet/nftables" "github.com/sagernet/nftables/expr" "golang.org/x/exp/slices" ) func (r *autoRedirect) configureOpenWRTFirewall4(nft *nftables.Conn, cleanup bool) error { tableFW4, err := nft.ListTableOfFamily("fw4", nftables.TableFamilyINet) if err != nil { return nil } if !cleanup { ruleIif := &nftables.Rule{ Table: tableFW4, Exprs: []expr.Any{ &expr.Meta{ Key: expr.MetaKeyIIFNAME, Register: 1, }, &expr.Cmp{ Op: expr.CmpOpEq, Register: 1, Data: nftablesIfname(r.tunOptions.Name), }, &expr.Counter{}, &expr.Verdict{ Kind: expr.VerdictAccept, }, }, } ruleOif := &nftables.Rule{ Table: tableFW4, Exprs: []expr.Any{ &expr.Meta{ Key: expr.MetaKeyOIFNAME, Register: 1, }, &expr.Cmp{ Op: expr.CmpOpEq, Register: 1, Data: nftablesIfname(r.tunOptions.Name), }, &expr.Counter{}, &expr.Verdict{ Kind: expr.VerdictAccept, }, }, } chainForward := &nftables.Chain{ Name: "forward", } ruleIif.Chain = chainForward ruleOif.Chain = chainForward nft.InsertRule(ruleOif) nft.InsertRule(ruleIif) chainInput := &nftables.Chain{ Name: "input", } ruleIif.Chain = chainInput ruleOif.Chain = chainInput nft.InsertRule(ruleOif) nft.InsertRule(ruleIif) return nil } for _, chainName := range []string{"input", "forward"} { var rules []*nftables.Rule rules, err = nft.GetRules(tableFW4, &nftables.Chain{ Name: chainName, }) if err != nil { return err } for _, rule := range rules { if len(rule.Exprs) != 4 { continue } exprMeta, isMeta := rule.Exprs[0].(*expr.Meta) if !isMeta { continue } if exprMeta.Key != expr.MetaKeyIIFNAME && exprMeta.Key != expr.MetaKeyOIFNAME { continue } exprCmp, isCmp := rule.Exprs[1].(*expr.Cmp) if !isCmp { continue } if !slices.Equal(exprCmp.Data, nftablesIfname(r.tunOptions.Name)) { continue } err = nft.DelRule(rule) if err != nil { return err } } } return nil }