1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
package nftables_test
import (
"fmt"
"log"
"net"
"sync"
"sync/atomic"
"testing"
"github.com/google/nftables"
"github.com/google/nftables/expr"
"github.com/google/nftables/internal/nftest"
)
func ExampleNewMonitor() {
conn, err := nftables.New()
if err != nil {
log.Fatal(err)
}
mon := nftables.NewMonitor()
defer mon.Close()
events, err := conn.AddMonitor(mon)
if err != nil {
log.Fatal(err)
}
for ev := range events {
log.Printf("ev: %+v, data = %T", ev, ev.Data)
switch ev.Type {
case nftables.MonitorEventTypeNewTable:
log.Printf("data = %+v", ev.Data.(*nftables.Table))
// …more cases if needed…
}
}
}
func TestMonitor(t *testing.T) {
// Create a new network namespace to test these operations,
// and tear down the namespace at test completion.
c, newNS := nftest.OpenSystemConn(t, *enableSysTests)
defer nftest.CleanupSystemConn(t, newNS)
// Clear all rules at the beginning + end of the test.
c.FlushRuleset()
defer c.FlushRuleset()
// default to monitor all
monitor := nftables.NewMonitor()
events, err := c.AddMonitor(monitor)
if err != nil {
t.Fatal(err)
}
defer monitor.Close()
var gotTable *nftables.Table
var gotChain *nftables.Chain
var gotRule *nftables.Rule
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
count := int32(0)
for {
select {
case event, ok := <-events:
if !ok {
return
}
if event.Error != nil {
err = fmt.Errorf("monitor err: %s", event.Error)
return
}
switch event.Type {
case nftables.MonitorEventTypeNewTable:
gotTable = event.Data.(*nftables.Table)
atomic.AddInt32(&count, 1)
case nftables.MonitorEventTypeNewChain:
gotChain = event.Data.(*nftables.Chain)
atomic.AddInt32(&count, 1)
case nftables.MonitorEventTypeNewRule:
gotRule = event.Data.(*nftables.Rule)
atomic.AddInt32(&count, 1)
}
if atomic.LoadInt32(&count) == 3 {
return
}
}
}
}()
nat := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv4,
Name: "nat",
})
postrouting := c.AddChain(&nftables.Chain{
Name: "postrouting",
Hooknum: nftables.ChainHookPostrouting,
Priority: nftables.ChainPriorityNATSource,
Table: nat,
Type: nftables.ChainTypeNAT,
})
rule := c.AddRule(&nftables.Rule{
Table: nat,
Chain: postrouting,
Exprs: []expr.Any{
// payload load 4b @ network header + 12 => reg 1
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 12,
Len: 4,
},
// cmp eq reg 1 0x0245a8c0
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: net.ParseIP("192.168.69.2").To4(),
},
// masq
&expr.Masq{},
},
})
if err := c.Flush(); err != nil {
t.Fatal(err)
}
wg.Wait()
if gotTable.Family != nat.Family || gotTable.Name != nat.Name {
t.Fatal("no want table", gotTable.Family, gotTable.Name)
}
if gotChain.Type != postrouting.Type || gotChain.Name != postrouting.Name ||
*gotChain.Hooknum != *postrouting.Hooknum {
t.Fatal("no want chain", gotChain.Type, gotChain.Name, gotChain.Hooknum)
}
if len(gotRule.Exprs) != len(rule.Exprs) {
t.Fatal("no want rule")
}
}
|