diff --git a/expr/bitwise.go b/expr/bitwise.go index 6196da6..4bb55a8 100644 --- a/expr/bitwise.go +++ b/expr/bitwise.go @@ -15,7 +15,7 @@ package expr import ( - "fmt" + "encoding/binary" "github.com/google/nftables/binaryutil" "github.com/mdlayher/netlink" @@ -61,5 +61,42 @@ func (e *Bitwise) marshal() ([]byte, error) { } func (e *Bitwise) unmarshal(data []byte) error { - return fmt.Errorf("not yet implemented") + ad, err := netlink.NewAttributeDecoder(data) + if err != nil { + return err + } + ad.ByteOrder = binary.BigEndian + for ad.Next() { + switch ad.Type() { + case unix.NFTA_BITWISE_SREG: + e.SourceRegister = ad.Uint32() + case unix.NFTA_BITWISE_DREG: + e.DestRegister = ad.Uint32() + case unix.NFTA_BITWISE_LEN: + e.Len = ad.Uint32() + case unix.NFTA_BITWISE_MASK: + // Since NFTA_BITWISE_MASK is nested, it requires additional decoding + ad.Nested(func(nad *netlink.AttributeDecoder) error { + for nad.Next() { + switch nad.Type() { + case unix.NFTA_DATA_VALUE: + e.Mask = nad.Bytes() + } + } + return nil + }) + case unix.NFTA_BITWISE_XOR: + // Since NFTA_BITWISE_XOR is nested, it requires additional decoding + ad.Nested(func(nad *netlink.AttributeDecoder) error { + for nad.Next() { + switch nad.Type() { + case unix.NFTA_DATA_VALUE: + e.Xor = nad.Bytes() + } + } + return nil + }) + } + } + return ad.Err() } diff --git a/expr/bitwise_test.go b/expr/bitwise_test.go new file mode 100644 index 0000000..3a71e48 --- /dev/null +++ b/expr/bitwise_test.go @@ -0,0 +1,58 @@ +package expr + +import ( + "encoding/binary" + "reflect" + "testing" + + "github.com/mdlayher/netlink" + "golang.org/x/sys/unix" +) + +func TestBitwise(t *testing.T) { + t.Parallel() + tests := []struct { + name string + bw Bitwise + }{ + { + name: "Unmarshal Bitwise IPv4 case", + bw: Bitwise{ + SourceRegister: 1, + DestRegister: 2, + Len: 4, + // By specifying Xor to 0x0,0x0,0x0,0x0 and Mask to 0xff,0xff,0x0,0x0 + // an expression will match /16 IPv4 address. + Xor: []byte{0x0, 0x0, 0x0, 0x0}, + Mask: []byte{0xff, 0xff, 0x0, 0x0}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nbw := Bitwise{} + data, err := tt.bw.marshal() + if err != nil { + t.Fatalf("marshal error: %+v", err) + + } + ad, err := netlink.NewAttributeDecoder(data) + if err != nil { + t.Fatalf("NewAttributeDecoder() error: %+v", err) + } + ad.ByteOrder = binary.BigEndian + for ad.Next() { + if ad.Type() == unix.NFTA_EXPR_DATA { + if err := nbw.unmarshal(ad.Bytes()); err != nil { + t.Errorf("unmarshal error: %+v", err) + break + } + } + } + if !reflect.DeepEqual(tt.bw, nbw) { + t.Fatalf("original %+v and recovered %+v Bitwise structs are different", tt.bw, nbw) + } + }) + } +} diff --git a/go.mod b/go.mod index 92e227f..dfd5143 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,8 @@ go 1.12 require ( github.com/koneu/natend v0.0.0-20150829182554-ec0926ea948d - github.com/mdlayher/netlink v0.0.0-20190516121005-0087c778e469 + github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc - golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5 + golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect + golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c ) diff --git a/go.sum b/go.sum index 1594ec2..e0e4d0d 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,26 @@ -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/koneu/natend v0.0.0-20150829182554-ec0926ea948d h1:MFX8DxRnKMY/2M3H61iSsVbo/n3h0MWGmWNN1UViOU0= github.com/koneu/natend v0.0.0-20150829182554-ec0926ea948d/go.mod h1:QHb4k4cr1fQikUahfcRVPcEXiUgFsdIstGqlurL0XL4= -github.com/mdlayher/netlink v0.0.0-20190516121005-0087c778e469 h1:6XwSkpIirmRxmstYmbL5PshChpqazkNfFNJ+Uj1iJlU= -github.com/mdlayher/netlink v0.0.0-20190516121005-0087c778e469/go.mod h1:gOrA34zDL0K3RsACQe54bDYLF/CeFspQ9m5DOycycQ8= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b h1:W3er9pI7mt2gOqOWzwvx20iJ8Akiqz1mUMTxU6wdvl8= +github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak= -golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5 h1:sM3evRHxE/1RuMe1FYAL3j7C7fUfIjkbE+NiDAYUF8U= -golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/rule.go b/rule.go index 8178749..a450182 100644 --- a/rule.go +++ b/rule.go @@ -190,6 +190,8 @@ func exprsFromMsg(b []byte) ([]expr.Any, error) { e = &expr.Lookup{} case "immediate": e = &expr.Immediate{} + case "bitwise": + e = &expr.Bitwise{} } if e == nil { // TODO: introduce an opaque expression type so that users know