| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- // Copyright (c) Tailscale Inc & contributors
- // SPDX-License-Identifier: BSD-3-Clause
- //go:build linux
- package linuxfw
- import (
- "bytes"
- "errors"
- "fmt"
- "net/netip"
- "os"
- "runtime"
- "slices"
- "strings"
- "testing"
- "github.com/google/nftables"
- "github.com/google/nftables/expr"
- "github.com/mdlayher/netlink"
- "github.com/vishvananda/netns"
- "tailscale.com/net/tsaddr"
- "tailscale.com/tstest"
- "tailscale.com/types/logger"
- )
- func toAnySlice[T any](s []T) []any {
- out := make([]any, len(s))
- for i, v := range s {
- out[i] = v
- }
- return out
- }
- // nfdump returns a hexdump of 4 bytes per line (like nft --debug=all), allowing
- // users to make sense of large byte literals more easily.
- func nfdump(b []byte) string {
- var buf bytes.Buffer
- for c := range slices.Chunk(b, 4) {
- format := strings.Repeat("%02x ", len(c))
- fmt.Fprintf(&buf, format+"\n", toAnySlice(c)...)
- }
- return buf.String()
- }
- func TestMaskof(t *testing.T) {
- pfx, err := netip.ParsePrefix("192.168.1.0/24")
- if err != nil {
- t.Fatal(err)
- }
- want := []byte{0xff, 0xff, 0xff, 0x00}
- if got := maskof(pfx); !bytes.Equal(got, want) {
- t.Errorf("got %v; want %v", got, want)
- }
- }
- // linediff returns a side-by-side diff of two nfdump() return values, flagging
- // lines which are not equal with an exclamation point prefix.
- func linediff(a, b string) string {
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "got -- want\n")
- linesA := strings.Split(a, "\n")
- linesB := strings.Split(b, "\n")
- for idx, lineA := range linesA {
- if idx >= len(linesB) {
- break
- }
- lineB := linesB[idx]
- prefix := "! "
- if lineA == lineB {
- prefix = " "
- }
- fmt.Fprintf(&buf, "%s%s -- %s\n", prefix, lineA, lineB)
- }
- return buf.String()
- }
- func newTestConn(t *testing.T, want [][]byte, reply [][]netlink.Message) *nftables.Conn {
- conn, err := nftables.New(nftables.WithTestDial(
- func(req []netlink.Message) ([]netlink.Message, error) {
- for idx, msg := range req {
- b, err := msg.MarshalBinary()
- if err != nil {
- t.Fatal(err)
- }
- if len(b) < 16 {
- continue
- }
- b = b[16:]
- if len(want) == 0 {
- t.Errorf("no want entry for message %d: %x", idx, b)
- continue
- }
- if got, want := b, want[0]; !bytes.Equal(got, want) {
- t.Errorf("message %d: %s", idx, linediff(nfdump(got), nfdump(want)))
- }
- want = want[1:]
- }
- // no reply for batch end message
- if len(want) == 0 {
- return nil, nil
- }
- rep := reply[0]
- reply = reply[1:]
- return rep, nil
- }))
- if err != nil {
- t.Fatal(err)
- }
- return conn
- }
- func TestInsertHookRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-input-test { type filter hook input priority 0 \; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add chain ip ts-filter-test ts-jumpto
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x0e\x00\x03\x00\x74\x73\x2d\x6a\x75\x6d\x70\x74\x6f\x00\x00\x00"),
- // nft add rule ip ts-filter-test ts-input-test counter jump ts-jumptp
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x70\x00\x04\x80\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x2c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x20\x00\x02\x80\x1c\x00\x02\x80\x08\x00\x01\x00\xff\xff\xff\xfd\x0e\x00\x02\x00\x74\x73\x2d\x6a\x75\x6d\x70\x74\x6f\x00\x00\x00"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- fromchain := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- tochain := testConn.AddChain(&nftables.Chain{
- Name: "ts-jumpto",
- Table: table,
- })
- err := addHookRule(testConn, table, fromchain, tochain.Name)
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestInsertLoopbackRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-input-test { type filter hook input priority 0 \; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-input-test iifname "lo" ip saddr 192.168.0.2 counter accept
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x10\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x06\x00\x01\x00\x6c\x6f\x00\x00\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x0c\x08\x00\x04\x00\x00\x00\x00\x04\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\xc0\xa8\x00\x02\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- addr := netip.MustParseAddr("192.168.0.2")
- err := insertLoopbackRule(testConn, proto, table, chain, addr)
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestInsertLoopbackRuleV6(t *testing.T) {
- protoV6 := nftables.TableFamilyIPv6
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip6 ts-filter-test
- []byte("\x0a\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip6 ts-filter-test ts-input-test { type filter hook input priority 0\; }
- []byte("\x0a\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip6 ts-filter-test ts-input-test iifname "lo" ip6 addr 2001:db8::1 counter accept
- []byte("\x0a\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x1c\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x06\x00\x01\x00\x6c\x6f\x00\x00\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x08\x08\x00\x04\x00\x00\x00\x00\x10\x38\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x2c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x18\x00\x03\x80\x14\x00\x01\x00\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- tableV6 := testConn.AddTable(&nftables.Table{
- Family: protoV6,
- Name: "ts-filter-test",
- })
- chainV6 := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: tableV6,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- addrV6 := netip.MustParseAddr("2001:db8::1")
- err := insertLoopbackRule(testConn, protoV6, tableV6, chainV6, addrV6)
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddReturnChromeOSVMRangeRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-input-test { type filter hook input priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-input-test iifname != "testTunn" ip saddr 100.115.92.0/23 counter return
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x58\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x0c\x08\x00\x04\x00\x00\x00\x00\x04\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\xff\xff\xfe\x00\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x00\x00\x00\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\x64\x73\x5c\x00\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\xff\xff\xff\xfb"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addReturnChromeOSVMRangeRule(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddDropCGNATRangeRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-input-test { type filter hook input priority filter; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-input-test iifname != "testTunn" ip saddr 100.64.0.0/10 counter drop
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x58\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x0c\x08\x00\x04\x00\x00\x00\x00\x04\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\xff\xc0\x00\x00\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x00\x00\x00\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\x64\x40\x00\x00\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addDropCGNATRangeRule(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddSetSubnetRouteMarkRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-forward-test { type filter hook forward priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x03\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x02\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-forward-test iifname "testTunn" counter meta mark set mark and 0xff00ffff xor 0x40000
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x02\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x10\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x03\x08\x00\x01\x00\x00\x00\x00\x01\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\xff\x00\xff\xff\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x04\x00\x00\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x03\x08\x00\x03\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-forward-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookForward,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addSetSubnetRouteMarkRule(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddDropOutgoingPacketFromCGNATRangeRuleWithTunname(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-forward-test { type filter hook forward priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x03\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x02\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-forward-test oifname "testTunn" ip saddr 100.64.0.0/10 counter drop
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x02\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x58\x01\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x07\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x34\x00\x01\x80\x0c\x00\x01\x00\x70\x61\x79\x6c\x6f\x61\x64\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x0c\x08\x00\x04\x00\x00\x00\x00\x04\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\xff\xc0\x00\x00\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x00\x00\x00\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\x64\x40\x00\x00\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-forward-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookForward,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addDropOutgoingPacketFromCGNATRangeRuleWithTunname(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddAcceptOutgoingPacketRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-forward-test { type filter hook forward priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x03\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x02\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-forward-test oifname "testTunn" counter accept
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x02\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\xb4\x00\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x07\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-forward-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookForward,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addAcceptOutgoingPacketRule(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddAcceptIncomingPacketRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-input-test { type filter hook input priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x03\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-input-test iifname "testTunn" counter accept
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x12\x00\x02\x00\x74\x73\x2d\x69\x6e\x70\x75\x74\x2d\x74\x65\x73\x74\x00\x00\x00\xb4\x00\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x06\x08\x00\x01\x00\x00\x00\x00\x01\x30\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x24\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x10\x00\x03\x80\x0c\x00\x01\x00\x74\x65\x73\x74\x54\x75\x6e\x6e\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-input-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookInput,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addAcceptIncomingPacketRule(testConn, table, chain, "testTunn")
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddMatchSubnetRouteMarkRuleMasq(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-nat-test
- []byte("\x02\x00\x00\x00\x10\x00\x01\x00\x74\x73\x2d\x6e\x61\x74\x2d\x74\x65\x73\x74\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-nat-test ts-postrouting-test { type nat hook postrouting priority 100; }
- []byte("\x02\x00\x00\x00\x10\x00\x01\x00\x74\x73\x2d\x6e\x61\x74\x2d\x74\x65\x73\x74\x00\x18\x00\x03\x00\x74\x73\x2d\x70\x6f\x73\x74\x72\x6f\x75\x74\x69\x6e\x67\x2d\x74\x65\x73\x74\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x04\x08\x00\x02\x00\x00\x00\x00\x64\x08\x00\x07\x00\x6e\x61\x74\x00"),
- // nft add rule ip ts-nat-test ts-postrouting-test meta mark & 0x00ff0000 == 0x00040000 counter masquerade
- []byte("\x02\x00\x00\x00\x10\x00\x01\x00\x74\x73\x2d\x6e\x61\x74\x2d\x74\x65\x73\x74\x00\x18\x00\x02\x00\x74\x73\x2d\x70\x6f\x73\x74\x72\x6f\x75\x74\x69\x6e\x67\x2d\x74\x65\x73\x74\x00\xd8\x00\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x03\x08\x00\x01\x00\x00\x00\x00\x01\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\x00\xff\x00\x00\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x00\x00\x00\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\x00\x04\x00\x00\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x01\x80\x09\x00\x01\x00\x6d\x61\x73\x71\x00\x00\x00\x00\x04\x00\x02\x80"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-nat-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-postrouting-test",
- Table: table,
- Type: nftables.ChainTypeNAT,
- Hooknum: nftables.ChainHookPostrouting,
- Priority: nftables.ChainPriorityNATSource,
- })
- err := addMatchSubnetRouteMarkRule(testConn, table, chain, Masq)
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestDelMatchSubnetRouteMarkMasqRule(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- reply := [][]netlink.Message{
- nil,
- {{Header: netlink.Header{Length: 0x128, Type: 0xa06, Flags: 0x802, Sequence: 0xa213d55d, PID: 0x11e79}, Data: []uint8{0x2, 0x0, 0x0, 0x8c, 0xd, 0x0, 0x1, 0x0, 0x6e, 0x61, 0x74, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x2, 0x0, 0x74, 0x73, 0x2d, 0x70, 0x6f, 0x73, 0x74, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x0, 0xc, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xe0, 0x0, 0x4, 0x0, 0x24, 0x0, 0x1, 0x0, 0x9, 0x0, 0x1, 0x0, 0x6d, 0x65, 0x74, 0x61, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x2, 0x0, 0x8, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x3, 0x8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4c, 0x0, 0x1, 0x0, 0xc, 0x0, 0x1, 0x0, 0x62, 0x69, 0x74, 0x77, 0x69, 0x73, 0x65, 0x0, 0x3c, 0x0, 0x2, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x4, 0x8, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x4, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0, 0xff, 0x0, 0x0, 0xc, 0x0, 0x5, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x1, 0x0, 0x8, 0x0, 0x1, 0x0, 0x63, 0x6d, 0x70, 0x0, 0x20, 0x0, 0x2, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x8, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x3, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0, 0x4, 0x0, 0x0, 0x2c, 0x0, 0x1, 0x0, 0xc, 0x0, 0x1, 0x0, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x0, 0x1c, 0x0, 0x2, 0x0, 0xc, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x1, 0x0, 0x9, 0x0, 0x1, 0x0, 0x6d, 0x61, 0x73, 0x71, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x0}}},
- {{Header: netlink.Header{Length: 0x14, Type: 0x3, Flags: 0x2, Sequence: 0x311fdccb, PID: 0x11e79}, Data: []uint8{0x0, 0x0, 0x0, 0x0}}},
- {{Header: netlink.Header{Length: 0x24, Type: 0x2, Flags: 0x100, Sequence: 0x311fdccb, PID: 0x11e79}, Data: []uint8{0x0, 0x0, 0x0, 0x0, 0x48, 0x0, 0x0, 0x0, 0x8, 0xa, 0x5, 0x0, 0xcb, 0xdc, 0x1f, 0x31, 0x79, 0x1e, 0x1, 0x0}}},
- }
- want := [][]byte{
- // get rules in nat-test table ts-postrouting-test chain
- []byte("\x02\x00\x00\x00\x0d\x00\x01\x00\x6e\x61\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x00\x18\x00\x02\x00\x74\x73\x2d\x70\x6f\x73\x74\x72\x6f\x75\x74\x69\x6e\x67\x2d\x74\x65\x73\x74\x00"),
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft delete rule ip nat-test ts-postrouting-test handle 4
- []byte("\x02\x00\x00\x00\x0d\x00\x01\x00\x6e\x61\x74\x2d\x74\x65\x73\x74\x00\x00\x00\x00\x18\x00\x02\x00\x74\x73\x2d\x70\x6f\x73\x74\x72\x6f\x75\x74\x69\x6e\x67\x2d\x74\x65\x73\x74\x00\x0c\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x04"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- conn := newTestConn(t, want, reply)
- table := &nftables.Table{
- Family: proto,
- Name: "nat-test",
- }
- chain := &nftables.Chain{
- Name: "ts-postrouting-test",
- Table: table,
- Type: nftables.ChainTypeNAT,
- Hooknum: nftables.ChainHookPostrouting,
- Priority: nftables.ChainPriorityNATSource,
- }
- err := delMatchSubnetRouteMarkMasqRule(conn, table, chain)
- if err != nil {
- t.Fatal(err)
- }
- }
- func TestAddMatchSubnetRouteMarkRuleAccept(t *testing.T) {
- proto := nftables.TableFamilyIPv4
- want := [][]byte{
- // batch begin
- []byte("\x00\x00\x00\x0a"),
- // nft add table ip ts-filter-test
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x08\x00\x02\x00\x00\x00\x00\x00"),
- // nft add chain ip ts-filter-test ts-forward-test { type filter hook forward priority 0\; }
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x03\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\x14\x00\x04\x80\x08\x00\x01\x00\x00\x00\x00\x02\x08\x00\x02\x00\x00\x00\x00\x00\x0b\x00\x07\x00\x66\x69\x6c\x74\x65\x72\x00\x00"),
- // nft add rule ip ts-filter-test ts-forward-test meta mark and 0x00ff0000 eq 0x00040000 counter accept
- []byte("\x02\x00\x00\x00\x13\x00\x01\x00\x74\x73\x2d\x66\x69\x6c\x74\x65\x72\x2d\x74\x65\x73\x74\x00\x00\x14\x00\x02\x00\x74\x73\x2d\x66\x6f\x72\x77\x61\x72\x64\x2d\x74\x65\x73\x74\x00\xf4\x00\x04\x80\x24\x00\x01\x80\x09\x00\x01\x00\x6d\x65\x74\x61\x00\x00\x00\x00\x14\x00\x02\x80\x08\x00\x02\x00\x00\x00\x00\x03\x08\x00\x01\x00\x00\x00\x00\x01\x44\x00\x01\x80\x0c\x00\x01\x00\x62\x69\x74\x77\x69\x73\x65\x00\x34\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x01\x08\x00\x03\x00\x00\x00\x00\x04\x0c\x00\x04\x80\x08\x00\x01\x00\x00\xff\x00\x00\x0c\x00\x05\x80\x08\x00\x01\x00\x00\x00\x00\x00\x2c\x00\x01\x80\x08\x00\x01\x00\x63\x6d\x70\x00\x20\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01\x08\x00\x02\x00\x00\x00\x00\x00\x0c\x00\x03\x80\x08\x00\x01\x00\x00\x04\x00\x00\x2c\x00\x01\x80\x0c\x00\x01\x00\x63\x6f\x75\x6e\x74\x65\x72\x00\x1c\x00\x02\x80\x0c\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x01\x80\x0e\x00\x01\x00\x69\x6d\x6d\x65\x64\x69\x61\x74\x65\x00\x00\x00\x1c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x00\x10\x00\x02\x80\x0c\x00\x02\x80\x08\x00\x01\x00\x00\x00\x00\x01"),
- // batch end
- []byte("\x00\x00\x00\x0a"),
- }
- testConn := newTestConn(t, want, nil)
- table := testConn.AddTable(&nftables.Table{
- Family: proto,
- Name: "ts-filter-test",
- })
- chain := testConn.AddChain(&nftables.Chain{
- Name: "ts-forward-test",
- Table: table,
- Type: nftables.ChainTypeFilter,
- Hooknum: nftables.ChainHookForward,
- Priority: nftables.ChainPriorityFilter,
- })
- err := addMatchSubnetRouteMarkRule(testConn, table, chain, Accept)
- if err != nil {
- t.Fatal(err)
- }
- }
- func newSysConn(t *testing.T) *nftables.Conn {
- t.Helper()
- if os.Geteuid() != 0 {
- t.Skip(t.Name(), " requires privileges to create a namespace in order to run")
- return nil
- }
- runtime.LockOSThread()
- ns, err := netns.New()
- if err != nil {
- t.Fatalf("netns.New() failed: %v", err)
- }
- c, err := nftables.New(nftables.WithNetNSFd(int(ns)))
- if err != nil {
- t.Fatalf("nftables.New() failed: %v", err)
- }
- t.Cleanup(func() { cleanupSysConn(t, ns) })
- return c
- }
- func cleanupSysConn(t *testing.T, ns netns.NsHandle) {
- defer runtime.UnlockOSThread()
- if err := ns.Close(); err != nil {
- t.Fatalf("newNS.Close() failed: %v", err)
- }
- }
- func checkChains(t *testing.T, conn *nftables.Conn, fam nftables.TableFamily, wantCount int) {
- t.Helper()
- got, err := conn.ListChainsOfTableFamily(fam)
- if err != nil {
- t.Fatalf("conn.ListChainsOfTableFamily(%v) failed: %v", fam, err)
- }
- if len(got) != wantCount {
- t.Fatalf("len(got) = %d, want %d", len(got), wantCount)
- }
- }
- func checkTables(t *testing.T, conn *nftables.Conn, fam nftables.TableFamily, wantCount int) {
- t.Helper()
- got, err := conn.ListTablesOfFamily(fam)
- if err != nil {
- t.Fatalf("conn.ListTablesOfFamily(%v) failed: %v", fam, err)
- }
- if len(got) != wantCount {
- t.Fatalf("len(got) = %d, want %d", len(got), wantCount)
- }
- }
- func TestAddAndDelNetfilterChains(t *testing.T) {
- type test struct {
- hostHasIPv6 bool
- initIPv4ChainCount int
- initIPv6ChainCount int
- ipv4TableCount int
- ipv6TableCount int
- ipv4ChainCount int
- ipv6ChainCount int
- ipv4ChainCountPostDelete int
- ipv6ChainCountPostDelete int
- }
- tests := []test{
- {
- hostHasIPv6: true,
- initIPv4ChainCount: 0,
- initIPv6ChainCount: 0,
- ipv4TableCount: 2,
- ipv6TableCount: 2,
- ipv4ChainCount: 6,
- ipv6ChainCount: 6,
- ipv4ChainCountPostDelete: 3,
- ipv6ChainCountPostDelete: 3,
- },
- { // host without IPv6 support
- ipv4TableCount: 2,
- ipv4ChainCount: 6,
- ipv4ChainCountPostDelete: 3,
- }}
- for _, tt := range tests {
- t.Logf("running a test case for IPv6 support: %v", tt.hostHasIPv6)
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, tt.hostHasIPv6)
- // Check that we start off with no chains.
- checkChains(t, conn, nftables.TableFamilyIPv4, tt.initIPv4ChainCount)
- checkChains(t, conn, nftables.TableFamilyIPv6, tt.initIPv6ChainCount)
- if err := runner.AddChains(); err != nil {
- t.Fatalf("runner.AddChains() failed: %v", err)
- }
- // Check that the amount of tables for each IP family is as expected.
- checkTables(t, conn, nftables.TableFamilyIPv4, tt.ipv4TableCount)
- checkTables(t, conn, nftables.TableFamilyIPv6, tt.ipv6TableCount)
- // Check that the amount of chains for each IP family is as expected.
- checkChains(t, conn, nftables.TableFamilyIPv4, tt.ipv4ChainCount)
- checkChains(t, conn, nftables.TableFamilyIPv6, tt.ipv6ChainCount)
- if err := runner.DelChains(); err != nil {
- t.Fatalf("runner.DelChains() failed: %v", err)
- }
- // Test that the tables as well as the default chains are still present.
- checkChains(t, conn, nftables.TableFamilyIPv4, tt.ipv4ChainCountPostDelete)
- checkChains(t, conn, nftables.TableFamilyIPv6, tt.ipv6ChainCountPostDelete)
- checkTables(t, conn, nftables.TableFamilyIPv4, tt.ipv4TableCount)
- checkTables(t, conn, nftables.TableFamilyIPv6, tt.ipv6TableCount)
- }
- }
- func getTsChains(
- conn *nftables.Conn,
- proto nftables.TableFamily) (*nftables.Chain, *nftables.Chain, *nftables.Chain, error) {
- chains, err := conn.ListChainsOfTableFamily(nftables.TableFamilyIPv4)
- if err != nil {
- return nil, nil, nil, fmt.Errorf("list chains failed: %w", err)
- }
- var chainInput, chainForward, chainPostrouting *nftables.Chain
- for _, chain := range chains {
- switch chain.Name {
- case "ts-input":
- chainInput = chain
- case "ts-forward":
- chainForward = chain
- case "ts-postrouting":
- chainPostrouting = chain
- }
- }
- return chainInput, chainForward, chainPostrouting, nil
- }
- // findV4BaseRules verifies that the base rules are present in the input and forward chains.
- func findV4BaseRules(
- conn *nftables.Conn,
- inpChain *nftables.Chain,
- forwChain *nftables.Chain,
- tunname string) ([]*nftables.Rule, error) {
- want := []*nftables.Rule{}
- rule, err := createRangeRule(inpChain.Table, inpChain, tunname, tsaddr.ChromeOSVMRange(), expr.VerdictReturn)
- if err != nil {
- return nil, fmt.Errorf("create rule: %w", err)
- }
- want = append(want, rule)
- rule, err = createRangeRule(inpChain.Table, inpChain, tunname, tsaddr.CGNATRange(), expr.VerdictDrop)
- if err != nil {
- return nil, fmt.Errorf("create rule: %w", err)
- }
- want = append(want, rule)
- rule, err = createDropOutgoingPacketFromCGNATRangeRuleWithTunname(forwChain.Table, forwChain, tunname)
- if err != nil {
- return nil, fmt.Errorf("create rule: %w", err)
- }
- want = append(want, rule)
- get := []*nftables.Rule{}
- for _, rule := range want {
- getRule, err := findRule(conn, rule)
- if err != nil {
- return nil, fmt.Errorf("find rule: %w", err)
- }
- get = append(get, getRule)
- }
- return get, nil
- }
- func findCommonBaseRules(
- conn *nftables.Conn,
- forwChain *nftables.Chain,
- tunname string) ([]*nftables.Rule, error) {
- want := []*nftables.Rule{}
- rule, err := createSetSubnetRouteMarkRule(forwChain.Table, forwChain, tunname)
- if err != nil {
- return nil, fmt.Errorf("create rule: %w", err)
- }
- want = append(want, rule)
- rule, err = createMatchSubnetRouteMarkRule(forwChain.Table, forwChain, Accept)
- if err != nil {
- return nil, fmt.Errorf("create rule: %w", err)
- }
- want = append(want, rule)
- rule = createAcceptOutgoingPacketRule(forwChain.Table, forwChain, tunname)
- want = append(want, rule)
- get := []*nftables.Rule{}
- for _, rule := range want {
- getRule, err := findRule(conn, rule)
- if err != nil {
- return nil, fmt.Errorf("find rule: %w", err)
- }
- get = append(get, getRule)
- }
- return get, nil
- }
- // checkChainRules verifies that the chain has the expected number of rules.
- func checkChainRules(t *testing.T, conn *nftables.Conn, chain *nftables.Chain, wantCount int) {
- t.Helper()
- got, err := conn.GetRules(chain.Table, chain)
- if err != nil {
- t.Fatalf("conn.GetRules() failed: %v", err)
- }
- if len(got) != wantCount {
- t.Fatalf("got = %d, want %d", len(got), wantCount)
- }
- }
- func TestNFTAddAndDelNetfilterBase(t *testing.T) {
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, true)
- if err := runner.AddChains(); err != nil {
- t.Fatalf("AddChains() failed: %v", err)
- }
- defer runner.DelChains()
- if err := runner.AddBase("testTunn"); err != nil {
- t.Fatalf("AddBase() failed: %v", err)
- }
- // check number of rules in each IPv4 TS chain
- inputV4, forwardV4, postroutingV4, err := getTsChains(conn, nftables.TableFamilyIPv4)
- if err != nil {
- t.Fatalf("getTsChains() failed: %v", err)
- }
- checkChainRules(t, conn, inputV4, 3)
- checkChainRules(t, conn, forwardV4, 4)
- checkChainRules(t, conn, postroutingV4, 0)
- _, err = findV4BaseRules(conn, inputV4, forwardV4, "testTunn")
- if err != nil {
- t.Fatalf("missing v4 base rule: %v", err)
- }
- _, err = findCommonBaseRules(conn, forwardV4, "testTunn")
- if err != nil {
- t.Fatalf("missing v4 base rule: %v", err)
- }
- // Check number of rules in each IPv6 TS chain.
- inputV6, forwardV6, postroutingV6, err := getTsChains(conn, nftables.TableFamilyIPv6)
- if err != nil {
- t.Fatalf("getTsChains() failed: %v", err)
- }
- checkChainRules(t, conn, inputV6, 3)
- checkChainRules(t, conn, forwardV6, 4)
- checkChainRules(t, conn, postroutingV6, 0)
- _, err = findCommonBaseRules(conn, forwardV6, "testTunn")
- if err != nil {
- t.Fatalf("missing v6 base rule: %v", err)
- }
- runner.DelBase()
- chains, err := conn.ListChains()
- if err != nil {
- t.Fatalf("conn.ListChains() failed: %v", err)
- }
- for _, chain := range chains {
- checkChainRules(t, conn, chain, 0)
- }
- }
- func findLoopBackRule(conn *nftables.Conn, proto nftables.TableFamily, table *nftables.Table, chain *nftables.Chain, addr netip.Addr) (*nftables.Rule, error) {
- matchingAddr := addr.AsSlice()
- saddrExpr, err := newLoadSaddrExpr(proto, 1)
- if err != nil {
- return nil, fmt.Errorf("get expr: %w", err)
- }
- loopBackRule := &nftables.Rule{
- Table: table,
- Chain: chain,
- Exprs: []expr.Any{
- &expr.Meta{
- Key: expr.MetaKeyIIFNAME,
- Register: 1,
- },
- &expr.Cmp{
- Op: expr.CmpOpEq,
- Register: 1,
- Data: []byte("lo"),
- },
- saddrExpr,
- &expr.Cmp{
- Op: expr.CmpOpEq,
- Register: 1,
- Data: matchingAddr,
- },
- &expr.Counter{},
- &expr.Verdict{
- Kind: expr.VerdictAccept,
- },
- },
- }
- existingLoopBackRule, err := findRule(conn, loopBackRule)
- if err != nil {
- return nil, fmt.Errorf("find loop back rule: %w", err)
- }
- return existingLoopBackRule, nil
- }
- func TestNFTAddAndDelLoopbackRule(t *testing.T) {
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, true)
- if err := runner.AddChains(); err != nil {
- t.Fatalf("AddChains() failed: %v", err)
- }
- defer runner.DelChains()
- inputV4, _, _, err := getTsChains(conn, nftables.TableFamilyIPv4)
- if err != nil {
- t.Fatalf("getTsChains() failed: %v", err)
- }
- inputV6, _, _, err := getTsChains(conn, nftables.TableFamilyIPv6)
- if err != nil {
- t.Fatalf("getTsChains() failed: %v", err)
- }
- checkChainRules(t, conn, inputV4, 0)
- checkChainRules(t, conn, inputV6, 0)
- runner.AddBase("testTunn")
- defer runner.DelBase()
- checkChainRules(t, conn, inputV4, 3)
- checkChainRules(t, conn, inputV6, 3)
- addr := netip.MustParseAddr("192.168.0.2")
- addrV6 := netip.MustParseAddr("2001:db8::2")
- runner.AddLoopbackRule(addr)
- runner.AddLoopbackRule(addrV6)
- checkChainRules(t, conn, inputV4, 4)
- checkChainRules(t, conn, inputV6, 4)
- existingLoopBackRule, err := findLoopBackRule(conn, nftables.TableFamilyIPv4, runner.nft4.Filter, inputV4, addr)
- if err != nil {
- t.Fatalf("findLoopBackRule() failed: %v", err)
- }
- if existingLoopBackRule.Position != 0 {
- t.Fatalf("existingLoopBackRule.Handle = %d, want 0", existingLoopBackRule.Handle)
- }
- existingLoopBackRuleV6, err := findLoopBackRule(conn, nftables.TableFamilyIPv6, runner.nft6.Filter, inputV6, addrV6)
- if err != nil {
- t.Fatalf("findLoopBackRule() failed: %v", err)
- }
- if existingLoopBackRuleV6.Position != 0 {
- t.Fatalf("existingLoopBackRule.Handle = %d, want 0", existingLoopBackRule.Handle)
- }
- runner.DelLoopbackRule(addr)
- runner.DelLoopbackRule(addrV6)
- checkChainRules(t, conn, inputV4, 3)
- checkChainRules(t, conn, inputV6, 3)
- }
- func TestNFTAddAndDelHookRule(t *testing.T) {
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, true)
- if err := runner.AddChains(); err != nil {
- t.Fatalf("AddChains() failed: %v", err)
- }
- defer runner.DelChains()
- if err := runner.AddHooks(); err != nil {
- t.Fatalf("AddHooks() failed: %v", err)
- }
- forwardChain, err := getChainFromTable(conn, runner.nft4.Filter, "FORWARD")
- if err != nil {
- t.Fatalf("failed to get forwardChain: %v", err)
- }
- inputChain, err := getChainFromTable(conn, runner.nft4.Filter, "INPUT")
- if err != nil {
- t.Fatalf("failed to get inputChain: %v", err)
- }
- postroutingChain, err := getChainFromTable(conn, runner.nft4.Nat, "POSTROUTING")
- if err != nil {
- t.Fatalf("failed to get postroutingChain: %v", err)
- }
- checkChainRules(t, conn, forwardChain, 1)
- checkChainRules(t, conn, inputChain, 1)
- checkChainRules(t, conn, postroutingChain, 1)
- runner.DelHooks(t.Logf)
- checkChainRules(t, conn, forwardChain, 0)
- checkChainRules(t, conn, inputChain, 0)
- checkChainRules(t, conn, postroutingChain, 0)
- }
- type testFWDetector struct {
- iptRuleCount, nftRuleCount int
- iptErr, nftErr error
- }
- func (t *testFWDetector) iptDetect() (int, error) {
- return t.iptRuleCount, t.iptErr
- }
- func (t *testFWDetector) nftDetect() (int, error) {
- return t.nftRuleCount, t.nftErr
- }
- // TestCreateDummyPostroutingChains tests that on a system with nftables
- // available, the function does not return an error and that the dummy
- // postrouting chains are cleaned up.
- func TestCreateDummyPostroutingChains(t *testing.T) {
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, true)
- if err := runner.createDummyPostroutingChains(); err != nil {
- t.Fatalf("createDummyPostroutingChains() failed: %v", err)
- }
- for _, table := range runner.getTables() {
- nt, err := getTableIfExists(conn, table.Proto, tsDummyTableName)
- if err != nil {
- t.Fatalf("getTableIfExists() failed: %v", err)
- }
- if nt != nil {
- t.Fatalf("expected table to be nil, got %v", nt)
- }
- }
- }
- func TestPickFirewallModeFromInstalledRules(t *testing.T) {
- tests := []struct {
- name string
- det *testFWDetector
- want FirewallMode
- }{
- {
- name: "using iptables legacy",
- det: &testFWDetector{iptRuleCount: 1},
- want: FirewallModeIPTables,
- },
- {
- name: "using nftables",
- det: &testFWDetector{nftRuleCount: 1},
- want: FirewallModeNfTables,
- },
- {
- name: "using both iptables and nftables",
- det: &testFWDetector{iptRuleCount: 2, nftRuleCount: 2},
- want: FirewallModeNfTables,
- },
- {
- name: "not using any firewall, both available",
- det: &testFWDetector{},
- want: FirewallModeNfTables,
- },
- {
- name: "not using any firewall, iptables available only",
- det: &testFWDetector{iptRuleCount: 1, nftErr: errors.New("nft error")},
- want: FirewallModeIPTables,
- },
- {
- name: "not using any firewall, nftables available only",
- det: &testFWDetector{iptErr: errors.New("iptables error"), nftRuleCount: 1},
- want: FirewallModeNfTables,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := pickFirewallModeFromInstalledRules(t.Logf, tt.det)
- if got != tt.want {
- t.Errorf("chooseFireWallMode() = %v, want %v", got, tt.want)
- }
- })
- }
- }
- // This test creates a temporary network namespace for the nftables rules being
- // set up, so it needs to run in a privileged mode. Locally it needs to be run
- // by root, else it will be silently skipped. In CI it runs in a privileged
- // container.
- func TestEnsureSNATForDst_nftables(t *testing.T) {
- conn := newSysConn(t)
- runner := newFakeNftablesRunnerWithConn(t, conn, true)
- ip1, ip2, ip3 := netip.MustParseAddr("100.99.99.99"), netip.MustParseAddr("100.88.88.88"), netip.MustParseAddr("100.77.77.77")
- // 1. A new rule gets added
- mustCreateSNATRule_nft(t, runner, ip1, ip2)
- chainRuleCount(t, "POSTROUTING", 1, conn, nftables.TableFamilyIPv4)
- checkSNATRule_nft(t, runner, runner.nft4.Proto, ip1, ip2)
- // 2. Another call to EnsureSNATForDst with the same src and dst does not result in another rule being added.
- mustCreateSNATRule_nft(t, runner, ip1, ip2)
- chainRuleCount(t, "POSTROUTING", 1, conn, nftables.TableFamilyIPv4) // still just one rule
- checkSNATRule_nft(t, runner, runner.nft4.Proto, ip1, ip2)
- // 3. Another call to EnsureSNATForDst with a different src and the same dst results in the earlier rule being
- // deleted.
- mustCreateSNATRule_nft(t, runner, ip3, ip2)
- chainRuleCount(t, "POSTROUTING", 1, conn, nftables.TableFamilyIPv4) // still just one rule
- checkSNATRule_nft(t, runner, runner.nft4.Proto, ip3, ip2)
- // 4. Another call to EnsureSNATForDst with a different dst should not get the earlier rule deleted.
- mustCreateSNATRule_nft(t, runner, ip3, ip1)
- chainRuleCount(t, "POSTROUTING", 2, conn, nftables.TableFamilyIPv4) // now two rules
- checkSNATRule_nft(t, runner, runner.nft4.Proto, ip3, ip1)
- }
- func newFakeNftablesRunnerWithConn(t *testing.T, conn *nftables.Conn, hasIPv6 bool) *nftablesRunner {
- t.Helper()
- if !hasIPv6 {
- tstest.Replace(t, &checkIPv6ForTest, func(logger.Logf) error {
- return errors.New("test: no IPv6")
- })
- }
- return newNfTablesRunnerWithConn(t.Logf, conn)
- }
- func mustCreateSNATRule_nft(t *testing.T, runner *nftablesRunner, src, dst netip.Addr) {
- t.Helper()
- if err := runner.EnsureSNATForDst(src, dst); err != nil {
- t.Fatalf("error ensuring SNAT rule: %v", err)
- }
- }
- // checkSNATRule_nft verifies that a SNAT rule for the given destination and source exists.
- func checkSNATRule_nft(t *testing.T, runner *nftablesRunner, fam nftables.TableFamily, src, dst netip.Addr) {
- t.Helper()
- chains, err := runner.conn.ListChainsOfTableFamily(fam)
- if err != nil {
- t.Fatalf("error listing chains: %v", err)
- }
- var chain *nftables.Chain
- for _, ch := range chains {
- if ch.Name == "POSTROUTING" {
- chain = ch
- break
- }
- }
- if chain == nil {
- t.Fatal("POSTROUTING chain does not exist")
- }
- meta := []byte(fmt.Sprintf("dst:%s,src:%s", dst.String(), src.String()))
- wantsRule := snatRule(chain.Table, chain, src, dst, meta)
- checkRule(t, wantsRule, runner.conn)
- }
|