Compare commits
5 Commits
be07ad0eab
...
d68771344c
Author | SHA1 | Date |
---|---|---|
|
d68771344c | |
|
ba5b671e14 | |
|
1148f1a84f | |
|
3efc75f481 | |
|
1e48c1007e |
44
conn.go
44
conn.go
|
@ -233,6 +233,19 @@ func (cc *Conn) CloseLasting() error {
|
||||||
|
|
||||||
// Flush sends all buffered commands in a single batch to nftables.
|
// Flush sends all buffered commands in a single batch to nftables.
|
||||||
func (cc *Conn) Flush() error {
|
func (cc *Conn) Flush() error {
|
||||||
|
return cc.flush(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlushWithGenID sends all buffered commands in a single batch to nftables
|
||||||
|
// along with the provided gen ID. If the ruleset has changed since the gen ID
|
||||||
|
// was retrieved, an ERESTART error will be returned.
|
||||||
|
func (cc *Conn) FlushWithGenID(genID uint32) error {
|
||||||
|
return cc.flush(genID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush sends all buffered commands in a single batch to nftables. If genID is
|
||||||
|
// non-zero, it will be included in the batch messages.
|
||||||
|
func (cc *Conn) flush(genID uint32) error {
|
||||||
cc.mu.Lock()
|
cc.mu.Lock()
|
||||||
defer func() {
|
defer func() {
|
||||||
cc.messages = nil
|
cc.messages = nil
|
||||||
|
@ -259,7 +272,12 @@ func (cc *Conn) Flush() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
messages, err := conn.SendMessages(batch(cc.messages))
|
batch, err := batch(cc.messages, genID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
messages, err := conn.SendMessages(batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("SendMessages: %w", err)
|
return fmt.Errorf("SendMessages: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -388,14 +406,30 @@ func (cc *Conn) marshalExpr(fam byte, e expr.Any) []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func batch(messages []netlinkMessage) []netlink.Message {
|
// batch wraps the given messages in a batch begin and end message, and returns
|
||||||
|
// the resulting slice of netlink messages. If the genID is non-zero, it will be
|
||||||
|
// included in both batch messages.
|
||||||
|
func batch(messages []netlinkMessage, genID uint32) ([]netlink.Message, error) {
|
||||||
batch := make([]netlink.Message, len(messages)+2)
|
batch := make([]netlink.Message, len(messages)+2)
|
||||||
|
|
||||||
|
data := extraHeader(0, unix.NFNL_SUBSYS_NFTABLES)
|
||||||
|
|
||||||
|
if genID > 0 {
|
||||||
|
attr, err := netlink.MarshalAttributes([]netlink.Attribute{
|
||||||
|
{Type: unix.NFNL_BATCH_GENID, Data: binaryutil.BigEndian.PutUint32(genID)},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data = append(data, attr...)
|
||||||
|
}
|
||||||
|
|
||||||
batch[0] = netlink.Message{
|
batch[0] = netlink.Message{
|
||||||
Header: netlink.Header{
|
Header: netlink.Header{
|
||||||
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_BEGIN),
|
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_BEGIN),
|
||||||
Flags: netlink.Request,
|
Flags: netlink.Request,
|
||||||
},
|
},
|
||||||
Data: extraHeader(0, unix.NFNL_SUBSYS_NFTABLES),
|
Data: data,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, msg := range messages {
|
for i, msg := range messages {
|
||||||
|
@ -410,10 +444,10 @@ func batch(messages []netlinkMessage) []netlink.Message {
|
||||||
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_END),
|
Type: netlink.HeaderType(unix.NFNL_MSG_BATCH_END),
|
||||||
Flags: netlink.Request,
|
Flags: netlink.Request,
|
||||||
},
|
},
|
||||||
Data: extraHeader(0, unix.NFNL_SUBSYS_NFTABLES),
|
Data: data,
|
||||||
}
|
}
|
||||||
|
|
||||||
return batch
|
return batch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocateTransactionID allocates an identifier which is only valid in the
|
// allocateTransactionID allocates an identifier which is only valid in the
|
||||||
|
|
50
gen.go
50
gen.go
|
@ -8,15 +8,18 @@ import (
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenMsg struct {
|
type Gen struct {
|
||||||
ID uint32
|
ID uint32
|
||||||
ProcPID uint32
|
ProcPID uint32
|
||||||
ProcComm string // [16]byte - max 16bytes - kernel TASK_COMM_LEN
|
ProcComm string // [16]byte - max 16bytes - kernel TASK_COMM_LEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: GenMsg is an inconsistent old name for Gen. Prefer using Gen.
|
||||||
|
type GenMsg = Gen
|
||||||
|
|
||||||
const genHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWGEN)
|
const genHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWGEN)
|
||||||
|
|
||||||
func genFromMsg(msg netlink.Message) (*GenMsg, error) {
|
func genFromMsg(msg netlink.Message) (*Gen, error) {
|
||||||
if got, want := msg.Header.Type, genHeaderType; got != want {
|
if got, want := msg.Header.Type, genHeaderType; got != want {
|
||||||
return nil, fmt.Errorf("unexpected header type: got %v, want %v", got, want)
|
return nil, fmt.Errorf("unexpected header type: got %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +29,7 @@ func genFromMsg(msg netlink.Message) (*GenMsg, error) {
|
||||||
}
|
}
|
||||||
ad.ByteOrder = binary.BigEndian
|
ad.ByteOrder = binary.BigEndian
|
||||||
|
|
||||||
msgOut := &GenMsg{}
|
msgOut := &Gen{}
|
||||||
for ad.Next() {
|
for ad.Next() {
|
||||||
switch ad.Type() {
|
switch ad.Type() {
|
||||||
case unix.NFTA_GEN_ID:
|
case unix.NFTA_GEN_ID:
|
||||||
|
@ -36,7 +39,7 @@ func genFromMsg(msg netlink.Message) (*GenMsg, error) {
|
||||||
case unix.NFTA_GEN_PROC_NAME:
|
case unix.NFTA_GEN_PROC_NAME:
|
||||||
msgOut.ProcComm = ad.String()
|
msgOut.ProcComm = ad.String()
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unknown attribute: %d %v\n", ad.Type(), ad.Bytes())
|
return nil, fmt.Errorf("unknown attribute: %d, %v", ad.Type(), ad.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := ad.Err(); err != nil {
|
if err := ad.Err(); err != nil {
|
||||||
|
@ -44,3 +47,42 @@ func genFromMsg(msg netlink.Message) (*GenMsg, error) {
|
||||||
}
|
}
|
||||||
return msgOut, nil
|
return msgOut, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGen retrieves the current nftables generation ID together with the name
|
||||||
|
// and ID of the process that last modified the ruleset.
|
||||||
|
// https://docs.kernel.org/networking/netlink_spec/nftables.html#getgen
|
||||||
|
func (cc *Conn) GetGen() (*Gen, error) {
|
||||||
|
conn, closer, err := cc.netlinkConn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() { _ = closer() }()
|
||||||
|
|
||||||
|
data, err := netlink.MarshalAttributes([]netlink.Attribute{
|
||||||
|
{Type: unix.NFTA_GEN_ID},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := netlink.Message{
|
||||||
|
Header: netlink.Header{
|
||||||
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETGEN),
|
||||||
|
Flags: netlink.Request | netlink.Acknowledge,
|
||||||
|
},
|
||||||
|
Data: append(extraHeader(0, 0), data...),
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
|
||||||
|
return nil, fmt.Errorf("SendMessages: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := receiveAckAware(conn, message.Header.Flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("receiveAckAware: %v", err)
|
||||||
|
}
|
||||||
|
if len(reply) == 0 {
|
||||||
|
return nil, fmt.Errorf("receiveAckAware: no reply")
|
||||||
|
}
|
||||||
|
return genFromMsg(reply[0])
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,299 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/nftables"
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
args := os.Args[1:]
|
||||||
|
if len(args) != 1 {
|
||||||
|
log.Fatalf("need to specify the file to read the \"nft list ruleset\" dump")
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := args[0]
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
// Create a new network namespace
|
||||||
|
ns, err := netns.New()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("netns.New() failed: %v", err)
|
||||||
|
}
|
||||||
|
n, err := nftables.New(nftables.WithNetNSFd(int(ns)))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("nftables.New() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptOutput, err := applyNFTRuleset(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to apply nftables script: %v\noutput:%s", err, scriptOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
// Helper function to print to the file
|
||||||
|
pf := func(format string, a ...interface{}) {
|
||||||
|
_, err := fmt.Fprintf(&buf, format, a...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pf("// Code generated by nft2go. DO NOT EDIT.\n")
|
||||||
|
pf("package main\n\n")
|
||||||
|
pf("import (\n")
|
||||||
|
pf("\t\"fmt\"\n")
|
||||||
|
pf("\t\"log\"\n")
|
||||||
|
pf("\t\"github.com/google/nftables\"\n")
|
||||||
|
pf("\t\"github.com/google/nftables/expr\"\n")
|
||||||
|
pf(")\n\n")
|
||||||
|
pf("func main() {\n")
|
||||||
|
pf("\tn, err:= nftables.New()\n")
|
||||||
|
pf("\tif err!= nil {\n")
|
||||||
|
pf("\t\tlog.Fatal(err)\n")
|
||||||
|
pf("\t}\n\n")
|
||||||
|
pf("\n")
|
||||||
|
pf("\tvar expressions []expr.Any\n")
|
||||||
|
pf("\tvar chain *nftables.Chain\n")
|
||||||
|
pf("\tvar table *nftables.Table\n")
|
||||||
|
|
||||||
|
tables, err := n.ListTables()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ListTables failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
chains, err := n.ListChains()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, table := range tables {
|
||||||
|
log.Printf("processing table: %s", table.Name)
|
||||||
|
|
||||||
|
pf("\ttable = n.AddTable(&nftables.Table{Family: %s,Name: \"%s\"})\n", TableFamilyString(table.Family), table.Name)
|
||||||
|
for _, chain := range chains {
|
||||||
|
if chain.Table.Name != table.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sets, err := n.GetSets(table)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, set := range sets {
|
||||||
|
// TODO datatype and the other options
|
||||||
|
pf("\tn.AddSet(&nftables.Set{\n")
|
||||||
|
pf("\t\tTable: table,\n")
|
||||||
|
pf("\t\tName: \"%s\",\n", set.Name)
|
||||||
|
pf("\t}, nil)\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
pf("\tchain = n.AddChain(&nftables.Chain{Name: \"%s\", Table: table, Type: %s, Hooknum: %s, Priority: %s})\n",
|
||||||
|
chain.Name, ChainTypeString(chain.Type), ChainHookRef(chain.Hooknum), ChainPrioRef(chain.Priority))
|
||||||
|
|
||||||
|
rules, err := n.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rule := range rules {
|
||||||
|
pf("\texpressions = []expr.Any{\n")
|
||||||
|
for _, exp := range rule.Exprs {
|
||||||
|
pf("\t\t%#v,\n", exp)
|
||||||
|
}
|
||||||
|
pf("\t\t}\n")
|
||||||
|
pf("\tn.AddRule(&nftables.Rule{\n")
|
||||||
|
pf("\t\tTable: table,\n")
|
||||||
|
pf("\t\tChain: chain,\n")
|
||||||
|
pf("\t\tExprs: expressions,\n")
|
||||||
|
pf("\t})\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pf("\n\tif err:= n.Flush(); err!= nil {\n")
|
||||||
|
pf("\t\tlog.Fatal(err)\n")
|
||||||
|
pf("\t}\n\n")
|
||||||
|
pf("\tfmt.Println(\"nft ruleset applied.\")\n")
|
||||||
|
pf("}\n")
|
||||||
|
|
||||||
|
// Program nftables using your Go code
|
||||||
|
if err := flushNFTRuleset(); err != nil {
|
||||||
|
log.Fatalf("Failed to flush nftables ruleset: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the output file
|
||||||
|
// Create a temporary directory
|
||||||
|
tempDir, err := ioutil.TempDir("", "nftables_gen")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir) // Clean up the temporary directory
|
||||||
|
|
||||||
|
// Create the temporary Go file
|
||||||
|
tempGoFile := filepath.Join(tempDir, "nftables_recreate.go")
|
||||||
|
f, err := os.Create(tempGoFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
mw := io.MultiWriter(f, os.Stdout)
|
||||||
|
buf.WriteTo(mw)
|
||||||
|
|
||||||
|
// Format the generated code
|
||||||
|
log.Printf("formating file: %s", tempGoFile)
|
||||||
|
cmd := exec.Command("gofmt", "-w", "-s", tempGoFile)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("gofmt error: %v\nOutput: %s", err, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the generated code
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
log.Printf("executing file: %s", tempGoFile)
|
||||||
|
cmd = exec.CommandContext(ctx, "go", "run", tempGoFile)
|
||||||
|
output, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Execution error: %v\nOutput: %s", err, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve nftables state using nft
|
||||||
|
log.Printf("obtain current ruleset: %s", tempGoFile)
|
||||||
|
actualOutput, err := listNFTRuleset()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to list nftables ruleset: %v\noutput:%s", err, actualOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to list nftables ruleset: %v\noutput:%s", err, actualOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !compareMultilineStringsIgnoreIndentation(string(expectedOutput), actualOutput) {
|
||||||
|
log.Printf("Expected output:\n%s", string(expectedOutput))
|
||||||
|
log.Printf("Actual output:\n%s", actualOutput)
|
||||||
|
|
||||||
|
log.Fatalf("nftables ruleset mismatch:\n%s", cmp.Diff(string(expectedOutput), actualOutput))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := flushNFTRuleset(); err != nil {
|
||||||
|
log.Fatalf("Failed to flush nftables ruleset: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyNFTRuleset(scriptPath string) (string, error) {
|
||||||
|
cmd := exec.Command("nft", "--debug=netlink", "-f", scriptPath)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return string(out), err
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listNFTRuleset() (string, error) {
|
||||||
|
cmd := exec.Command("nft", "list", "ruleset")
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return string(out), err
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flushNFTRuleset() error {
|
||||||
|
cmd := exec.Command("nft", "flush", "ruleset")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainHookRef(hookNum *nftables.ChainHook) string {
|
||||||
|
i := uint32(0)
|
||||||
|
if hookNum != nil {
|
||||||
|
i = uint32(*hookNum)
|
||||||
|
}
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
return "nftables.ChainHookPrerouting"
|
||||||
|
case 1:
|
||||||
|
return "nftables.ChainHookInput"
|
||||||
|
case 2:
|
||||||
|
return "nftables.ChainHookForward"
|
||||||
|
case 3:
|
||||||
|
return "nftables.ChainHookOutput"
|
||||||
|
case 4:
|
||||||
|
return "nftables.ChainHookPostrouting"
|
||||||
|
case 5:
|
||||||
|
return "nftables.ChainHookIngress"
|
||||||
|
case 6:
|
||||||
|
return "nftables.ChainHookEgress"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainPrioRef(priority *nftables.ChainPriority) string {
|
||||||
|
i := int32(0)
|
||||||
|
if priority != nil {
|
||||||
|
i = int32(*priority)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("nftables.ChainPriorityRef(%d)", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainTypeString(chaintype nftables.ChainType) string {
|
||||||
|
switch chaintype {
|
||||||
|
case nftables.ChainTypeFilter:
|
||||||
|
return "nftables.ChainTypeFilter"
|
||||||
|
case nftables.ChainTypeRoute:
|
||||||
|
return "nftables.ChainTypeRoute"
|
||||||
|
case nftables.ChainTypeNAT:
|
||||||
|
return "nftables.ChainTypeNAT"
|
||||||
|
default:
|
||||||
|
return "nftables.ChainTypeFilter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TableFamilyString(family nftables.TableFamily) string {
|
||||||
|
switch family {
|
||||||
|
case nftables.TableFamilyUnspecified:
|
||||||
|
return "nftables.TableFamilyUnspecified"
|
||||||
|
case nftables.TableFamilyINet:
|
||||||
|
return "nftables.TableFamilyINet"
|
||||||
|
case nftables.TableFamilyIPv4:
|
||||||
|
return "nftables.TableFamilyIPv4"
|
||||||
|
case nftables.TableFamilyIPv6:
|
||||||
|
return "nftables.TableFamilyIPv6"
|
||||||
|
case nftables.TableFamilyARP:
|
||||||
|
return "nftables.TableFamilyARP"
|
||||||
|
case nftables.TableFamilyNetdev:
|
||||||
|
return "nftables.TableFamilyNetdev"
|
||||||
|
case nftables.TableFamilyBridge:
|
||||||
|
return "nftables.TableFamilyBridge"
|
||||||
|
default:
|
||||||
|
return "nftables.TableFamilyIPv4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareMultilineStringsIgnoreIndentation(str1, str2 string) bool {
|
||||||
|
// Remove all indentation from both strings
|
||||||
|
re := regexp.MustCompile(`(?m)^\s+`)
|
||||||
|
str1 = re.ReplaceAllString(str1, "")
|
||||||
|
str2 = re.ReplaceAllString(str2, "")
|
||||||
|
|
||||||
|
return str1 == str2
|
||||||
|
}
|
|
@ -0,0 +1,550 @@
|
||||||
|
table ip nat {
|
||||||
|
chain PREROUTING {
|
||||||
|
type nat hook prerouting priority dstnat; policy accept;
|
||||||
|
counter packets 769 bytes 46239 jump KUBE-SERVICES
|
||||||
|
ip daddr 192.168.8.1 counter packets 0 bytes 0 jump DOCKER_OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
chain INPUT {
|
||||||
|
type nat hook input priority 100; policy accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain OUTPUT {
|
||||||
|
type nat hook output priority -100; policy accept;
|
||||||
|
counter packets 245348 bytes 14721139 jump KUBE-SERVICES
|
||||||
|
ip daddr 192.168.8.1 counter packets 122 bytes 9151 jump DOCKER_OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
chain POSTROUTING {
|
||||||
|
type nat hook postrouting priority srcnat; policy accept;
|
||||||
|
counter packets 246110 bytes 14766910 jump KUBE-POSTROUTING
|
||||||
|
ip daddr 192.168.8.1 counter packets 0 bytes 0 jump DOCKER_POSTROUTING
|
||||||
|
}
|
||||||
|
|
||||||
|
chain DOCKER_OUTPUT {
|
||||||
|
ip daddr 192.168.8.1 tcp dport 53 counter packets 0 bytes 0 dnat to 127.0.0.11:36405
|
||||||
|
ip daddr 192.168.8.1 udp dport 53 counter packets 122 bytes 9151 dnat to 127.0.0.11:39066
|
||||||
|
}
|
||||||
|
|
||||||
|
chain DOCKER_POSTROUTING {
|
||||||
|
ip saddr 127.0.0.11 tcp sport 36405 counter packets 0 bytes 0 snat to 192.168.8.1:53
|
||||||
|
ip saddr 127.0.0.11 udp sport 39066 counter packets 0 bytes 0 snat to 192.168.8.1:53
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SERVICES {
|
||||||
|
meta l4proto tcp ip daddr 10.96.0.10 tcp dport 9153 counter packets 0 bytes 0 jump KUBE-SVC-JD5MR3NA4I4DYORP
|
||||||
|
meta l4proto udp ip daddr 10.96.0.10 udp dport 53 counter packets 0 bytes 0 jump KUBE-SVC-TCOU7JCQXEZGVUNU
|
||||||
|
meta l4proto tcp ip daddr 10.96.106.185 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-D5JKTLXOFYHV5HQZ
|
||||||
|
meta l4proto tcp ip daddr 10.96.70.203 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-IB3WK5BQ64FMB5FP
|
||||||
|
meta l4proto tcp ip daddr 10.96.0.10 tcp dport 53 counter packets 13 bytes 780 jump KUBE-SVC-ERIFXISQEP7F7OF4
|
||||||
|
meta l4proto tcp ip daddr 10.96.86.60 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-QUBDBT4PCRU7S2PI
|
||||||
|
meta l4proto tcp ip daddr 10.96.184.88 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-ZD23KKVZJDKFKTCE
|
||||||
|
meta l4proto tcp ip daddr 10.96.149.162 tcp dport 443 counter packets 0 bytes 0 jump KUBE-SVC-WHNIZNLB5XFXIX2C
|
||||||
|
meta l4proto tcp ip daddr 10.96.225.221 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-ROH4UCJ7RVN2OSM4
|
||||||
|
meta l4proto tcp ip daddr 10.96.50.119 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-SB7WEE53EMIXFNKY
|
||||||
|
meta l4proto tcp ip daddr 10.96.230.205 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-OJLEMCF5KYSTXAAJ
|
||||||
|
meta l4proto tcp ip daddr 10.96.149.162 tcp dport 15014 counter packets 0 bytes 0 jump KUBE-SVC-XHUBMW47Y5G3ICIS
|
||||||
|
meta l4proto tcp ip daddr 10.96.83.127 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-4MYBDLPZ2DFGC5Z6
|
||||||
|
meta l4proto tcp ip daddr 10.96.245.249 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-53SQRANQXVHTJ6HK
|
||||||
|
meta l4proto tcp ip daddr 10.96.85.31 tcp dport 9090 counter packets 0 bytes 0 jump KUBE-SVC-VVO7BBXOSCJQDQML
|
||||||
|
meta l4proto tcp ip daddr 10.96.0.1 tcp dport 443 counter packets 0 bytes 0 jump KUBE-SVC-NPX46M4PTMTKRN6Y
|
||||||
|
meta l4proto tcp ip daddr 10.96.113.49 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-SVC-COV23IKAKYWND6VU
|
||||||
|
meta l4proto tcp ip daddr 10.96.149.162 tcp dport 15010 counter packets 0 bytes 0 jump KUBE-SVC-NVNLZVDQSGQUD3NM
|
||||||
|
meta l4proto tcp ip daddr 10.96.231.15 tcp dport 3000 counter packets 0 bytes 0 jump KUBE-SVC-XUJLWDDTZEWKLHU6
|
||||||
|
meta l4proto tcp ip daddr 10.96.149.162 tcp dport 15012 counter packets 2 bytes 120 jump KUBE-SVC-CG3LQLBYYHBKATGN
|
||||||
|
fib daddr type local counter packets 329 bytes 19740 jump KUBE-NODEPORTS
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-POSTROUTING {
|
||||||
|
meta mark & 0x00004000 != 0x00004000 counter packets 1593 bytes 95580 return
|
||||||
|
counter packets 13 bytes 780 meta mark set mark xor 0x4000
|
||||||
|
counter packets 13 bytes 780 masquerade fully-random
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-NODEPORTS {
|
||||||
|
meta l4proto tcp tcp dport 30207 counter packets 0 bytes 0 jump KUBE-EXT-VVO7BBXOSCJQDQML
|
||||||
|
meta l4proto tcp tcp dport 31182 counter packets 0 bytes 0 jump KUBE-EXT-XUJLWDDTZEWKLHU6
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-MARK-MASQ {
|
||||||
|
counter packets 13 bytes 780 meta mark set mark or 0x4000
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-COV23IKAKYWND6VU {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.113.49 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-UYFG3BP6SBY2ENL5
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-OJLEMCF5KYSTXAAJ {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.230.205 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-4Y5RNE5AMASHQ2OZ
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-4MYBDLPZ2DFGC5Z6 {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.83.127 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-VLSRDM63ATDZAA3A
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-53SQRANQXVHTJ6HK {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.245.249 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta random & 2147483647 < 715827883 counter packets 0 bytes 0 jump KUBE-SEP-AYXBHI7HU6SF34DI
|
||||||
|
meta random & 2147483647 < 1073741824 counter packets 0 bytes 0 jump KUBE-SEP-PBXQV3T6XQVEVBGL
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-WLEZNEPJCJLP5SOM
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-EXT-VVO7BBXOSCJQDQML {
|
||||||
|
counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SVC-VVO7BBXOSCJQDQML
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-VVO7BBXOSCJQDQML {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.85.31 tcp dport 9090 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-6ZOGXI2ZCDJV5G4O
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-NPX46M4PTMTKRN6Y {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.0.1 tcp dport 443 counter packets 29 bytes 1740 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 30 bytes 1800 jump KUBE-SEP-B5DUEXKFRYN46BFH
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-B5DUEXKFRYN46BFH {
|
||||||
|
ip saddr 192.168.8.4 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 30 bytes 1800 dnat to 192.168.8.4:6443
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-EXT-XUJLWDDTZEWKLHU6 {
|
||||||
|
counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SVC-XUJLWDDTZEWKLHU6
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-XUJLWDDTZEWKLHU6 {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.231.15 tcp dport 3000 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-AEOIAT7KXYABTON5
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-D5JKTLXOFYHV5HQZ {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.106.185 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-IRX4MQBX4KRVQAZU
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-IB3WK5BQ64FMB5FP {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.70.203 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-ME7B5OZS3EMRJJUS
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-SB7WEE53EMIXFNKY {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.50.119 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-UBXSLXFPFJOARYRN
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-QUBDBT4PCRU7S2PI {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.86.60 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-ENYDTZIVOME6TBBV
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-ZD23KKVZJDKFKTCE {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.184.88 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-5KXO57AZTMNCDCVX
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-ROH4UCJ7RVN2OSM4 {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.225.221 tcp dport 9080 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-YMBKJHKN7Y2F6666
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-YMBKJHKN7Y2F6666 {
|
||||||
|
ip saddr 10.244.1.189 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.189:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-5KXO57AZTMNCDCVX {
|
||||||
|
ip saddr 10.244.1.189 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.189:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-UBXSLXFPFJOARYRN {
|
||||||
|
ip saddr 10.244.1.108 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.108:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-ENYDTZIVOME6TBBV {
|
||||||
|
ip saddr 10.244.1.108 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.108:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-6ZOGXI2ZCDJV5G4O {
|
||||||
|
ip saddr 10.244.1.9 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.9:9090
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-UYFG3BP6SBY2ENL5 {
|
||||||
|
ip saddr 10.244.1.215 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.215:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-4Y5RNE5AMASHQ2OZ {
|
||||||
|
ip saddr 10.244.2.98 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.2.98:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-VLSRDM63ATDZAA3A {
|
||||||
|
ip saddr 10.244.1.237 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.237:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-AYXBHI7HU6SF34DI {
|
||||||
|
ip saddr 10.244.1.131 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.131:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-PBXQV3T6XQVEVBGL {
|
||||||
|
ip saddr 10.244.1.215 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.215:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-WLEZNEPJCJLP5SOM {
|
||||||
|
ip saddr 10.244.2.98 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.2.98:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-AEOIAT7KXYABTON5 {
|
||||||
|
ip saddr 10.244.1.13 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.13:3000
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-IRX4MQBX4KRVQAZU {
|
||||||
|
ip saddr 10.244.1.237 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.237:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-ME7B5OZS3EMRJJUS {
|
||||||
|
ip saddr 10.244.1.131 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.1.131:9080
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-WHNIZNLB5XFXIX2C {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.149.162 tcp dport 443 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-22OJIEOUHUS2VH36
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-22OJIEOUHUS2VH36 {
|
||||||
|
ip saddr 10.244.2.88 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.2.88:15017
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-XHUBMW47Y5G3ICIS {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.149.162 tcp dport 15014 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-N6BCKY3MRNRV2ZJ2
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-N6BCKY3MRNRV2ZJ2 {
|
||||||
|
ip saddr 10.244.2.88 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.2.88:15014
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-CG3LQLBYYHBKATGN {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.149.162 tcp dport 15012 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 259 bytes 15540 jump KUBE-SEP-E675BOVPZS3XINT6
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-E675BOVPZS3XINT6 {
|
||||||
|
ip saddr 10.244.2.88 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 259 bytes 15540 dnat to 10.244.2.88:15012
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-NVNLZVDQSGQUD3NM {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.149.162 tcp dport 15010 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-E2OCVXQ5RANXZKNO
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-E2OCVXQ5RANXZKNO {
|
||||||
|
ip saddr 10.244.2.88 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.2.88:15010
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-ERIFXISQEP7F7OF4 {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.0.10 tcp dport 53 counter packets 1718 bytes 103080 jump KUBE-MARK-MASQ
|
||||||
|
meta random & 2147483647 < 1073741824 counter packets 875 bytes 52500 jump KUBE-SEP-IH2TMTJLEHQTEXG4
|
||||||
|
counter packets 843 bytes 50580 jump KUBE-SEP-QHHO2BBHA2W6ABVA
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-IH2TMTJLEHQTEXG4 {
|
||||||
|
ip saddr 10.244.0.44 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 875 bytes 52500 dnat to 10.244.0.44:53
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-JD5MR3NA4I4DYORP {
|
||||||
|
meta l4proto tcp ip saddr != 10.244.0.0/16 ip daddr 10.96.0.10 tcp dport 9153 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta random & 2147483647 < 1073741824 counter packets 0 bytes 0 jump KUBE-SEP-KTQ44RRS25IYXDAU
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-SWQQGKEGIJFNRJRL
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-KTQ44RRS25IYXDAU {
|
||||||
|
ip saddr 10.244.0.44 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.0.44:9153
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SVC-TCOU7JCQXEZGVUNU {
|
||||||
|
meta l4proto udp ip saddr != 10.244.0.0/16 ip daddr 10.96.0.10 udp dport 53 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta random & 2147483647 < 1073741824 counter packets 2 bytes 171 jump KUBE-SEP-YGFHBW2DM6N3IEK3
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SEP-W3GSBK4IMEBEFHPJ
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-YGFHBW2DM6N3IEK3 {
|
||||||
|
ip saddr 10.244.0.44 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto udp counter packets 2 bytes 171 dnat to 10.244.0.44:53
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-QHHO2BBHA2W6ABVA {
|
||||||
|
ip saddr 10.244.0.63 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 843 bytes 50580 dnat to 10.244.0.63:53
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-SWQQGKEGIJFNRJRL {
|
||||||
|
ip saddr 10.244.0.63 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto tcp counter packets 0 bytes 0 dnat to 10.244.0.63:9153
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SEP-W3GSBK4IMEBEFHPJ {
|
||||||
|
ip saddr 10.244.0.63 counter packets 0 bytes 0 jump KUBE-MARK-MASQ
|
||||||
|
meta l4proto udp counter packets 0 bytes 0 dnat to 10.244.0.63:53
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table ip mangle {
|
||||||
|
chain KUBE-IPTABLES-HINT {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table ip filter {
|
||||||
|
chain KUBE-FIREWALL {
|
||||||
|
ip saddr != 127.0.0.0/8 ip daddr 127.0.0.0/8 ct status dnat counter packets 0 bytes 0 drop
|
||||||
|
}
|
||||||
|
|
||||||
|
chain OUTPUT {
|
||||||
|
type filter hook output priority filter; policy accept;
|
||||||
|
ct state new counter packets 245383 bytes 14723644 jump KUBE-PROXY-FIREWALL
|
||||||
|
ct state new counter packets 245383 bytes 14723644 jump KUBE-SERVICES
|
||||||
|
counter packets 3043981 bytes 2633914697 jump KUBE-FIREWALL
|
||||||
|
}
|
||||||
|
|
||||||
|
chain INPUT {
|
||||||
|
type filter hook input priority filter; policy accept;
|
||||||
|
ct state new counter packets 47332 bytes 2840200 jump KUBE-PROXY-FIREWALL
|
||||||
|
counter packets 3210147 bytes 435991279 jump KUBE-NODEPORTS
|
||||||
|
ct state new counter packets 47332 bytes 2840200 jump KUBE-EXTERNAL-SERVICES
|
||||||
|
counter packets 3210791 bytes 436579809 jump KUBE-FIREWALL
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-EXTERNAL-SERVICES {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain FORWARD {
|
||||||
|
type filter hook forward priority filter; policy accept;
|
||||||
|
ct state new counter packets 774 bytes 46491 jump KUBE-PROXY-FIREWALL
|
||||||
|
counter packets 287624 bytes 35538980 jump KUBE-FORWARD
|
||||||
|
ct state new counter packets 774 bytes 46491 jump KUBE-SERVICES
|
||||||
|
ct state new counter packets 774 bytes 46491 jump KUBE-EXTERNAL-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-NODEPORTS {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SERVICES {
|
||||||
|
meta l4proto tcp ip daddr 10.96.65.65 tcp dport 80 counter packets 0 bytes 0 reject
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-FORWARD {
|
||||||
|
meta mark & 0x00004000 == 0x00004000 counter packets 0 bytes 0 accept
|
||||||
|
ct state related,established counter packets 1866 bytes 233783 accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-FIREWALL {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table ip6 mangle {
|
||||||
|
chain KUBE-IPTABLES-HINT {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table ip6 nat {
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain POSTROUTING {
|
||||||
|
type nat hook postrouting priority srcnat; policy accept;
|
||||||
|
counter packets 0 bytes 0 jump KUBE-POSTROUTING
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SERVICES {
|
||||||
|
ip6 daddr != ::1 fib daddr type local counter packets 0 bytes 0 jump KUBE-NODEPORTS
|
||||||
|
}
|
||||||
|
|
||||||
|
chain OUTPUT {
|
||||||
|
type nat hook output priority -100; policy accept;
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain PREROUTING {
|
||||||
|
type nat hook prerouting priority dstnat; policy accept;
|
||||||
|
counter packets 0 bytes 0 jump KUBE-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-POSTROUTING {
|
||||||
|
meta mark & 0x00004000 != 0x00004000 counter packets 0 bytes 0 return
|
||||||
|
counter packets 0 bytes 0 meta mark set mark xor 0x4000
|
||||||
|
counter packets 0 bytes 0
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-NODEPORTS {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-MARK-MASQ {
|
||||||
|
counter packets 0 bytes 0 meta mark set mark or 0x4000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table ip6 filter {
|
||||||
|
chain KUBE-KUBELET-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-CANARY {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-EXTERNAL-SERVICES {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain INPUT {
|
||||||
|
type filter hook input priority filter; policy accept;
|
||||||
|
counter packets 8 bytes 552 jump KUBE-FIREWALL
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-PROXY-FIREWALL
|
||||||
|
counter packets 8 bytes 552 jump KUBE-NODEPORTS
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-EXTERNAL-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain FORWARD {
|
||||||
|
type filter hook forward priority filter; policy accept;
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-PROXY-FIREWALL
|
||||||
|
counter packets 0 bytes 0 jump KUBE-FORWARD
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-SERVICES
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-EXTERNAL-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-NODEPORTS {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-SERVICES {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain OUTPUT {
|
||||||
|
type filter hook output priority filter; policy accept;
|
||||||
|
counter packets 139 bytes 7888 jump KUBE-FIREWALL
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-PROXY-FIREWALL
|
||||||
|
ct state new counter packets 0 bytes 0 jump KUBE-SERVICES
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-FORWARD {
|
||||||
|
meta mark & 0x00004000 == 0x00004000 counter packets 0 bytes 0 accept
|
||||||
|
ct state related,established counter packets 0 bytes 0 accept
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-PROXY-FIREWALL {
|
||||||
|
}
|
||||||
|
|
||||||
|
chain KUBE-FIREWALL {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table inet kindnet-network-policies {
|
||||||
|
set podips-v4 {
|
||||||
|
type ipv4_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
set podips-v6 {
|
||||||
|
type ipv6_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
chain postrouting {
|
||||||
|
type filter hook postrouting priority srcnat - 5; policy accept;
|
||||||
|
udp dport 53 accept
|
||||||
|
meta l4proto ipv6-icmp accept
|
||||||
|
meta skuid 0 accept
|
||||||
|
ct state established,related accept
|
||||||
|
ip saddr @podips-v4 queue flags bypass to 102
|
||||||
|
ip daddr @podips-v4 queue flags bypass to 102
|
||||||
|
ip6 saddr @podips-v6 queue flags bypass to 102
|
||||||
|
ip6 daddr @podips-v6 queue flags bypass to 102
|
||||||
|
}
|
||||||
|
|
||||||
|
chain prerouting {
|
||||||
|
type filter hook prerouting priority dstnat + 5; policy accept;
|
||||||
|
meta l4proto != udp accept
|
||||||
|
udp dport != 53 accept
|
||||||
|
ip saddr @podips-v4 queue flags bypass to 102
|
||||||
|
ip daddr @podips-v4 queue flags bypass to 102
|
||||||
|
ip6 saddr @podips-v6 queue flags bypass to 102
|
||||||
|
ip6 daddr @podips-v6 queue flags bypass to 102
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table inet kindnet-dnscache {
|
||||||
|
set set-v4-nameservers {
|
||||||
|
type ipv4_addr
|
||||||
|
elements = { 10.96.0.10 }
|
||||||
|
}
|
||||||
|
|
||||||
|
chain prerouting {
|
||||||
|
type filter hook prerouting priority raw; policy accept;
|
||||||
|
ip saddr 10.244.2.0/24 ip daddr @set-v4-nameservers udp dport 53 queue flags bypass to 103
|
||||||
|
}
|
||||||
|
|
||||||
|
chain output {
|
||||||
|
type filter hook output priority raw; policy accept;
|
||||||
|
meta mark 0x0000006e udp sport 53 notrack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table inet kindnet-ipmasq {
|
||||||
|
set noMasqV4 {
|
||||||
|
type ipv4_addr
|
||||||
|
flags interval
|
||||||
|
auto-merge
|
||||||
|
elements = { 10.244.0.0/24, 10.244.1.0/24,
|
||||||
|
10.244.2.0/24 }
|
||||||
|
}
|
||||||
|
|
||||||
|
set noMasqV6 {
|
||||||
|
type ipv6_addr
|
||||||
|
flags interval
|
||||||
|
auto-merge
|
||||||
|
}
|
||||||
|
|
||||||
|
chain postrouting {
|
||||||
|
type nat hook postrouting priority srcnat - 10; policy accept;
|
||||||
|
ct state established,related accept
|
||||||
|
fib saddr type local accept
|
||||||
|
ip daddr @noMasqV4 accept
|
||||||
|
ip6 daddr @noMasqV6 accept
|
||||||
|
masquerade
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
table ip filter {
|
||||||
|
chain output {
|
||||||
|
type filter hook output priority 100; policy accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain input {
|
||||||
|
type filter hook input priority 0; policy accept;
|
||||||
|
iifname "lan0" accept
|
||||||
|
iifname "wan0" drop
|
||||||
|
}
|
||||||
|
|
||||||
|
chain forward {
|
||||||
|
type filter hook forward priority 0; policy drop;
|
||||||
|
iifname "lan0" oifname "wan0" accept
|
||||||
|
iifname "wan0" oifname "lan0" ct state related,established accept
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,7 +71,7 @@ func TestMonitor(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
genMsg := event.GeneratedBy.Data.(*nftables.GenMsg)
|
genMsg := event.GeneratedBy.Data.(*nftables.Gen)
|
||||||
fileName := filepath.Base(os.Args[0])
|
fileName := filepath.Base(os.Args[0])
|
||||||
|
|
||||||
if genMsg.ProcComm != fileName {
|
if genMsg.ProcComm != fileName {
|
||||||
|
|
359
nftables_test.go
359
nftables_test.go
|
@ -128,6 +128,47 @@ func ifname(n string) []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTableCreateDestroy(t *testing.T) {
|
||||||
|
c, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer c.FlushRuleset()
|
||||||
|
|
||||||
|
filter := &nftables.Table{
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
Name: "filter",
|
||||||
|
}
|
||||||
|
c.DestroyTable(filter)
|
||||||
|
c.AddTable(filter)
|
||||||
|
err := c.Flush()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("on Flush: %q", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lookupMyTable := func() bool {
|
||||||
|
ts, err := c.ListTables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("on ListTables: %q", err.Error())
|
||||||
|
}
|
||||||
|
return slices.ContainsFunc(ts, func(t *nftables.Table) bool {
|
||||||
|
return t.Name == filter.Name && t.Family == filter.Family
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !lookupMyTable() {
|
||||||
|
t.Fatal("AddTable doesn't create my table!")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.DestroyTable(filter)
|
||||||
|
if err = c.Flush(); err != nil {
|
||||||
|
t.Fatalf("on Flush: %q", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if lookupMyTable() {
|
||||||
|
t.Fatal("DestroyTable doesn't delete my table!")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.DestroyTable(filter) // just for test that 'destroy' ignore error 'not found'
|
||||||
|
}
|
||||||
|
|
||||||
func TestRuleOperations(t *testing.T) {
|
func TestRuleOperations(t *testing.T) {
|
||||||
// Create a new network namespace to test these operations,
|
// Create a new network namespace to test these operations,
|
||||||
// and tear down the namespace at test completion.
|
// and tear down the namespace at test completion.
|
||||||
|
@ -3777,7 +3818,7 @@ func TestDeleteElementNamedSet(t *testing.T) {
|
||||||
Name: "test",
|
Name: "test",
|
||||||
KeyType: nftables.TypeInetService,
|
KeyType: nftables.TypeInetService,
|
||||||
}
|
}
|
||||||
if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {
|
if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}, {Key: []byte{0, 24}}}); err != nil {
|
||||||
t.Errorf("c.AddSet(portSet) failed: %v", err)
|
t.Errorf("c.AddSet(portSet) failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.Flush(); err != nil {
|
if err := c.Flush(); err != nil {
|
||||||
|
@ -3794,6 +3835,22 @@ func TestDeleteElementNamedSet(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("c.GetSets() failed: %v", err)
|
t.Errorf("c.GetSets() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if len(elems) != 2 {
|
||||||
|
t.Fatalf("len(elems) = %d, want 2", len(elems))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}})
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}})
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 99}}})
|
||||||
|
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
t.Errorf("Third c.Flush() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
elems, err = c.GetSetElements(portSet)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("c.GetSets() failed: %v", err)
|
||||||
|
}
|
||||||
if len(elems) != 1 {
|
if len(elems) != 1 {
|
||||||
t.Fatalf("len(elems) = %d, want 1", len(elems))
|
t.Fatalf("len(elems) = %d, want 1", len(elems))
|
||||||
}
|
}
|
||||||
|
@ -7429,3 +7486,303 @@ func TestAutoBufferSize(t *testing.T) {
|
||||||
t.Fatalf("failed to flush: %v", err)
|
t.Fatalf("failed to flush: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetGen(t *testing.T) {
|
||||||
|
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer conn.FlushRuleset()
|
||||||
|
|
||||||
|
gen, err := conn.GetGen()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get gen: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Flush to increment the generation ID.
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
t.Fatalf("failed to flush: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newGen, err := conn.GetGen()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get gen: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if newGen.ID <= gen.ID {
|
||||||
|
t.Fatalf("gen ID did not increase, got %d, want > %d", newGen.ID, gen.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if newGen.ProcComm != gen.ProcComm {
|
||||||
|
t.Errorf("gen ProcComm changed, got %s, want %s", newGen.ProcComm, gen.ProcComm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if newGen.ProcPID != gen.ProcPID {
|
||||||
|
t.Errorf("gen ProcPID changed, got %d, want %d", newGen.ProcPID, gen.ProcPID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlushWithGenID(t *testing.T) {
|
||||||
|
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer conn.FlushRuleset()
|
||||||
|
|
||||||
|
gen, err := conn.GetGen()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get gen: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Flush to increment the generation ID.
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
t.Fatalf("failed to flush: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table-2",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
err = conn.FlushWithGenID(gen.ID)
|
||||||
|
if err == nil || !errors.Is(err, syscall.ERESTART) {
|
||||||
|
t.Errorf("expected error to be ERESTART, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, err := conn.ListTable("test-table-2")
|
||||||
|
if table != nil && !errors.Is(err, syscall.ENOENT) {
|
||||||
|
t.Errorf("expected table to not exist, got: %v", table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRuleByHandle(t *testing.T) {
|
||||||
|
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer conn.FlushRuleset()
|
||||||
|
|
||||||
|
table := conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
chain := conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "test-chain",
|
||||||
|
Table: table,
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := range 3 {
|
||||||
|
conn.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
UserData: fmt.Appendf([]byte{}, "rule-%d", i+1),
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
t.Fatalf("failed to flush: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err := conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := rules[1]
|
||||||
|
|
||||||
|
got, err := conn.GetRuleByHandle(table, chain, want.Handle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRuleByHandle failed: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(got.UserData, want.UserData) {
|
||||||
|
t.Fatalf("expected userdata %q, got %q", got.UserData, want.UserData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResetRule(t *testing.T) {
|
||||||
|
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer conn.FlushRuleset()
|
||||||
|
|
||||||
|
table := conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
chain := conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "test-chain",
|
||||||
|
Table: table,
|
||||||
|
})
|
||||||
|
|
||||||
|
tests := [...]struct {
|
||||||
|
Bytes uint64
|
||||||
|
Packets uint64
|
||||||
|
Reset bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Bytes: 1024,
|
||||||
|
Packets: 1,
|
||||||
|
Reset: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Bytes: 2048,
|
||||||
|
Packets: 2,
|
||||||
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Bytes: 4096,
|
||||||
|
Packets: 4,
|
||||||
|
Reset: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
conn.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Counter{
|
||||||
|
Bytes: tt.Bytes,
|
||||||
|
Packets: tt.Packets,
|
||||||
|
},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
t.Fatalf("flush failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err := conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rules) != len(tests) {
|
||||||
|
t.Fatalf("expected %d rules, got %d", len(tests), len(rules))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, r := range rules {
|
||||||
|
if !tests[i].Reset {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err := conn.ResetRule(table, chain, r.Handle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ResetRule failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err = conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, r := range rules {
|
||||||
|
counter, ok := r.Exprs[0].(*expr.Counter)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("expected first expr to be Counter, got %T", r.Exprs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if tests[i].Reset {
|
||||||
|
if counter.Bytes != 0 || counter.Packets != 0 {
|
||||||
|
t.Errorf(
|
||||||
|
"expected counter values to be reset to zero, got Bytes=%d, Packets=%d",
|
||||||
|
counter.Bytes,
|
||||||
|
counter.Packets,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Making sure that only the selected rules were reset
|
||||||
|
if counter.Bytes != tests[i].Bytes || counter.Packets != tests[i].Packets {
|
||||||
|
t.Errorf(
|
||||||
|
"unexpected counter values: got Bytes=%d, Packets=%d, want Bytes=%d, Packets=%d",
|
||||||
|
counter.Bytes,
|
||||||
|
counter.Packets,
|
||||||
|
tests[i].Bytes,
|
||||||
|
tests[i].Packets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResetRules(t *testing.T) {
|
||||||
|
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer conn.FlushRuleset()
|
||||||
|
|
||||||
|
table := conn.AddTable(&nftables.Table{
|
||||||
|
Name: "test-table",
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
})
|
||||||
|
|
||||||
|
chain := conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "test-chain",
|
||||||
|
Table: table,
|
||||||
|
})
|
||||||
|
|
||||||
|
for range 3 {
|
||||||
|
conn.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: chain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Counter{
|
||||||
|
Bytes: 1,
|
||||||
|
Packets: 1,
|
||||||
|
},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
t.Fatalf("flush failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err := conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rules) != 3 {
|
||||||
|
t.Fatalf("expected %d rules, got %d", 3, len(rules))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.ResetRules(table, chain); err != nil {
|
||||||
|
t.Fatalf("ResetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err = conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetRules failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range rules {
|
||||||
|
counter, ok := r.Exprs[0].(*expr.Counter)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("expected first expr to be Counter, got %T", r.Exprs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter.Bytes != 0 || counter.Packets != 0 {
|
||||||
|
t.Errorf(
|
||||||
|
"expected counter values to be reset to zero, got Bytes=%d, Packets=%d",
|
||||||
|
counter.Bytes,
|
||||||
|
counter.Packets,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
77
rule.go
77
rule.go
|
@ -71,31 +71,98 @@ type Rule struct {
|
||||||
|
|
||||||
// GetRule returns the rules in the specified table and chain.
|
// GetRule returns the rules in the specified table and chain.
|
||||||
//
|
//
|
||||||
// Deprecated: use GetRules instead.
|
// Deprecated: use GetRuleByHandle instead.
|
||||||
func (cc *Conn) GetRule(t *Table, c *Chain) ([]*Rule, error) {
|
func (cc *Conn) GetRule(t *Table, c *Chain) ([]*Rule, error) {
|
||||||
return cc.GetRules(t, c)
|
return cc.GetRules(t, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRuleByHandle returns the rule in the specified table and chain by its
|
||||||
|
// handle.
|
||||||
|
// https://docs.kernel.org/networking/netlink_spec/nftables.html#getrule
|
||||||
|
func (cc *Conn) GetRuleByHandle(t *Table, c *Chain, handle uint64) (*Rule, error) {
|
||||||
|
rules, err := cc.getRules(t, c, unix.NFT_MSG_GETRULE, handle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := len(rules), 1; got != want {
|
||||||
|
return nil, fmt.Errorf("expected rule count %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetRules returns the rules in the specified table and chain.
|
// GetRules returns the rules in the specified table and chain.
|
||||||
func (cc *Conn) GetRules(t *Table, c *Chain) ([]*Rule, error) {
|
func (cc *Conn) GetRules(t *Table, c *Chain) ([]*Rule, error) {
|
||||||
|
return cc.getRules(t, c, unix.NFT_MSG_GETRULE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetRule resets the stateful expressions (e.g., counters) of the given
|
||||||
|
// rule. The reset is applied immediately (no Flush is required). The returned
|
||||||
|
// rule reflects its state prior to the reset. The provided rule must have a
|
||||||
|
// valid Handle.
|
||||||
|
// https://docs.kernel.org/networking/netlink_spec/nftables.html#getrule-reset
|
||||||
|
func (cc *Conn) ResetRule(t *Table, c *Chain, handle uint64) (*Rule, error) {
|
||||||
|
if handle == 0 {
|
||||||
|
return nil, fmt.Errorf("rule must have a valid handle")
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err := cc.getRules(t, c, unix.NFT_MSG_GETRULE_RESET, handle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := len(rules), 1; got != want {
|
||||||
|
return nil, fmt.Errorf("expected rule count %d, got %d", want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetRules resets the stateful expressions (e.g., counters) of all rules
|
||||||
|
// in the given table and chain. The reset is applied immediately (no Flush
|
||||||
|
// is required). The returned rules reflect their state prior to the reset.
|
||||||
|
// state.
|
||||||
|
// https://docs.kernel.org/networking/netlink_spec/nftables.html#getrule-reset
|
||||||
|
func (cc *Conn) ResetRules(t *Table, c *Chain) ([]*Rule, error) {
|
||||||
|
return cc.getRules(t, c, unix.NFT_MSG_GETRULE_RESET, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRules retrieves rules from the given table and chain, using the provided
|
||||||
|
// msgType (either unix.NFT_MSG_GETRULE or unix.NFT_MSG_GETRULE_RESET). If the
|
||||||
|
// handle is non-zero, the operation applies only to the rule with that handle.
|
||||||
|
func (cc *Conn) getRules(t *Table, c *Chain, msgType int, handle uint64) ([]*Rule, error) {
|
||||||
conn, closer, err := cc.netlinkConn()
|
conn, closer, err := cc.netlinkConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() { _ = closer() }()
|
defer func() { _ = closer() }()
|
||||||
|
|
||||||
data, err := netlink.MarshalAttributes([]netlink.Attribute{
|
attrs := []netlink.Attribute{
|
||||||
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
|
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
|
||||||
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(c.Name + "\x00")},
|
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(c.Name + "\x00")},
|
||||||
})
|
}
|
||||||
|
|
||||||
|
var flags netlink.HeaderFlags = netlink.Request | netlink.Acknowledge | netlink.Dump
|
||||||
|
|
||||||
|
if handle != 0 {
|
||||||
|
attrs = append(attrs, netlink.Attribute{
|
||||||
|
Type: unix.NFTA_RULE_HANDLE,
|
||||||
|
Data: binaryutil.BigEndian.PutUint64(handle),
|
||||||
|
})
|
||||||
|
|
||||||
|
flags = netlink.Request | netlink.Acknowledge
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := netlink.MarshalAttributes(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
message := netlink.Message{
|
message := netlink.Message{
|
||||||
Header: netlink.Header{
|
Header: netlink.Header{
|
||||||
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETRULE),
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | msgType),
|
||||||
Flags: netlink.Request | netlink.Acknowledge | netlink.Dump,
|
Flags: flags,
|
||||||
},
|
},
|
||||||
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
||||||
}
|
}
|
||||||
|
|
18
set.go
18
set.go
|
@ -44,6 +44,9 @@ const (
|
||||||
NFTA_SET_ELEM_KEY_END = 10
|
NFTA_SET_ELEM_KEY_END = 10
|
||||||
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429
|
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429
|
||||||
NFTA_SET_ELEM_EXPRESSIONS = 0x11
|
NFTA_SET_ELEM_EXPRESSIONS = 0x11
|
||||||
|
// FIXME: in sys@v0.34.0 no unix.NFT_MSG_DESTROYSETELEM const yet.
|
||||||
|
// See nf_tables_msg_types enum in https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h
|
||||||
|
NFT_MSG_DESTROYSETELEM = 0x1e
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetDatatype represents a datatype declared by nft.
|
// SetDatatype represents a datatype declared by nft.
|
||||||
|
@ -391,6 +394,16 @@ func (cc *Conn) SetDeleteElements(s *Set, vals []SetElement) error {
|
||||||
return cc.appendElemList(s, vals, unix.NFT_MSG_DELSETELEM)
|
return cc.appendElemList(s, vals, unix.NFT_MSG_DELSETELEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDestroyElements like SetDeleteElements, but not an error if setelement doesn't exists
|
||||||
|
func (cc *Conn) SetDestroyElements(s *Set, vals []SetElement) error {
|
||||||
|
cc.mu.Lock()
|
||||||
|
defer cc.mu.Unlock()
|
||||||
|
if s.Anonymous {
|
||||||
|
return errors.New("anonymous sets cannot be updated")
|
||||||
|
}
|
||||||
|
return cc.appendElemList(s, vals, NFT_MSG_DESTROYSETELEM)
|
||||||
|
}
|
||||||
|
|
||||||
// maxElemBatchSize is the maximum size in bytes of encoded set elements which
|
// maxElemBatchSize is the maximum size in bytes of encoded set elements which
|
||||||
// are sent in one netlink message. The size field of a netlink attribute is a
|
// are sent in one netlink message. The size field of a netlink attribute is a
|
||||||
// uint16, and 1024 bytes is more than enough for the per-message headers.
|
// uint16, and 1024 bytes is more than enough for the per-message headers.
|
||||||
|
@ -826,8 +839,9 @@ func parseSetDatatype(magic uint32) (SetDatatype, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM)
|
newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM)
|
||||||
delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM)
|
delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM)
|
||||||
|
destroyElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_DESTROYSETELEM)
|
||||||
)
|
)
|
||||||
|
|
||||||
func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {
|
func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {
|
||||||
|
|
16
table.go
16
table.go
|
@ -24,6 +24,10 @@ import (
|
||||||
const (
|
const (
|
||||||
newTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE)
|
newTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE)
|
||||||
delTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE)
|
delTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE)
|
||||||
|
|
||||||
|
// FIXME: in sys@v0.34.0 no unix.NFT_MSG_DESTROYTABLE const yet.
|
||||||
|
// See nf_tables_msg_types enum in https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h
|
||||||
|
destroyTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | 0x1a)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TableFamily specifies the address family for this table.
|
// TableFamily specifies the address family for this table.
|
||||||
|
@ -51,15 +55,25 @@ type Table struct {
|
||||||
|
|
||||||
// DelTable deletes a specific table, along with all chains/rules it contains.
|
// DelTable deletes a specific table, along with all chains/rules it contains.
|
||||||
func (cc *Conn) DelTable(t *Table) {
|
func (cc *Conn) DelTable(t *Table) {
|
||||||
|
cc.delTable(t, delTableHeaderType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestroyTable is like DelTable, but not an error if table doesn't exists
|
||||||
|
func (cc *Conn) DestroyTable(t *Table) {
|
||||||
|
cc.delTable(t, destroyTableHeaderType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *Conn) delTable(t *Table, hdrType netlink.HeaderType) {
|
||||||
cc.mu.Lock()
|
cc.mu.Lock()
|
||||||
defer cc.mu.Unlock()
|
defer cc.mu.Unlock()
|
||||||
data := cc.marshalAttr([]netlink.Attribute{
|
data := cc.marshalAttr([]netlink.Attribute{
|
||||||
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
|
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
|
||||||
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
|
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
|
||||||
})
|
})
|
||||||
|
|
||||||
cc.messages = append(cc.messages, netlinkMessage{
|
cc.messages = append(cc.messages, netlinkMessage{
|
||||||
Header: netlink.Header{
|
Header: netlink.Header{
|
||||||
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE),
|
Type: hdrType,
|
||||||
Flags: netlink.Request | netlink.Acknowledge,
|
Flags: netlink.Request | netlink.Acknowledge,
|
||||||
},
|
},
|
||||||
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
||||||
|
|
Loading…
Reference in New Issue