Improve nftables rules for openwrt
This commit is contained in:
parent
5e343c4b66
commit
8763c24e49
1 changed files with 32 additions and 83 deletions
|
|
@ -3,101 +3,50 @@
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/nftables"
|
"os"
|
||||||
"github.com/sagernet/nftables/expr"
|
"os/exec"
|
||||||
|
|
||||||
"golang.org/x/exp/slices"
|
"github.com/sagernet/nftables"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/shell"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *autoRedirect) configureOpenWRTFirewall4(nft *nftables.Conn, cleanup bool) error {
|
func (r *autoRedirect) configureOpenWRTFirewall4(nft *nftables.Conn, cleanup bool) error {
|
||||||
tableFW4, err := nft.ListTableOfFamily("fw4", nftables.TableFamilyINet)
|
_, err := nft.ListTableOfFamily("fw4", nftables.TableFamilyINet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
fw4Path, err := exec.LookPath("fw4")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rulePath := "/etc/nftables.d/0-" + r.tableName + "-auto-redirect.nft"
|
||||||
if !cleanup {
|
if !cleanup {
|
||||||
ruleIif := &nftables.Rule{
|
err = os.WriteFile(rulePath, []byte(`chain input {
|
||||||
Table: tableFW4,
|
type filter hook input priority filter; policy accept;
|
||||||
Exprs: []expr.Any{
|
iifname "`+r.tunOptions.Name+`" counter accept comment "!`+r.tableName+`: Accept traffic from tun"
|
||||||
&expr.Meta{
|
oifname "`+r.tunOptions.Name+`" counter accept comment "!`+r.tableName+`: Accept traffic from tun"
|
||||||
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{
|
chain forward {
|
||||||
Table: tableFW4,
|
type filter hook forward priority filter; policy accept;
|
||||||
Exprs: []expr.Any{
|
iifname "`+r.tunOptions.Name+`" counter accept comment "!`+r.tableName+`: Accept traffic from tun"
|
||||||
&expr.Meta{
|
oifname "`+r.tunOptions.Name+`" counter accept comment "!`+r.tableName+`: Accept traffic from tun"
|
||||||
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{
|
`), 0o644)
|
||||||
Name: "forward",
|
if err != nil {
|
||||||
|
return E.Cause(err, "write fw4 rules")
|
||||||
}
|
}
|
||||||
ruleIif.Chain = chainForward
|
} else if _, err = os.Stat(rulePath); os.IsNotExist(err) {
|
||||||
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
|
return nil
|
||||||
}
|
} else {
|
||||||
for _, chainName := range []string{"input", "forward"} {
|
err = os.Remove(rulePath)
|
||||||
var rules []*nftables.Rule
|
|
||||||
rules, err = nft.GetRules(tableFW4, &nftables.Chain{
|
|
||||||
Name: chainName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return E.Cause(err, "clean fw4 rules")
|
||||||
}
|
}
|
||||||
for _, rule := range rules {
|
|
||||||
if len(rule.Exprs) != 4 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
exprMeta, isMeta := rule.Exprs[0].(*expr.Meta)
|
_, err = shell.Exec(fw4Path, "reload").Read()
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return E.Cause(err, "reload fw4 rules")
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue