Initial commit (code only without large binaries)
This commit is contained in:
1
EdgeDNS/internal/firewalls/nftables/.gitignore
vendored
Normal file
1
EdgeDNS/internal/firewalls/nftables/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
build_remote.sh
|
||||
369
EdgeDNS/internal/firewalls/nftables/chain.go
Normal file
369
EdgeDNS/internal/firewalls/nftables/chain.go
Normal file
@@ -0,0 +1,369 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
nft "github.com/google/nftables"
|
||||
"github.com/google/nftables/expr"
|
||||
)
|
||||
|
||||
const MaxChainNameLength = 31
|
||||
|
||||
type RuleOptions struct {
|
||||
Exprs []expr.Any
|
||||
UserData []byte
|
||||
}
|
||||
|
||||
// Chain chain object in table
|
||||
type Chain struct {
|
||||
conn *Conn
|
||||
rawTable *nft.Table
|
||||
rawChain *nft.Chain
|
||||
}
|
||||
|
||||
func NewChain(conn *Conn, rawTable *nft.Table, rawChain *nft.Chain) *Chain {
|
||||
return &Chain{
|
||||
conn: conn,
|
||||
rawTable: rawTable,
|
||||
rawChain: rawChain,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Chain) Raw() *nft.Chain {
|
||||
return this.rawChain
|
||||
}
|
||||
|
||||
func (this *Chain) Name() string {
|
||||
return this.rawChain.Name
|
||||
}
|
||||
|
||||
func (this *Chain) AddRule(options *RuleOptions) (*Rule, error) {
|
||||
var rawRule = this.conn.Raw().AddRule(&nft.Rule{
|
||||
Table: this.rawTable,
|
||||
Chain: this.rawChain,
|
||||
Exprs: options.Exprs,
|
||||
UserData: options.UserData,
|
||||
})
|
||||
err := this.conn.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewRule(rawRule), nil
|
||||
}
|
||||
|
||||
func (this *Chain) AddAcceptIPv4Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictAccept,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddAcceptIPv6Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictAccept,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddDropIPv4Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictDrop,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddDropIPv6Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictDrop,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddRejectIPv4Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Reject{},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddRejectIPv6Rule(ip []byte, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ip,
|
||||
},
|
||||
&expr.Reject{},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddAcceptIPv4SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictAccept,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddAcceptIPv6SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictAccept,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddDropIPv4SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictDrop,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddDropIPv6SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictDrop,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddRejectIPv4SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 12,
|
||||
Len: 4,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Reject{},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddRejectIPv6SetRule(setName string, userData []byte) (*Rule, error) {
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 8,
|
||||
Len: 16,
|
||||
},
|
||||
&expr.Lookup{
|
||||
SourceRegister: 1,
|
||||
SetName: setName,
|
||||
},
|
||||
&expr.Reject{},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) AddAcceptInterfaceRule(interfaceName string, userData []byte) (*Rule, error) {
|
||||
if len(interfaceName) >= 16 {
|
||||
return nil, errors.New("invalid interface name '" + interfaceName + "'")
|
||||
}
|
||||
var ifname = make([]byte, 16)
|
||||
copy(ifname, interfaceName+"\x00")
|
||||
|
||||
return this.AddRule(&RuleOptions{
|
||||
Exprs: []expr.Any{
|
||||
&expr.Meta{
|
||||
Key: expr.MetaKeyIIFNAME,
|
||||
Register: 1,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: ifname,
|
||||
},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictAccept,
|
||||
},
|
||||
},
|
||||
UserData: userData,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *Chain) GetRuleWithUserData(userData []byte) (*Rule, error) {
|
||||
rawRules, err := this.conn.Raw().GetRule(this.rawTable, this.rawChain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, rawRule := range rawRules {
|
||||
if bytes.Compare(rawRule.UserData, userData) == 0 {
|
||||
return NewRule(rawRule), nil
|
||||
}
|
||||
}
|
||||
return nil, ErrRuleNotFound
|
||||
}
|
||||
|
||||
func (this *Chain) GetRules() ([]*Rule, error) {
|
||||
rawRules, err := this.conn.Raw().GetRule(this.rawTable, this.rawChain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = []*Rule{}
|
||||
for _, rawRule := range rawRules {
|
||||
result = append(result, NewRule(rawRule))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (this *Chain) DeleteRule(rule *Rule) error {
|
||||
err := this.conn.Raw().DelRule(rule.Raw())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return this.conn.Commit()
|
||||
}
|
||||
|
||||
func (this *Chain) Flush() error {
|
||||
this.conn.Raw().FlushChain(this.rawChain)
|
||||
return this.conn.Commit()
|
||||
}
|
||||
14
EdgeDNS/internal/firewalls/nftables/chain_policy.go
Normal file
14
EdgeDNS/internal/firewalls/nftables/chain_policy.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import nft "github.com/google/nftables"
|
||||
|
||||
type ChainPolicy = nft.ChainPolicy
|
||||
|
||||
// Possible ChainPolicy values.
|
||||
const (
|
||||
ChainPolicyDrop = nft.ChainPolicyDrop
|
||||
ChainPolicyAccept = nft.ChainPolicyAccept
|
||||
)
|
||||
129
EdgeDNS/internal/firewalls/nftables/chain_test.go
Normal file
129
EdgeDNS/internal/firewalls/nftables/chain_test.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeDNS/internal/firewalls/nftables"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getIPv4Chain(t *testing.T) *nftables.Chain {
|
||||
var conn = nftables.NewConn()
|
||||
table, err := conn.GetTable("test_ipv4", nftables.TableFamilyIPv4)
|
||||
if err != nil {
|
||||
if err == nftables.ErrTableNotFound {
|
||||
table, err = conn.AddIPv4Table("test_ipv4")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
chain, err := table.GetChain("test_chain")
|
||||
if err != nil {
|
||||
if err == nftables.ErrChainNotFound {
|
||||
chain, err = table.AddAcceptChain("test_chain")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func TestChain_AddAcceptIPRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
_, err := chain.AddAcceptIPv4Rule(net.ParseIP("192.168.2.40").To4(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_AddDropIPRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
_, err := chain.AddDropIPv4Rule(net.ParseIP("192.168.2.31").To4(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_AddAcceptSetRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
_, err := chain.AddAcceptIPv4SetRule("ipv4_black_set", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_AddDropSetRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
_, err := chain.AddDropIPv4SetRule("ipv4_black_set", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_AddRejectSetRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
_, err := chain.AddRejectIPv4SetRule("ipv4_black_set", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_GetRuleWithUserData(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
rule, err := chain.GetRuleWithUserData([]byte("test"))
|
||||
if err != nil {
|
||||
if err == nftables.ErrRuleNotFound {
|
||||
t.Log("rule not found")
|
||||
return
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
t.Log("rule:", rule)
|
||||
}
|
||||
|
||||
func TestChain_GetRules(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
rules, err := chain.GetRules()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, rule := range rules {
|
||||
t.Log("handle:", rule.Handle(), "set name:", rule.LookupSetName(),
|
||||
"verdict:", rule.VerDict(), "user data:", string(rule.UserData()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_DeleteRule(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
rule, err := chain.GetRuleWithUserData([]byte("test"))
|
||||
if err != nil {
|
||||
if err == nftables.ErrRuleNotFound {
|
||||
t.Log("rule not found")
|
||||
return
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = chain.DeleteRule(rule)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain_Flush(t *testing.T) {
|
||||
var chain = getIPv4Chain(t)
|
||||
err := chain.Flush()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
83
EdgeDNS/internal/firewalls/nftables/conn.go
Normal file
83
EdgeDNS/internal/firewalls/nftables/conn.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
"errors"
|
||||
nft "github.com/google/nftables"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
const MaxTableNameLength = 27
|
||||
|
||||
type Conn struct {
|
||||
rawConn *nft.Conn
|
||||
}
|
||||
|
||||
func NewConn() *Conn {
|
||||
return &Conn{
|
||||
rawConn: &nft.Conn{},
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Conn) Raw() *nft.Conn {
|
||||
return this.rawConn
|
||||
}
|
||||
|
||||
func (this *Conn) GetTable(name string, family TableFamily) (*Table, error) {
|
||||
rawTables, err := this.rawConn.ListTables()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, rawTable := range rawTables {
|
||||
if rawTable.Name == name && rawTable.Family == family {
|
||||
return NewTable(this, rawTable), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrTableNotFound
|
||||
}
|
||||
|
||||
func (this *Conn) AddTable(name string, family TableFamily) (*Table, error) {
|
||||
if len(name) > MaxTableNameLength {
|
||||
return nil, errors.New("table name too long (max " + types.String(MaxTableNameLength) + ")")
|
||||
}
|
||||
|
||||
var rawTable = this.rawConn.AddTable(&nft.Table{
|
||||
Family: family,
|
||||
Name: name,
|
||||
})
|
||||
|
||||
err := this.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTable(this, rawTable), nil
|
||||
}
|
||||
|
||||
func (this *Conn) AddIPv4Table(name string) (*Table, error) {
|
||||
return this.AddTable(name, TableFamilyIPv4)
|
||||
}
|
||||
|
||||
func (this *Conn) AddIPv6Table(name string) (*Table, error) {
|
||||
return this.AddTable(name, TableFamilyIPv6)
|
||||
}
|
||||
|
||||
func (this *Conn) DeleteTable(name string, family TableFamily) error {
|
||||
table, err := this.GetTable(name, family)
|
||||
if err != nil {
|
||||
if err == ErrTableNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
this.rawConn.DelTable(table.Raw())
|
||||
return this.Commit()
|
||||
}
|
||||
|
||||
func (this *Conn) Commit() error {
|
||||
return this.rawConn.Flush()
|
||||
}
|
||||
77
EdgeDNS/internal/firewalls/nftables/conn_test.go
Normal file
77
EdgeDNS/internal/firewalls/nftables/conn_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeDNS/internal/firewalls/nftables"
|
||||
executils "github.com/TeaOSLab/EdgeDNS/internal/utils/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConn_Test(t *testing.T) {
|
||||
_, err := executils.LookPath("nft")
|
||||
if err == nil {
|
||||
t.Log("ok")
|
||||
return
|
||||
}
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
func TestConn_GetTable_NotFound(t *testing.T) {
|
||||
var conn = nftables.NewConn()
|
||||
|
||||
table, err := conn.GetTable("a", nftables.TableFamilyIPv4)
|
||||
if err != nil {
|
||||
if err == nftables.ErrTableNotFound {
|
||||
t.Log("table not found")
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Log("table:", table)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConn_GetTable(t *testing.T) {
|
||||
var conn = nftables.NewConn()
|
||||
|
||||
table, err := conn.GetTable("myFilter", nftables.TableFamilyIPv4)
|
||||
if err != nil {
|
||||
if err == nftables.ErrTableNotFound {
|
||||
t.Log("table not found")
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Log("table:", table)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConn_AddTable(t *testing.T) {
|
||||
var conn = nftables.NewConn()
|
||||
|
||||
{
|
||||
table, err := conn.AddIPv4Table("test_ipv4")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(table.Name())
|
||||
}
|
||||
{
|
||||
table, err := conn.AddIPv6Table("test_ipv6")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(table.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConn_DeleteTable(t *testing.T) {
|
||||
var conn = nftables.NewConn()
|
||||
err := conn.DeleteTable("test_ipv4", nftables.TableFamilyIPv4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
7
EdgeDNS/internal/firewalls/nftables/element.go
Normal file
7
EdgeDNS/internal/firewalls/nftables/element.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
type Element struct {
|
||||
}
|
||||
18
EdgeDNS/internal/firewalls/nftables/errors.go
Normal file
18
EdgeDNS/internal/firewalls/nftables/errors.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrTableNotFound = errors.New("table not found")
|
||||
var ErrChainNotFound = errors.New("chain not found")
|
||||
var ErrSetNotFound = errors.New("set not found")
|
||||
var ErrRuleNotFound = errors.New("rule not found")
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return err == ErrTableNotFound || err == ErrChainNotFound || err == ErrSetNotFound || err == ErrRuleNotFound
|
||||
}
|
||||
19
EdgeDNS/internal/firewalls/nftables/family.go
Normal file
19
EdgeDNS/internal/firewalls/nftables/family.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
nft "github.com/google/nftables"
|
||||
)
|
||||
|
||||
type TableFamily = nft.TableFamily
|
||||
|
||||
const (
|
||||
TableFamilyINet TableFamily = nft.TableFamilyINet
|
||||
TableFamilyIPv4 TableFamily = nft.TableFamilyIPv4
|
||||
TableFamilyIPv6 TableFamily = nft.TableFamilyIPv6
|
||||
TableFamilyARP TableFamily = nft.TableFamilyARP
|
||||
TableFamilyNetdev TableFamily = nft.TableFamilyNetdev
|
||||
TableFamilyBridge TableFamily = nft.TableFamilyBridge
|
||||
)
|
||||
52
EdgeDNS/internal/firewalls/nftables/rule.go
Normal file
52
EdgeDNS/internal/firewalls/nftables/rule.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
nft "github.com/google/nftables"
|
||||
"github.com/google/nftables/expr"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
rawRule *nft.Rule
|
||||
}
|
||||
|
||||
func NewRule(rawRule *nft.Rule) *Rule {
|
||||
return &Rule{
|
||||
rawRule: rawRule,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Rule) Raw() *nft.Rule {
|
||||
return this.rawRule
|
||||
}
|
||||
|
||||
func (this *Rule) LookupSetName() string {
|
||||
for _, e := range this.rawRule.Exprs {
|
||||
exp, ok := e.(*expr.Lookup)
|
||||
if ok {
|
||||
return exp.SetName
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Rule) VerDict() expr.VerdictKind {
|
||||
for _, e := range this.rawRule.Exprs {
|
||||
exp, ok := e.(*expr.Verdict)
|
||||
if ok {
|
||||
return exp.Kind
|
||||
}
|
||||
}
|
||||
|
||||
return -100
|
||||
}
|
||||
|
||||
func (this *Rule) Handle() uint64 {
|
||||
return this.rawRule.Handle
|
||||
}
|
||||
|
||||
func (this *Rule) UserData() []byte {
|
||||
return this.rawRule.UserData
|
||||
}
|
||||
160
EdgeDNS/internal/firewalls/nftables/set.go
Normal file
160
EdgeDNS/internal/firewalls/nftables/set.go
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeDNS/internal/utils"
|
||||
nft "github.com/google/nftables"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const MaxSetNameLength = 15
|
||||
|
||||
type SetOptions struct {
|
||||
Id uint32
|
||||
HasTimeout bool
|
||||
Timeout time.Duration
|
||||
KeyType SetDataType
|
||||
DataType SetDataType
|
||||
Constant bool
|
||||
Interval bool
|
||||
Anonymous bool
|
||||
IsMap bool
|
||||
}
|
||||
|
||||
type ElementOptions struct {
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
type Set struct {
|
||||
conn *Conn
|
||||
rawSet *nft.Set
|
||||
batch *SetBatch
|
||||
}
|
||||
|
||||
func NewSet(conn *Conn, rawSet *nft.Set) *Set {
|
||||
return &Set{
|
||||
conn: conn,
|
||||
rawSet: rawSet,
|
||||
batch: &SetBatch{
|
||||
conn: conn,
|
||||
rawSet: rawSet,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Set) Raw() *nft.Set {
|
||||
return this.rawSet
|
||||
}
|
||||
|
||||
func (this *Set) Name() string {
|
||||
return this.rawSet.Name
|
||||
}
|
||||
|
||||
func (this *Set) AddElement(key []byte, options *ElementOptions) error {
|
||||
var rawElement = nft.SetElement{
|
||||
Key: key,
|
||||
}
|
||||
if options != nil {
|
||||
rawElement.Timeout = options.Timeout
|
||||
}
|
||||
err := this.conn.Raw().SetAddElements(this.rawSet, []nft.SetElement{
|
||||
rawElement,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = this.conn.Commit()
|
||||
if err != nil {
|
||||
// retry if exists
|
||||
if strings.Contains(err.Error(), "file exists") {
|
||||
deleteErr := this.conn.Raw().SetDeleteElements(this.rawSet, []nft.SetElement{
|
||||
{
|
||||
Key: key,
|
||||
},
|
||||
})
|
||||
if deleteErr == nil {
|
||||
err = this.conn.Raw().SetAddElements(this.rawSet, []nft.SetElement{
|
||||
rawElement,
|
||||
})
|
||||
if err == nil {
|
||||
err = this.conn.Commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (this *Set) AddIPElement(ip string, options *ElementOptions) error {
|
||||
var ipObj = net.ParseIP(ip)
|
||||
if ipObj == nil {
|
||||
return errors.New("invalid ip '" + ip + "'")
|
||||
}
|
||||
|
||||
if utils.IsIPv4(ip) {
|
||||
return this.AddElement(ipObj.To4(), options)
|
||||
} else {
|
||||
return this.AddElement(ipObj.To16(), options)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Set) DeleteElement(key []byte) error {
|
||||
err := this.conn.Raw().SetDeleteElements(this.rawSet, []nft.SetElement{
|
||||
{
|
||||
Key: key,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = this.conn.Commit()
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such file or directory") {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (this *Set) DeleteIPElement(ip string) error {
|
||||
var ipObj = net.ParseIP(ip)
|
||||
if ipObj == nil {
|
||||
return errors.New("invalid ip '" + ip + "'")
|
||||
}
|
||||
|
||||
if utils.IsIPv4(ip) {
|
||||
return this.DeleteElement(ipObj.To4())
|
||||
} else {
|
||||
return this.DeleteElement(ipObj.To16())
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Set) Batch() *SetBatch {
|
||||
return this.batch
|
||||
}
|
||||
|
||||
func (this *Set) GetIPElements() ([]string, error) {
|
||||
elements, err := this.conn.Raw().GetSetElements(this.rawSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result = []string{}
|
||||
for _, element := range elements {
|
||||
result = append(result, net.IP(element.Key).String())
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// not work current time
|
||||
/**func (this *Set) Flush() error {
|
||||
this.conn.Raw().FlushSet(this.rawSet)
|
||||
return this.conn.Commit()
|
||||
}**/
|
||||
37
EdgeDNS/internal/firewalls/nftables/set_batch.go
Normal file
37
EdgeDNS/internal/firewalls/nftables/set_batch.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
nft "github.com/google/nftables"
|
||||
)
|
||||
|
||||
type SetBatch struct {
|
||||
conn *Conn
|
||||
rawSet *nft.Set
|
||||
}
|
||||
|
||||
func (this *SetBatch) AddElement(key []byte, options *ElementOptions) error {
|
||||
var rawElement = nft.SetElement{
|
||||
Key: key,
|
||||
}
|
||||
if options != nil {
|
||||
rawElement.Timeout = options.Timeout
|
||||
}
|
||||
return this.conn.Raw().SetAddElements(this.rawSet, []nft.SetElement{
|
||||
rawElement,
|
||||
})
|
||||
}
|
||||
|
||||
func (this *SetBatch) DeleteElement(key []byte) error {
|
||||
return this.conn.Raw().SetDeleteElements(this.rawSet, []nft.SetElement{
|
||||
{
|
||||
Key: key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (this *SetBatch) Commit() error {
|
||||
return this.conn.Commit()
|
||||
}
|
||||
58
EdgeDNS/internal/firewalls/nftables/set_data_type.go
Normal file
58
EdgeDNS/internal/firewalls/nftables/set_data_type.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import nft "github.com/google/nftables"
|
||||
|
||||
type SetDataType = nft.SetDatatype
|
||||
|
||||
var (
|
||||
TypeInvalid = nft.TypeInvalid
|
||||
TypeVerdict = nft.TypeVerdict
|
||||
TypeNFProto = nft.TypeNFProto
|
||||
TypeBitmask = nft.TypeBitmask
|
||||
TypeInteger = nft.TypeInteger
|
||||
TypeString = nft.TypeString
|
||||
TypeLLAddr = nft.TypeLLAddr
|
||||
TypeIPAddr = nft.TypeIPAddr
|
||||
TypeIP6Addr = nft.TypeIP6Addr
|
||||
TypeEtherAddr = nft.TypeEtherAddr
|
||||
TypeEtherType = nft.TypeEtherType
|
||||
TypeARPOp = nft.TypeARPOp
|
||||
TypeInetProto = nft.TypeInetProto
|
||||
TypeInetService = nft.TypeInetService
|
||||
TypeICMPType = nft.TypeICMPType
|
||||
TypeTCPFlag = nft.TypeTCPFlag
|
||||
TypeDCCPPktType = nft.TypeDCCPPktType
|
||||
TypeMHType = nft.TypeMHType
|
||||
TypeTime = nft.TypeTime
|
||||
TypeMark = nft.TypeMark
|
||||
TypeIFIndex = nft.TypeIFIndex
|
||||
TypeARPHRD = nft.TypeARPHRD
|
||||
TypeRealm = nft.TypeRealm
|
||||
TypeClassID = nft.TypeClassID
|
||||
TypeUID = nft.TypeUID
|
||||
TypeGID = nft.TypeGID
|
||||
TypeCTState = nft.TypeCTState
|
||||
TypeCTDir = nft.TypeCTDir
|
||||
TypeCTStatus = nft.TypeCTStatus
|
||||
TypeICMP6Type = nft.TypeICMP6Type
|
||||
TypeCTLabel = nft.TypeCTLabel
|
||||
TypePktType = nft.TypePktType
|
||||
TypeICMPCode = nft.TypeICMPCode
|
||||
TypeICMPV6Code = nft.TypeICMPV6Code
|
||||
TypeICMPXCode = nft.TypeICMPXCode
|
||||
TypeDevGroup = nft.TypeDevGroup
|
||||
TypeDSCP = nft.TypeDSCP
|
||||
TypeECN = nft.TypeECN
|
||||
TypeFIBAddr = nft.TypeFIBAddr
|
||||
TypeBoolean = nft.TypeBoolean
|
||||
TypeCTEventBit = nft.TypeCTEventBit
|
||||
TypeIFName = nft.TypeIFName
|
||||
TypeIGMPType = nft.TypeIGMPType
|
||||
TypeTimeDate = nft.TypeTimeDate
|
||||
TypeTimeHour = nft.TypeTimeHour
|
||||
TypeTimeDay = nft.TypeTimeDay
|
||||
TypeCGroupV2 = nft.TypeCGroupV2
|
||||
)
|
||||
111
EdgeDNS/internal/firewalls/nftables/set_test.go
Normal file
111
EdgeDNS/internal/firewalls/nftables/set_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TeaOSLab/EdgeDNS/internal/firewalls/nftables"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"github.com/mdlayher/netlink"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getIPv4Set(t *testing.T) *nftables.Set {
|
||||
var table = getIPv4Table(t)
|
||||
set, err := table.GetSet("test_ipv4_set")
|
||||
if err != nil {
|
||||
if err == nftables.ErrSetNotFound {
|
||||
set, err = table.AddSet("test_ipv4_set", &nftables.SetOptions{
|
||||
KeyType: nftables.TypeIPAddr,
|
||||
HasTimeout: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func TestSet_AddElement(t *testing.T) {
|
||||
var set = getIPv4Set(t)
|
||||
err := set.AddElement(net.ParseIP("192.168.2.31").To4(), &nftables.ElementOptions{Timeout: 86400 * time.Second})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestSet_DeleteElement(t *testing.T) {
|
||||
var set = getIPv4Set(t)
|
||||
err := set.DeleteElement(net.ParseIP("192.168.2.31").To4())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestSet_Batch(t *testing.T) {
|
||||
var batch = getIPv4Set(t).Batch()
|
||||
|
||||
for _, ip := range []string{"192.168.2.30", "192.168.2.31", "192.168.2.32", "192.168.2.33", "192.168.2.34"} {
|
||||
var ipData = net.ParseIP(ip).To4()
|
||||
//err := batch.DeleteElement(ipData)
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
err := batch.AddElement(ipData, &nftables.ElementOptions{Timeout: 10 * time.Second})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
err := batch.Commit()
|
||||
if err != nil {
|
||||
t.Logf("%#v", errors.Unwrap(err).(*netlink.OpError))
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestSet_Add_Many(t *testing.T) {
|
||||
var set = getIPv4Set(t)
|
||||
|
||||
for i := 0; i < 255; i++ {
|
||||
t.Log(i)
|
||||
for j := 0; j < 255; j++ {
|
||||
var ip = "192.167." + types.String(i) + "." + types.String(j)
|
||||
var ipData = net.ParseIP(ip).To4()
|
||||
err := set.Batch().AddElement(ipData, &nftables.ElementOptions{Timeout: 3600 * time.Second})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if j%10 == 0 {
|
||||
err = set.Batch().Commit()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
err := set.Batch().Commit()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
/**func TestSet_Flush(t *testing.T) {
|
||||
var set = getIPv4Set(t)
|
||||
err := set.Flush()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}**/
|
||||
156
EdgeDNS/internal/firewalls/nftables/table.go
Normal file
156
EdgeDNS/internal/firewalls/nftables/table.go
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables
|
||||
|
||||
import (
|
||||
"errors"
|
||||
nft "github.com/google/nftables"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Table struct {
|
||||
conn *Conn
|
||||
rawTable *nft.Table
|
||||
}
|
||||
|
||||
func NewTable(conn *Conn, rawTable *nft.Table) *Table {
|
||||
return &Table{
|
||||
conn: conn,
|
||||
rawTable: rawTable,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Table) Raw() *nft.Table {
|
||||
return this.rawTable
|
||||
}
|
||||
|
||||
func (this *Table) Name() string {
|
||||
return this.rawTable.Name
|
||||
}
|
||||
|
||||
func (this *Table) Family() TableFamily {
|
||||
return this.rawTable.Family
|
||||
}
|
||||
|
||||
func (this *Table) GetChain(name string) (*Chain, error) {
|
||||
rawChains, err := this.conn.Raw().ListChains()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, rawChain := range rawChains {
|
||||
// must compare table name
|
||||
if rawChain.Name == name && rawChain.Table.Name == this.rawTable.Name {
|
||||
return NewChain(this.conn, this.rawTable, rawChain), nil
|
||||
}
|
||||
}
|
||||
return nil, ErrChainNotFound
|
||||
}
|
||||
|
||||
func (this *Table) AddChain(name string, chainPolicy *ChainPolicy) (*Chain, error) {
|
||||
if len(name) > MaxChainNameLength {
|
||||
return nil, errors.New("chain name too long (max " + types.String(MaxChainNameLength) + ")")
|
||||
}
|
||||
|
||||
var rawChain = this.conn.Raw().AddChain(&nft.Chain{
|
||||
Name: name,
|
||||
Table: this.rawTable,
|
||||
Hooknum: nft.ChainHookInput,
|
||||
Priority: nft.ChainPriorityFilter,
|
||||
Type: nft.ChainTypeFilter,
|
||||
Policy: chainPolicy,
|
||||
})
|
||||
|
||||
err := this.conn.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewChain(this.conn, this.rawTable, rawChain), nil
|
||||
}
|
||||
|
||||
func (this *Table) AddAcceptChain(name string) (*Chain, error) {
|
||||
var policy = ChainPolicyAccept
|
||||
return this.AddChain(name, &policy)
|
||||
}
|
||||
|
||||
func (this *Table) AddDropChain(name string) (*Chain, error) {
|
||||
var policy = ChainPolicyDrop
|
||||
return this.AddChain(name, &policy)
|
||||
}
|
||||
|
||||
func (this *Table) DeleteChain(name string) error {
|
||||
chain, err := this.GetChain(name)
|
||||
if err != nil {
|
||||
if err == ErrChainNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
this.conn.Raw().DelChain(chain.Raw())
|
||||
return this.conn.Commit()
|
||||
}
|
||||
|
||||
func (this *Table) GetSet(name string) (*Set, error) {
|
||||
rawSet, err := this.conn.Raw().GetSetByName(this.rawTable, name)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no such file or directory") {
|
||||
return nil, ErrSetNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSet(this.conn, rawSet), nil
|
||||
}
|
||||
|
||||
func (this *Table) AddSet(name string, options *SetOptions) (*Set, error) {
|
||||
if len(name) > MaxSetNameLength {
|
||||
return nil, errors.New("set name too long (max " + types.String(MaxSetNameLength) + ")")
|
||||
}
|
||||
|
||||
if options == nil {
|
||||
options = &SetOptions{}
|
||||
}
|
||||
var rawSet = &nft.Set{
|
||||
Table: this.rawTable,
|
||||
ID: options.Id,
|
||||
Name: name,
|
||||
Anonymous: options.Anonymous,
|
||||
Constant: options.Constant,
|
||||
Interval: options.Interval,
|
||||
IsMap: options.IsMap,
|
||||
HasTimeout: options.HasTimeout,
|
||||
Timeout: options.Timeout,
|
||||
KeyType: options.KeyType,
|
||||
DataType: options.DataType,
|
||||
}
|
||||
err := this.conn.Raw().AddSet(rawSet, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = this.conn.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSet(this.conn, rawSet), nil
|
||||
}
|
||||
|
||||
func (this *Table) DeleteSet(name string) error {
|
||||
set, err := this.GetSet(name)
|
||||
if err != nil {
|
||||
if err == ErrSetNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
this.conn.Raw().DelSet(set.Raw())
|
||||
return this.conn.Commit()
|
||||
}
|
||||
|
||||
func (this *Table) Flush() error {
|
||||
this.conn.Raw().FlushTable(this.rawTable)
|
||||
return this.conn.Commit()
|
||||
}
|
||||
139
EdgeDNS/internal/firewalls/nftables/table_test.go
Normal file
139
EdgeDNS/internal/firewalls/nftables/table_test.go
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
//go:build linux
|
||||
|
||||
package nftables_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeDNS/internal/firewalls/nftables"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getIPv4Table(t *testing.T) *nftables.Table {
|
||||
var conn = nftables.NewConn()
|
||||
table, err := conn.GetTable("test_ipv4", nftables.TableFamilyIPv4)
|
||||
if err != nil {
|
||||
if err == nftables.ErrTableNotFound {
|
||||
table, err = conn.AddIPv4Table("test_ipv4")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func TestTable_AddChain(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
|
||||
{
|
||||
chain, err := table.AddChain("test_default_chain", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("created:", chain.Name())
|
||||
}
|
||||
|
||||
{
|
||||
chain, err := table.AddAcceptChain("test_accept_chain")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("created:", chain.Name())
|
||||
}
|
||||
|
||||
// Do not test drop chain before adding accept rule, you will drop yourself!!!!!!!
|
||||
/**{
|
||||
chain, err := table.AddDropChain("test_drop_chain")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("created:", chain.Name())
|
||||
}**/
|
||||
}
|
||||
|
||||
func TestTable_GetChain(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
for _, chainName := range []string{"not_found_chain", "test_default_chain"} {
|
||||
chain, err := table.GetChain(chainName)
|
||||
if err != nil {
|
||||
if err == nftables.ErrChainNotFound {
|
||||
t.Log(chainName, ":", "not found")
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Log(chainName, ":", chain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTable_DeleteChain(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
err := table.DeleteChain("test_default_chain")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestTable_AddSet(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
{
|
||||
set, err := table.AddSet("ipv4_black_set", &nftables.SetOptions{
|
||||
HasTimeout: false,
|
||||
KeyType: nftables.TypeIPAddr,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(set.Name())
|
||||
}
|
||||
|
||||
{
|
||||
set, err := table.AddSet("ipv6_black_set", &nftables.SetOptions{
|
||||
HasTimeout: true,
|
||||
//Timeout: 3600 * time.Second,
|
||||
KeyType: nftables.TypeIP6Addr,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(set.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTable_GetSet(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
for _, setName := range []string{"not_found_set", "ipv4_black_set"} {
|
||||
set, err := table.GetSet(setName)
|
||||
if err != nil {
|
||||
if err == nftables.ErrSetNotFound {
|
||||
t.Log(setName, ": not found")
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
t.Log(setName, ":", set)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTable_DeleteSet(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
err := table.DeleteSet("ipv4_black_set")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestTable_Flush(t *testing.T) {
|
||||
var table = getIPv4Table(t)
|
||||
err := table.Flush()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
Reference in New Issue
Block a user