Compare commits

...

3 Commits

Author SHA1 Message Date
turekt fb79e6f97f
Merge b77f1a918e into 20edd38e22 2024-04-19 18:56:04 +00:00
turekt b77f1a918e Objects implementation refactor
Refactored obj.go to a more generic approach
Added object support for already implemented expressions
Added test for limit object
Fixes https://github.com/google/nftables/issues/253
2024-04-19 18:55:24 +00:00
dependabot[bot] 20edd38e22
Bump golang.org/x/net from 0.22.0 to 0.23.0 (#261)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 19:12:50 +02:00
40 changed files with 730 additions and 377 deletions

View File

@ -16,11 +16,12 @@ package nftables
import ( import (
"github.com/google/nftables/binaryutil" "github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/mdlayher/netlink" "github.com/mdlayher/netlink"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// CounterObj implements Obj. // Deprecated: Use ObjAttr instead
type CounterObj struct { type CounterObj struct {
Table *Table Table *Table
Name string // e.g. “fwded” Name string // e.g. “fwded”
@ -41,6 +42,20 @@ func (c *CounterObj) unmarshal(ad *netlink.AttributeDecoder) error {
return ad.Err() return ad.Err()
} }
func (c *CounterObj) data() expr.Any {
return &expr.Counter{
Bytes: c.Bytes,
Packets: c.Packets,
}
}
func (c *CounterObj) name() string {
return c.Name
}
func (c *CounterObj) objType() ObjType {
return ObjTypeCounter
}
func (c *CounterObj) table() *Table { func (c *CounterObj) table() *Table {
return c.Table return c.Table
} }

View File

@ -31,6 +31,17 @@ type Bitwise struct {
} }
func (e *Bitwise) marshal(fam byte) ([]byte, error) { func (e *Bitwise) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("bitwise\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Bitwise) marshalData(fam byte) ([]byte, error) {
mask, err := netlink.MarshalAttributes([]netlink.Attribute{ mask, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Mask}, {Type: unix.NFTA_DATA_VALUE, Data: e.Mask},
}) })
@ -44,20 +55,13 @@ func (e *Bitwise) marshal(fam byte) ([]byte, error) {
return nil, err return nil, err
} }
data, err := netlink.MarshalAttributes([]netlink.Attribute{ return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_BITWISE_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)}, {Type: unix.NFTA_BITWISE_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
{Type: unix.NFTA_BITWISE_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)}, {Type: unix.NFTA_BITWISE_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
{Type: unix.NFTA_BITWISE_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)}, {Type: unix.NFTA_BITWISE_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
{Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_MASK, Data: mask}, {Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_MASK, Data: mask},
{Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_XOR, Data: xor}, {Type: unix.NLA_F_NESTED | unix.NFTA_BITWISE_XOR, Data: xor},
}) })
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("bitwise\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Bitwise) unmarshal(fam byte, data []byte) error { func (e *Bitwise) unmarshal(fam byte, data []byte) error {

View File

@ -38,13 +38,7 @@ type Byteorder struct {
} }
func (e *Byteorder) marshal(fam byte) ([]byte, error) { func (e *Byteorder) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_BYTEORDER_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
{Type: unix.NFTA_BYTEORDER_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
{Type: unix.NFTA_BYTEORDER_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NFTA_BYTEORDER_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
{Type: unix.NFTA_BYTEORDER_SIZE, Data: binaryutil.BigEndian.PutUint32(e.Size)},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -54,6 +48,16 @@ func (e *Byteorder) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Byteorder) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_BYTEORDER_SREG, Data: binaryutil.BigEndian.PutUint32(e.SourceRegister)},
{Type: unix.NFTA_BYTEORDER_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)},
{Type: unix.NFTA_BYTEORDER_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NFTA_BYTEORDER_LEN, Data: binaryutil.BigEndian.PutUint32(e.Len)},
{Type: unix.NFTA_BYTEORDER_SIZE, Data: binaryutil.BigEndian.PutUint32(e.Size)},
})
}
func (e *Byteorder) unmarshal(fam byte, data []byte) error { func (e *Byteorder) unmarshal(fam byte, data []byte) error {
return fmt.Errorf("not yet implemented") return fmt.Errorf("not yet implemented")
} }

View File

@ -37,10 +37,7 @@ type Connlimit struct {
} }
func (e *Connlimit) marshal(fam byte) ([]byte, error) { func (e *Connlimit) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: NFTA_CONNLIMIT_COUNT, Data: binaryutil.BigEndian.PutUint32(e.Count)},
{Type: NFTA_CONNLIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,6 +48,13 @@ func (e *Connlimit) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Connlimit) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: NFTA_CONNLIMIT_COUNT, Data: binaryutil.BigEndian.PutUint32(e.Count)},
{Type: NFTA_CONNLIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)},
})
}
func (e *Connlimit) unmarshal(fam byte, data []byte) error { func (e *Connlimit) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -28,10 +28,7 @@ type Counter struct {
} }
func (e *Counter) marshal(fam byte) ([]byte, error) { func (e *Counter) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_COUNTER_BYTES, Data: binaryutil.BigEndian.PutUint64(e.Bytes)},
{Type: unix.NFTA_COUNTER_PACKETS, Data: binaryutil.BigEndian.PutUint64(e.Packets)},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -42,6 +39,13 @@ func (e *Counter) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Counter) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_COUNTER_BYTES, Data: binaryutil.BigEndian.PutUint64(e.Bytes)},
{Type: unix.NFTA_COUNTER_PACKETS, Data: binaryutil.BigEndian.PutUint64(e.Packets)},
})
}
func (e *Counter) unmarshal(fam byte, data []byte) error { func (e *Counter) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -64,7 +64,19 @@ type Ct struct {
} }
func (e *Ct) marshal(fam byte) ([]byte, error) { func (e *Ct) marshal(fam byte) ([]byte, error) {
regData := []byte{} exprData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("ct\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Ct) marshalData(fam byte) ([]byte, error) {
var regData []byte
exprData, err := netlink.MarshalAttributes( exprData, err := netlink.MarshalAttributes(
[]netlink.Attribute{ []netlink.Attribute{
{Type: unix.NFTA_CT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))}, {Type: unix.NFTA_CT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
@ -90,11 +102,7 @@ func (e *Ct) marshal(fam byte) ([]byte, error) {
return nil, err return nil, err
} }
exprData = append(exprData, regData...) exprData = append(exprData, regData...)
return exprData, nil
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("ct\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
} }
func (e *Ct) unmarshal(fam byte, data []byte) error { func (e *Ct) unmarshal(fam byte, data []byte) error {

View File

@ -29,16 +29,7 @@ type Dup struct {
} }
func (e *Dup) marshal(fam byte) ([]byte, error) { func (e *Dup) marshal(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_DUP_SREG_ADDR, Data: binaryutil.BigEndian.PutUint32(e.RegAddr)},
}
if e.IsRegDevSet {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_DUP_SREG_DEV, Data: binaryutil.BigEndian.PutUint32(e.RegDev)})
}
data, err := netlink.MarshalAttributes(attrs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -49,6 +40,18 @@ func (e *Dup) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Dup) marshalData(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{
{Type: unix.NFTA_DUP_SREG_ADDR, Data: binaryutil.BigEndian.PutUint32(e.RegAddr)},
}
if e.IsRegDevSet {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_DUP_SREG_DEV, Data: binaryutil.BigEndian.PutUint32(e.RegDev)})
}
return netlink.MarshalAttributes(attrs)
}
func (e *Dup) unmarshal(fam byte, data []byte) error { func (e *Dup) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -44,6 +44,18 @@ type Dynset struct {
} }
func (e *Dynset) marshal(fam byte) ([]byte, error) { func (e *Dynset) marshal(fam byte) ([]byte, error) {
opData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("dynset\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
}
func (e *Dynset) marshalData(fam byte) ([]byte, error) {
// See: https://git.netfilter.org/libnftnl/tree/src/expr/dynset.c // See: https://git.netfilter.org/libnftnl/tree/src/expr/dynset.c
var opAttrs []netlink.Attribute var opAttrs []netlink.Attribute
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_SREG_KEY, Data: binaryutil.BigEndian.PutUint32(e.SrcRegKey)}) opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_SREG_KEY, Data: binaryutil.BigEndian.PutUint32(e.SrcRegKey)})
@ -89,17 +101,9 @@ func (e *Dynset) marshal(fam byte) ([]byte, error) {
opAttrs = append(opAttrs, netlink.Attribute{Type: NFTA_DYNSET_EXPRESSIONS, Data: elemData}) opAttrs = append(opAttrs, netlink.Attribute{Type: NFTA_DYNSET_EXPRESSIONS, Data: elemData})
} }
} }
opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)}) opAttrs = append(opAttrs, netlink.Attribute{Type: unix.NFTA_DYNSET_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)})
return netlink.MarshalAttributes(opAttrs)
opData, err := netlink.MarshalAttributes(opAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("dynset\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
} }
func (e *Dynset) unmarshal(fam byte, data []byte) error { func (e *Dynset) unmarshal(fam byte, data []byte) error {
@ -125,7 +129,7 @@ func (e *Dynset) unmarshal(fam byte, data []byte) error {
case unix.NFTA_DYNSET_FLAGS: case unix.NFTA_DYNSET_FLAGS:
e.Invert = (ad.Uint32() & unix.NFT_DYNSET_F_INV) != 0 e.Invert = (ad.Uint32() & unix.NFT_DYNSET_F_INV) != 0
case unix.NFTA_DYNSET_EXPR: case unix.NFTA_DYNSET_EXPR:
exprs, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes()) exprs, err := parseexprfunc.ParseExprBytesFunc(fam, ad)
if err != nil { if err != nil {
return err return err
} }

View File

@ -25,8 +25,8 @@ import (
) )
func init() { func init() {
parseexprfunc.ParseExprBytesFunc = func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error) { parseexprfunc.ParseExprBytesFunc = func(fam byte, ad *netlink.AttributeDecoder, args ...string) ([]interface{}, error) {
exprs, err := exprsFromBytes(fam, ad, b) exprs, err := exprsFromBytes(fam, ad, args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -36,7 +36,7 @@ func init() {
} }
return result, nil return result, nil
} }
parseexprfunc.ParseExprMsgFunc = func(fam byte, b []byte) ([]interface{}, error) { parseexprfunc.ParseExprMsgFunc = func(fam byte, b []byte, args ...string) ([]interface{}, error) {
ad, err := netlink.NewAttributeDecoder(b) ad, err := netlink.NewAttributeDecoder(b)
if err != nil { if err != nil {
return nil, err return nil, err
@ -44,7 +44,7 @@ func init() {
ad.ByteOrder = binary.BigEndian ad.ByteOrder = binary.BigEndian
var exprs []interface{} var exprs []interface{}
for ad.Next() { for ad.Next() {
e, err := parseexprfunc.ParseExprBytesFunc(fam, ad, b) e, err := parseexprfunc.ParseExprBytesFunc(fam, ad, args...)
if err != nil { if err != nil {
return e, err return e, err
} }
@ -59,6 +59,10 @@ func Marshal(fam byte, e Any) ([]byte, error) {
return e.marshal(fam) return e.marshal(fam)
} }
func MarshalExprData(fam byte, e Any) ([]byte, error) {
return e.marshalData(fam)
}
// Unmarshal fills an expression from the specified byte slice. // Unmarshal fills an expression from the specified byte slice.
func Unmarshal(fam byte, data []byte, e Any) error { func Unmarshal(fam byte, data []byte, e Any) error {
return e.unmarshal(fam, data) return e.unmarshal(fam, data)
@ -66,8 +70,20 @@ func Unmarshal(fam byte, data []byte, e Any) error {
// exprsFromBytes parses nested raw expressions bytes // exprsFromBytes parses nested raw expressions bytes
// to construct nftables expressions // to construct nftables expressions
func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, error) { func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, args ...string) ([]Any, error) {
var exprs []Any var exprs []Any
if len(args) > 0 {
e := exprFromName(args[0])
ad.Do(func(b []byte) error {
if err := Unmarshal(fam, b, e); err != nil {
return err
}
exprs = append(exprs, e)
return nil
})
return exprs, ad.Err()
}
ad.Do(func(b []byte) error { ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b) ad, err := netlink.NewAttributeDecoder(b)
if err != nil { if err != nil {
@ -84,65 +100,12 @@ func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, er
exprs = append(exprs, e) exprs = append(exprs, e)
} }
case unix.NFTA_EXPR_DATA: case unix.NFTA_EXPR_DATA:
var e Any e := exprFromName(name)
switch name {
case "ct":
e = &Ct{}
case "range":
e = &Range{}
case "meta":
e = &Meta{}
case "cmp":
e = &Cmp{}
case "counter":
e = &Counter{}
case "objref":
e = &Objref{}
case "payload":
e = &Payload{}
case "lookup":
e = &Lookup{}
case "immediate":
e = &Immediate{}
case "bitwise":
e = &Bitwise{}
case "redir":
e = &Redir{}
case "nat":
e = &NAT{}
case "limit":
e = &Limit{}
case "quota":
e = &Quota{}
case "dynset":
e = &Dynset{}
case "log":
e = &Log{}
case "exthdr":
e = &Exthdr{}
case "match":
e = &Match{}
case "target":
e = &Target{}
case "connlimit":
e = &Connlimit{}
case "queue":
e = &Queue{}
case "flow_offload":
e = &FlowOffload{}
case "reject":
e = &Reject{}
case "masq":
e = &Masq{}
case "hash":
e = &Hash{}
}
if e == nil { if e == nil {
// TODO: introduce an opaque expression type so that users know // TODO: introduce an opaque expression type so that users know
// something is here. // something is here.
continue // unsupported expression type continue // unsupported expression type
} }
ad.Do(func(b []byte) error { ad.Do(func(b []byte) error {
if err := Unmarshal(fam, b, e); err != nil { if err := Unmarshal(fam, b, e); err != nil {
return err return err
@ -166,9 +129,67 @@ func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, er
return exprs, ad.Err() return exprs, ad.Err()
} }
func exprFromName(name string) Any {
var e Any
switch name {
case "ct":
e = &Ct{}
case "range":
e = &Range{}
case "meta":
e = &Meta{}
case "cmp":
e = &Cmp{}
case "counter":
e = &Counter{}
case "objref":
e = &Objref{}
case "payload":
e = &Payload{}
case "lookup":
e = &Lookup{}
case "immediate":
e = &Immediate{}
case "bitwise":
e = &Bitwise{}
case "redir":
e = &Redir{}
case "nat":
e = &NAT{}
case "limit":
e = &Limit{}
case "quota":
e = &Quota{}
case "dynset":
e = &Dynset{}
case "log":
e = &Log{}
case "exthdr":
e = &Exthdr{}
case "match":
e = &Match{}
case "target":
e = &Target{}
case "connlimit":
e = &Connlimit{}
case "queue":
e = &Queue{}
case "flow_offload":
e = &FlowOffload{}
case "reject":
e = &Reject{}
case "masq":
e = &Masq{}
case "hash":
e = &Hash{}
}
return e
}
// Any is an interface implemented by any expression type. // Any is an interface implemented by any expression type.
type Any interface { type Any interface {
marshal(fam byte) ([]byte, error) marshal(fam byte) ([]byte, error)
marshalData(fam byte) ([]byte, error)
unmarshal(fam byte, data []byte) error unmarshal(fam byte, data []byte) error
} }
@ -214,7 +235,19 @@ type Meta struct {
} }
func (e *Meta) marshal(fam byte) ([]byte, error) { func (e *Meta) marshal(fam byte) ([]byte, error) {
regData := []byte{} exprData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("meta\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Meta) marshalData(fam byte) ([]byte, error) {
var regData []byte
exprData, err := netlink.MarshalAttributes( exprData, err := netlink.MarshalAttributes(
[]netlink.Attribute{ []netlink.Attribute{
{Type: unix.NFTA_META_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))}, {Type: unix.NFTA_META_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
@ -240,11 +273,7 @@ func (e *Meta) marshal(fam byte) ([]byte, error) {
return nil, err return nil, err
} }
exprData = append(exprData, regData...) exprData = append(exprData, regData...)
return exprData, nil
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("meta\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
} }
func (e *Meta) unmarshal(fam byte, data []byte) error { func (e *Meta) unmarshal(fam byte, data []byte) error {
@ -291,6 +320,17 @@ const (
) )
func (e *Masq) marshal(fam byte) ([]byte, error) { func (e *Masq) marshal(fam byte) ([]byte, error) {
msgData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("masq\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: msgData},
})
}
func (e *Masq) marshalData(fam byte) ([]byte, error) {
msgData := []byte{} msgData := []byte{}
if !e.ToPorts { if !e.ToPorts {
flags := uint32(0) flags := uint32(0)
@ -327,10 +367,7 @@ func (e *Masq) marshal(fam byte) ([]byte, error) {
msgData = append(msgData, regsData...) msgData = append(msgData, regsData...)
} }
} }
return netlink.MarshalAttributes([]netlink.Attribute{ return msgData, nil
{Type: unix.NFTA_EXPR_NAME, Data: []byte("masq\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: msgData},
})
} }
func (e *Masq) unmarshal(fam byte, data []byte) error { func (e *Masq) unmarshal(fam byte, data []byte) error {
@ -377,17 +414,7 @@ type Cmp struct {
} }
func (e *Cmp) marshal(fam byte) ([]byte, error) { func (e *Cmp) marshal(fam byte) ([]byte, error) {
cmpData, err := netlink.MarshalAttributes([]netlink.Attribute{ exprData, err := e.marshalData(fam)
{Type: unix.NFTA_DATA_VALUE, Data: e.Data},
})
if err != nil {
return nil, err
}
exprData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_CMP_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NFTA_CMP_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NLA_F_NESTED | unix.NFTA_CMP_DATA, Data: cmpData},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -397,6 +424,20 @@ func (e *Cmp) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Cmp) marshalData(fam byte) ([]byte, error) {
cmpData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Data},
})
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_CMP_SREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NFTA_CMP_OP, Data: binaryutil.BigEndian.PutUint32(uint32(e.Op))},
{Type: unix.NLA_F_NESTED | unix.NFTA_CMP_DATA, Data: cmpData},
})
}
func (e *Cmp) unmarshal(fam byte, data []byte) error { func (e *Cmp) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -40,6 +40,17 @@ type Exthdr struct {
} }
func (e *Exthdr) marshal(fam byte) ([]byte, error) { func (e *Exthdr) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("exthdr\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Exthdr) marshalData(fam byte) ([]byte, error) {
var attr []netlink.Attribute var attr []netlink.Attribute
// Operations are differentiated by the Op and whether the SourceRegister // Operations are differentiated by the Op and whether the SourceRegister
@ -64,14 +75,7 @@ func (e *Exthdr) marshal(fam byte) ([]byte, error) {
netlink.Attribute{Type: unix.NFTA_EXTHDR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)}) netlink.Attribute{Type: unix.NFTA_EXTHDR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)})
} }
data, err := netlink.MarshalAttributes(attr) return netlink.MarshalAttributes(attr)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("exthdr\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Exthdr) unmarshal(fam byte, data []byte) error { func (e *Exthdr) unmarshal(fam byte, data []byte) error {

View File

@ -37,6 +37,17 @@ type Fib struct {
} }
func (e *Fib) marshal(fam byte) ([]byte, error) { func (e *Fib) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("fib\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Fib) marshalData(fam byte) ([]byte, error) {
data := []byte{} data := []byte{}
reg, err := netlink.MarshalAttributes([]netlink.Attribute{ reg, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_FIB_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)}, {Type: unix.NFTA_FIB_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
@ -92,11 +103,7 @@ func (e *Fib) marshal(fam byte) ([]byte, error) {
} }
data = append(data, rslt...) data = append(data, rslt...)
} }
return data, nil
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("fib\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Fib) unmarshal(fam byte, data []byte) error { func (e *Fib) unmarshal(fam byte, data []byte) error {

View File

@ -28,9 +28,7 @@ type FlowOffload struct {
} }
func (e *FlowOffload) marshal(fam byte) ([]byte, error) { func (e *FlowOffload) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: NFTNL_EXPR_FLOW_TABLE_NAME, Data: []byte(e.Name)},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,6 +39,12 @@ func (e *FlowOffload) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *FlowOffload) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: NFTNL_EXPR_FLOW_TABLE_NAME, Data: []byte(e.Name)},
})
}
func (e *FlowOffload) unmarshal(fam byte, data []byte) error { func (e *FlowOffload) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -41,6 +41,17 @@ type Hash struct {
} }
func (e *Hash) marshal(fam byte) ([]byte, error) { func (e *Hash) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("hash\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Hash) marshalData(fam byte) ([]byte, error) {
hashAttrs := []netlink.Attribute{ hashAttrs := []netlink.Attribute{
{Type: unix.NFTA_HASH_SREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.SourceRegister))}, {Type: unix.NFTA_HASH_SREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.SourceRegister))},
{Type: unix.NFTA_HASH_DREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.DestRegister))}, {Type: unix.NFTA_HASH_DREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.DestRegister))},
@ -56,14 +67,7 @@ func (e *Hash) marshal(fam byte) ([]byte, error) {
{Type: unix.NFTA_HASH_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.Offset))}, {Type: unix.NFTA_HASH_OFFSET, Data: binaryutil.BigEndian.PutUint32(uint32(e.Offset))},
{Type: unix.NFTA_HASH_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))}, {Type: unix.NFTA_HASH_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
}...) }...)
data, err := netlink.MarshalAttributes(hashAttrs) return netlink.MarshalAttributes(hashAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("hash\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Hash) unmarshal(fam byte, data []byte) error { func (e *Hash) unmarshal(fam byte, data []byte) error {

View File

@ -29,6 +29,17 @@ type Immediate struct {
} }
func (e *Immediate) marshal(fam byte) ([]byte, error) { func (e *Immediate) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Immediate) marshalData(fam byte) ([]byte, error) {
immData, err := netlink.MarshalAttributes([]netlink.Attribute{ immData, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_DATA_VALUE, Data: e.Data}, {Type: unix.NFTA_DATA_VALUE, Data: e.Data},
}) })
@ -36,17 +47,10 @@ func (e *Immediate) marshal(fam byte) ([]byte, error) {
return nil, err return nil, err
} }
data, err := netlink.MarshalAttributes([]netlink.Attribute{ return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)}, {Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData}, {Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData},
}) })
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Immediate) unmarshal(fam byte, data []byte) error { func (e *Immediate) unmarshal(fam byte, data []byte) error {

View File

@ -72,6 +72,18 @@ type Limit struct {
} }
func (l *Limit) marshal(fam byte) ([]byte, error) { func (l *Limit) marshal(fam byte) ([]byte, error) {
data, err := l.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("limit\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (l *Limit) marshalData(fam byte) ([]byte, error) {
var flags uint32 var flags uint32
if l.Over { if l.Over {
flags = unix.NFT_LIMIT_F_INV flags = unix.NFT_LIMIT_F_INV
@ -84,15 +96,7 @@ func (l *Limit) marshal(fam byte) ([]byte, error) {
{Type: unix.NFTA_LIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)}, {Type: unix.NFTA_LIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)},
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("limit\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (l *Limit) unmarshal(fam byte, data []byte) error { func (l *Limit) unmarshal(fam byte, data []byte) error {

View File

@ -69,6 +69,18 @@ type Log struct {
} }
func (e *Log) marshal(fam byte) ([]byte, error) { func (e *Log) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("log\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Log) marshalData(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/log.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n129 // Per https://git.netfilter.org/libnftnl/tree/src/expr/log.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n129
attrs := make([]netlink.Attribute, 0) attrs := make([]netlink.Attribute, 0)
if e.Key&(1<<unix.NFTA_LOG_GROUP) != 0 { if e.Key&(1<<unix.NFTA_LOG_GROUP) != 0 {
@ -109,15 +121,7 @@ func (e *Log) marshal(fam byte) ([]byte, error) {
}) })
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("log\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Log) unmarshal(fam byte, data []byte) error { func (e *Log) unmarshal(fam byte, data []byte) error {

View File

@ -34,6 +34,18 @@ type Lookup struct {
} }
func (e *Lookup) marshal(fam byte) ([]byte, error) { func (e *Lookup) marshal(fam byte) ([]byte, error) {
opData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("lookup\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
}
func (e *Lookup) marshalData(fam byte) ([]byte, error) {
// See: https://git.netfilter.org/libnftnl/tree/src/expr/lookup.c?id=6dc1c3d8bb64077da7f3f28c7368fb087d10a492#n115 // See: https://git.netfilter.org/libnftnl/tree/src/expr/lookup.c?id=6dc1c3d8bb64077da7f3f28c7368fb087d10a492#n115
var opAttrs []netlink.Attribute var opAttrs []netlink.Attribute
if e.SourceRegister != 0 { if e.SourceRegister != 0 {
@ -49,15 +61,7 @@ func (e *Lookup) marshal(fam byte) ([]byte, error) {
netlink.Attribute{Type: unix.NFTA_LOOKUP_SET, Data: []byte(e.SetName + "\x00")}, netlink.Attribute{Type: unix.NFTA_LOOKUP_SET, Data: []byte(e.SetName + "\x00")},
netlink.Attribute{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)}, netlink.Attribute{Type: unix.NFTA_LOOKUP_SET_ID, Data: binaryutil.BigEndian.PutUint32(e.SetID)},
) )
opData, err := netlink.MarshalAttributes(opAttrs) return netlink.MarshalAttributes(opAttrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("lookup\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: opData},
})
} }
func (e *Lookup) unmarshal(fam byte, data []byte) error { func (e *Lookup) unmarshal(fam byte, data []byte) error {

View File

@ -18,6 +18,17 @@ type Match struct {
} }
func (e *Match) marshal(fam byte) ([]byte, error) { func (e *Match) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("match\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Match) marshalData(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/match.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38 // Per https://git.netfilter.org/libnftnl/tree/src/expr/match.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38
name := e.Name name := e.Name
// limit the extension name as (some) user-space tools do and leave room for // limit the extension name as (some) user-space tools do and leave room for
@ -36,15 +47,7 @@ func (e *Match) marshal(fam byte) ([]byte, error) {
{Type: unix.NFTA_MATCH_REV, Data: binaryutil.BigEndian.PutUint32(e.Rev)}, {Type: unix.NFTA_MATCH_REV, Data: binaryutil.BigEndian.PutUint32(e.Rev)},
{Type: unix.NFTA_MATCH_INFO, Data: info}, {Type: unix.NFTA_MATCH_INFO, Data: info},
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("match\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Match) unmarshal(fam byte, data []byte) error { func (e *Match) unmarshal(fam byte, data []byte) error {

View File

@ -57,6 +57,17 @@ type NAT struct {
// | 00 00 00 02 | | data | reg 2 // | 00 00 00 02 | | data | reg 2
func (e *NAT) marshal(fam byte) ([]byte, error) { func (e *NAT) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("nat\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *NAT) marshalData(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{ attrs := []netlink.Attribute{
{Type: unix.NFTA_NAT_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))}, {Type: unix.NFTA_NAT_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
{Type: unix.NFTA_NAT_FAMILY, Data: binaryutil.BigEndian.PutUint32(e.Family)}, {Type: unix.NFTA_NAT_FAMILY, Data: binaryutil.BigEndian.PutUint32(e.Family)},
@ -90,14 +101,7 @@ func (e *NAT) marshal(fam byte) ([]byte, error) {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)}) attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_NAT_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)})
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("nat\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *NAT) unmarshal(fam byte, data []byte) error { func (e *NAT) unmarshal(fam byte, data []byte) error {

View File

@ -27,6 +27,10 @@ func (e *Notrack) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Notrack) marshalData(fam byte) ([]byte, error) {
return []byte("notrack\x00"), nil
}
func (e *Notrack) unmarshal(fam byte, data []byte) error { func (e *Notrack) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)

View File

@ -32,6 +32,18 @@ type Numgen struct {
} }
func (e *Numgen) marshal(fam byte) ([]byte, error) { func (e *Numgen) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("numgen\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Numgen) marshalData(fam byte) ([]byte, error) {
// Currently only two types are supported, failing if Type is not of two known types // Currently only two types are supported, failing if Type is not of two known types
switch e.Type { switch e.Type {
case unix.NFT_NG_INCREMENTAL: case unix.NFT_NG_INCREMENTAL:
@ -40,20 +52,12 @@ func (e *Numgen) marshal(fam byte) ([]byte, error) {
return nil, fmt.Errorf("unsupported numgen type %d", e.Type) return nil, fmt.Errorf("unsupported numgen type %d", e.Type)
} }
data, err := netlink.MarshalAttributes([]netlink.Attribute{ return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_NG_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)}, {Type: unix.NFTA_NG_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: unix.NFTA_NG_MODULUS, Data: binaryutil.BigEndian.PutUint32(e.Modulus)}, {Type: unix.NFTA_NG_MODULUS, Data: binaryutil.BigEndian.PutUint32(e.Modulus)},
{Type: unix.NFTA_NG_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)}, {Type: unix.NFTA_NG_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)},
{Type: unix.NFTA_NG_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)}, {Type: unix.NFTA_NG_OFFSET, Data: binaryutil.BigEndian.PutUint32(e.Offset)},
}) })
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("numgen\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Numgen) unmarshal(fam byte, data []byte) error { func (e *Numgen) unmarshal(fam byte, data []byte) error {

View File

@ -28,10 +28,7 @@ type Objref struct {
} }
func (e *Objref) marshal(fam byte) ([]byte, error) { func (e *Objref) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_OBJREF_IMM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
{Type: unix.NFTA_OBJREF_IMM_NAME, Data: []byte(e.Name)}, // NOT \x00-terminated?!
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -42,6 +39,13 @@ func (e *Objref) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Objref) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_OBJREF_IMM_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))},
{Type: unix.NFTA_OBJREF_IMM_NAME, Data: []byte(e.Name)}, // NOT \x00-terminated?!
})
}
func (e *Objref) unmarshal(fam byte, data []byte) error { func (e *Objref) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -58,7 +58,18 @@ type Payload struct {
} }
func (e *Payload) marshal(fam byte) ([]byte, error) { func (e *Payload) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("payload\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Payload) marshalData(fam byte) ([]byte, error) {
var attrs []netlink.Attribute var attrs []netlink.Attribute
if e.OperationType == PayloadWrite { if e.OperationType == PayloadWrite {
@ -89,15 +100,7 @@ func (e *Payload) marshal(fam byte) ([]byte, error) {
} }
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("payload\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Payload) unmarshal(fam byte, data []byte) error { func (e *Payload) unmarshal(fam byte, data []byte) error {

View File

@ -44,14 +44,7 @@ type Queue struct {
} }
func (e *Queue) marshal(fam byte) ([]byte, error) { func (e *Queue) marshal(fam byte) ([]byte, error) {
if e.Total == 0 { data, err := e.marshalData(fam)
e.Total = 1 // The total default value is 1
}
data, err := netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_QUEUE_NUM, Data: binaryutil.BigEndian.PutUint16(e.Num)},
{Type: unix.NFTA_QUEUE_TOTAL, Data: binaryutil.BigEndian.PutUint16(e.Total)},
{Type: unix.NFTA_QUEUE_FLAGS, Data: binaryutil.BigEndian.PutUint16(uint16(e.Flag))},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -61,6 +54,17 @@ func (e *Queue) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Queue) marshalData(fam byte) ([]byte, error) {
if e.Total == 0 {
e.Total = 1 // The total default value is 1
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_QUEUE_NUM, Data: binaryutil.BigEndian.PutUint16(e.Num)},
{Type: unix.NFTA_QUEUE_TOTAL, Data: binaryutil.BigEndian.PutUint16(e.Total)},
{Type: unix.NFTA_QUEUE_FLAGS, Data: binaryutil.BigEndian.PutUint16(uint16(e.Flag))},
})
}
func (e *Queue) unmarshal(fam byte, data []byte) error { func (e *Queue) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -30,6 +30,18 @@ type Quota struct {
} }
func (q *Quota) marshal(fam byte) ([]byte, error) { func (q *Quota) marshal(fam byte) ([]byte, error) {
data, err := q.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("quota\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (q *Quota) marshalData(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{ attrs := []netlink.Attribute{
{Type: unix.NFTA_QUOTA_BYTES, Data: binaryutil.BigEndian.PutUint64(q.Bytes)}, {Type: unix.NFTA_QUOTA_BYTES, Data: binaryutil.BigEndian.PutUint64(q.Bytes)},
{Type: unix.NFTA_QUOTA_CONSUMED, Data: binaryutil.BigEndian.PutUint64(q.Consumed)}, {Type: unix.NFTA_QUOTA_CONSUMED, Data: binaryutil.BigEndian.PutUint64(q.Consumed)},
@ -44,15 +56,7 @@ func (q *Quota) marshal(fam byte) ([]byte, error) {
Data: binaryutil.BigEndian.PutUint32(flags), Data: binaryutil.BigEndian.PutUint32(flags),
}) })
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("quota\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (q *Quota) unmarshal(fam byte, data []byte) error { func (q *Quota) unmarshal(fam byte, data []byte) error {

View File

@ -31,6 +31,18 @@ type Range struct {
} }
func (e *Range) marshal(fam byte) ([]byte, error) { func (e *Range) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("range\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Range) marshalData(fam byte) ([]byte, error) {
var attrs []netlink.Attribute var attrs []netlink.Attribute
var err error var err error
var rangeFromData, rangeToData []byte var rangeFromData, rangeToData []byte
@ -57,11 +69,7 @@ func (e *Range) marshal(fam byte) ([]byte, error) {
} }
data = append(data, rangeFromData...) data = append(data, rangeFromData...)
data = append(data, rangeToData...) data = append(data, rangeToData...)
return data, nil
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("range\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Range) unmarshal(fam byte, data []byte) error { func (e *Range) unmarshal(fam byte, data []byte) error {

View File

@ -29,6 +29,18 @@ type Redir struct {
} }
func (e *Redir) marshal(fam byte) ([]byte, error) { func (e *Redir) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("redir\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Redir) marshalData(fam byte) ([]byte, error) {
var attrs []netlink.Attribute var attrs []netlink.Attribute
if e.RegisterProtoMin > 0 { if e.RegisterProtoMin > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_REG_PROTO_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegisterProtoMin)}) attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_REG_PROTO_MIN, Data: binaryutil.BigEndian.PutUint32(e.RegisterProtoMin)})
@ -40,15 +52,7 @@ func (e *Redir) marshal(fam byte) ([]byte, error) {
attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)}) attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_REDIR_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)})
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("redir\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Redir) unmarshal(fam byte, data []byte) error { func (e *Redir) unmarshal(fam byte, data []byte) error {

View File

@ -28,10 +28,7 @@ type Reject struct {
} }
func (e *Reject) marshal(fam byte) ([]byte, error) { func (e *Reject) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_REJECT_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)},
{Type: unix.NFTA_REJECT_ICMP_CODE, Data: []byte{e.Code}},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,6 +38,13 @@ func (e *Reject) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Reject) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_REJECT_TYPE, Data: binaryutil.BigEndian.PutUint32(e.Type)},
{Type: unix.NFTA_REJECT_ICMP_CODE, Data: []byte{e.Code}},
})
}
func (e *Reject) unmarshal(fam byte, data []byte) error { func (e *Reject) unmarshal(fam byte, data []byte) error {
ad, err := netlink.NewAttributeDecoder(data) ad, err := netlink.NewAttributeDecoder(data)
if err != nil { if err != nil {

View File

@ -37,10 +37,7 @@ type Rt struct {
} }
func (e *Rt) marshal(fam byte) ([]byte, error) { func (e *Rt) marshal(fam byte) ([]byte, error) {
data, err := netlink.MarshalAttributes([]netlink.Attribute{ data, err := e.marshalData(fam)
{Type: unix.NFTA_RT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
{Type: unix.NFTA_RT_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -50,6 +47,13 @@ func (e *Rt) marshal(fam byte) ([]byte, error) {
}) })
} }
func (e *Rt) marshalData(fam byte) ([]byte, error) {
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_RT_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
{Type: unix.NFTA_RT_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
})
}
func (e *Rt) unmarshal(fam byte, data []byte) error { func (e *Rt) unmarshal(fam byte, data []byte) error {
return fmt.Errorf("not yet implemented") return fmt.Errorf("not yet implemented")
} }

View File

@ -49,23 +49,26 @@ const (
) )
func (e *Socket) marshal(fam byte) ([]byte, error) { func (e *Socket) marshal(fam byte) ([]byte, error) {
exprData, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("socket\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
}
func (e *Socket) marshalData(fam byte) ([]byte, error) {
// NOTE: Socket.Level is only used when Socket.Key == SocketKeyCgroupv2. But `nft` always encoding it. Check link below: // NOTE: Socket.Level is only used when Socket.Key == SocketKeyCgroupv2. But `nft` always encoding it. Check link below:
// http://git.netfilter.org/nftables/tree/src/netlink_linearize.c?id=0583bac241ea18c9d7f61cb20ca04faa1e043b78#n319 // http://git.netfilter.org/nftables/tree/src/netlink_linearize.c?id=0583bac241ea18c9d7f61cb20ca04faa1e043b78#n319
exprData, err := netlink.MarshalAttributes( return netlink.MarshalAttributes(
[]netlink.Attribute{ []netlink.Attribute{
{Type: NFTA_SOCKET_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)}, {Type: NFTA_SOCKET_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)},
{Type: NFTA_SOCKET_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))}, {Type: NFTA_SOCKET_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))},
{Type: NFTA_SOCKET_LEVEL, Data: binaryutil.BigEndian.PutUint32(uint32(e.Level))}, {Type: NFTA_SOCKET_LEVEL, Data: binaryutil.BigEndian.PutUint32(uint32(e.Level))},
}, },
) )
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("socket\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: exprData},
})
} }
func (e *Socket) unmarshal(fam byte, data []byte) error { func (e *Socket) unmarshal(fam byte, data []byte) error {

View File

@ -21,6 +21,17 @@ type Target struct {
} }
func (e *Target) marshal(fam byte) ([]byte, error) { func (e *Target) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("target\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Target) marshalData(fam byte) ([]byte, error) {
// Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38 // Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38
name := e.Name name := e.Name
// limit the extension name as (some) user-space tools do and leave room for // limit the extension name as (some) user-space tools do and leave room for
@ -40,15 +51,7 @@ func (e *Target) marshal(fam byte) ([]byte, error) {
{Type: unix.NFTA_TARGET_INFO, Data: info}, {Type: unix.NFTA_TARGET_INFO, Data: info},
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("target\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Target) unmarshal(fam byte, data []byte) error { func (e *Target) unmarshal(fam byte, data []byte) error {

View File

@ -40,6 +40,17 @@ type TProxy struct {
} }
func (e *TProxy) marshal(fam byte) ([]byte, error) { func (e *TProxy) marshal(fam byte) ([]byte, error) {
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("tproxy\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *TProxy) marshalData(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{ attrs := []netlink.Attribute{
{Type: NFTA_TPROXY_FAMILY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Family))}, {Type: NFTA_TPROXY_FAMILY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Family))},
{Type: NFTA_TPROXY_REG_PORT, Data: binaryutil.BigEndian.PutUint32(e.RegPort)}, {Type: NFTA_TPROXY_REG_PORT, Data: binaryutil.BigEndian.PutUint32(e.RegPort)},
@ -52,14 +63,7 @@ func (e *TProxy) marshal(fam byte) ([]byte, error) {
}) })
} }
data, err := netlink.MarshalAttributes(attrs) return netlink.MarshalAttributes(attrs)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("tproxy\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *TProxy) unmarshal(fam byte, data []byte) error { func (e *TProxy) unmarshal(fam byte, data []byte) error {

View File

@ -64,7 +64,17 @@ func (e *Verdict) marshal(fam byte) ([]byte, error) {
// } // }
// } // }
// } // }
data, err := e.marshalData(fam)
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
}
func (e *Verdict) marshalData(fam byte) ([]byte, error) {
attrs := []netlink.Attribute{ attrs := []netlink.Attribute{
{Type: unix.NFTA_VERDICT_CODE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Kind))}, {Type: unix.NFTA_VERDICT_CODE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Kind))},
} }
@ -83,17 +93,10 @@ func (e *Verdict) marshal(fam byte) ([]byte, error) {
return nil, err return nil, err
} }
data, err := netlink.MarshalAttributes([]netlink.Attribute{ return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(unix.NFT_REG_VERDICT)}, {Type: unix.NFTA_IMMEDIATE_DREG, Data: binaryutil.BigEndian.PutUint32(unix.NFT_REG_VERDICT)},
{Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData}, {Type: unix.NLA_F_NESTED | unix.NFTA_IMMEDIATE_DATA, Data: immData},
}) })
if err != nil {
return nil, err
}
return netlink.MarshalAttributes([]netlink.Attribute{
{Type: unix.NFTA_EXPR_NAME, Data: []byte("immediate\x00")},
{Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
})
} }
func (e *Verdict) unmarshal(fam byte, data []byte) error { func (e *Verdict) unmarshal(fam byte, data []byte) error {

2
go.mod
View File

@ -12,6 +12,6 @@ require (
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/josharian/native v1.1.0 // indirect github.com/josharian/native v1.1.0 // indirect
github.com/mdlayher/socket v0.5.0 // indirect github.com/mdlayher/socket v0.5.0 // indirect
golang.org/x/net v0.22.0 // indirect golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/sync v0.6.0 // indirect
) )

4
go.sum
View File

@ -8,8 +8,8 @@ github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=

View File

@ -5,6 +5,6 @@ import (
) )
var ( var (
ParseExprBytesFunc func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error) ParseExprBytesFunc func(fam byte, ad *netlink.AttributeDecoder, args ...string) ([]interface{}, error)
ParseExprMsgFunc func(fam byte, b []byte) ([]interface{}, error) ParseExprMsgFunc func(fam byte, b []byte, args ...string) ([]interface{}, error)
) )

View File

@ -1783,7 +1783,7 @@ func TestListChainByName(t *testing.T) {
} }
func TestListChainByNameUsingLasting(t *testing.T) { func TestListChainByNameUsingLasting(t *testing.T) {
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests) _, newNS := nftest.OpenSystemConn(t, *enableSysTests)
conn, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting()) conn, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting())
if err != nil { if err != nil {
t.Fatalf("nftables.New() failed: %v", err) t.Fatalf("nftables.New() failed: %v", err)
@ -1882,8 +1882,7 @@ func TestListTableByName(t *testing.T) {
} }
// not specifying correct family should return err since no table in ipv4 // not specifying correct family should return err since no table in ipv4
tr, err = conn.ListTable(table2.Name) if _, err = conn.ListTable(table2.Name); err == nil {
if err == nil {
t.Fatalf("conn.ListTable() should have failed") t.Fatalf("conn.ListTable() should have failed")
} }
@ -2114,9 +2113,9 @@ func TestGetObjReset(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
co, ok := obj.(*nftables.CounterObj) co, ok := obj.(*nftables.ObjAttr)
if !ok { if !ok {
t.Fatalf("unexpected type: got %T, want *nftables.CounterObj", obj) t.Fatalf("unexpected type: got %T, want *nftables.ObjAttr", obj)
} }
if got, want := co.Table.Name, filter.Name; got != want { if got, want := co.Table.Name, filter.Name; got != want {
t.Errorf("unexpected table name: got %q, want %q", got, want) t.Errorf("unexpected table name: got %q, want %q", got, want)
@ -2124,10 +2123,14 @@ func TestGetObjReset(t *testing.T) {
if got, want := co.Table.Family, filter.Family; got != want { if got, want := co.Table.Family, filter.Family; got != want {
t.Errorf("unexpected table family: got %d, want %d", got, want) t.Errorf("unexpected table family: got %d, want %d", got, want)
} }
if got, want := co.Packets, uint64(9); got != want { o, ok := co.Obj.(*expr.Counter)
if !ok {
t.Fatalf("unexpected type: got %T, want *expr.Counter", o)
}
if got, want := o.Packets, uint64(9); got != want {
t.Errorf("unexpected number of packets: got %d, want %d", got, want) t.Errorf("unexpected number of packets: got %d, want %d", got, want)
} }
if got, want := co.Bytes, uint64(1121); got != want { if got, want := o.Bytes, uint64(1121); got != want {
t.Errorf("unexpected number of bytes: got %d, want %d", got, want) t.Errorf("unexpected number of bytes: got %d, want %d", got, want)
} }
} }
@ -2223,10 +2226,9 @@ func TestObjAPI(t *testing.T) {
t.Errorf("c.GetObject(counter1) failed: %v failed", err) t.Errorf("c.GetObject(counter1) failed: %v failed", err)
} }
rcounter1, ok := obj1.(*nftables.CounterObj) rcounter1, ok := obj1.(*nftables.ObjAttr)
if !ok { if !ok {
t.Fatalf("unexpected type: got %T, want *nftables.CounterObj", rcounter1) t.Fatalf("unexpected type: got %T, want *nftables.CounterObj", obj1)
} }
if rcounter1.Name != "fwded1" { if rcounter1.Name != "fwded1" {
@ -2238,10 +2240,9 @@ func TestObjAPI(t *testing.T) {
t.Errorf("c.GetObject(counter2) failed: %v failed", err) t.Errorf("c.GetObject(counter2) failed: %v failed", err)
} }
rcounter2, ok := obj2.(*nftables.CounterObj) rcounter2, ok := obj2.(*nftables.ObjAttr)
if !ok { if !ok {
t.Fatalf("unexpected type: got %T, want *nftables.CounterObj", rcounter2) t.Fatalf("unexpected type: got %T, want *nftables.CounterObj", obj2)
} }
if rcounter2.Name != "fwded2" { if rcounter2.Name != "fwded2" {
@ -2260,7 +2261,7 @@ func TestObjAPI(t *testing.T) {
t.Errorf("c.GetObject(counter1) failed: %v failed", err) t.Errorf("c.GetObject(counter1) failed: %v failed", err)
} }
if counter1 := obj1.(*nftables.CounterObj); counter1.Packets > 0 { if counter1 := obj1.(*nftables.ObjAttr).Obj.(*expr.Counter); counter1.Packets > 0 {
t.Errorf("unexpected packets number: got %d, want %d", counter1.Packets, 0) t.Errorf("unexpected packets number: got %d, want %d", counter1.Packets, 0)
} }
@ -2270,7 +2271,7 @@ func TestObjAPI(t *testing.T) {
t.Errorf("c.GetObject(counter2) failed: %v failed", err) t.Errorf("c.GetObject(counter2) failed: %v failed", err)
} }
if counter2 := obj2.(*nftables.CounterObj); counter2.Packets != 1 { if counter2 := obj2.(*nftables.ObjAttr).Obj.(*expr.Counter); counter2.Packets != 1 {
t.Errorf("unexpected packets number: got %d, want %d", counter2.Packets, 1) t.Errorf("unexpected packets number: got %d, want %d", counter2.Packets, 1)
} }
@ -2767,7 +2768,7 @@ func TestCreateUseAnonymousSet(t *testing.T) {
} }
func TestCappedErrMsgOnSets(t *testing.T) { func TestCappedErrMsgOnSets(t *testing.T) {
c, newNS := nftest.OpenSystemConn(t, *enableSysTests) _, newNS := nftest.OpenSystemConn(t, *enableSysTests)
c, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting()) c, err := nftables.New(nftables.WithNetNSFd(int(newNS)), nftables.AsLasting())
if err != nil { if err != nil {
t.Fatalf("nftables.New() failed: %v", err) t.Fatalf("nftables.New() failed: %v", err)
@ -6285,6 +6286,84 @@ func TestGetRulesObjref(t *testing.T) {
} }
} }
func TestAddLimitObj(t *testing.T) {
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
defer nftest.CleanupSystemConn(t, newNS)
conn.FlushRuleset()
defer conn.FlushRuleset()
table := &nftables.Table{
Name: "limit_demo",
Family: nftables.TableFamilyIPv4,
}
tr := conn.AddTable(table)
c := &nftables.Chain{
Name: "filter",
Table: table,
}
conn.AddChain(c)
l := &expr.Limit{
Type: expr.LimitTypePkts,
Rate: 400,
Unit: expr.LimitTimeMinute,
Burst: 5,
Over: false,
}
o := &nftables.ObjAttr{
Table: tr,
Name: "limit_test",
Type: nftables.ObjTypeLimit,
Obj: l,
}
conn.AddObj(o)
if err := conn.Flush(); err != nil {
t.Errorf("conn.Flush() failed: %v", err)
}
obj, err := conn.GetObj(&nftables.ObjAttr{
Table: table,
Name: "limit_test",
Type: nftables.ObjTypeLimit,
})
if err != nil {
t.Fatalf("conn.GetObj() failed: %v", err)
}
if got, want := len(obj), 1; got != want {
t.Fatalf("unexpected object list length: got %d, want %d", got, want)
}
o1, ok := obj[0].(*nftables.ObjAttr)
if !ok {
t.Fatalf("unexpected type: got %T, want *ObjAttr", obj[0])
}
if got, want := o1.Name, o.Name; got != want {
t.Fatalf("limit name mismatch: got %s, want %s", got, want)
}
q, ok := o1.Obj.(*expr.Limit)
if !ok {
t.Fatalf("unexpected type: got %T, want *expr.Quota", o1.Obj)
}
if got, want := q.Burst, l.Burst; got != want {
t.Fatalf("limit burst mismatch: got %d, want %d", got, want)
}
if got, want := q.Unit, l.Unit; got != want {
t.Fatalf("limit unit mismatch: got %d, want %d", got, want)
}
if got, want := q.Rate, l.Rate; got != want {
t.Fatalf("limit rate mismatch: got %v, want %v", got, want)
}
if got, want := q.Over, l.Over; got != want {
t.Fatalf("limit over mismatch: got %v, want %v", got, want)
}
if got, want := q.Type, l.Type; got != want {
t.Fatalf("limit type mismatch: got %v, want %v", got, want)
}
}
func TestAddQuotaObj(t *testing.T) { func TestAddQuotaObj(t *testing.T) {
conn, newNS := nftest.OpenSystemConn(t, *enableSysTests) conn, newNS := nftest.OpenSystemConn(t, *enableSysTests)
defer nftest.CleanupSystemConn(t, newNS) defer nftest.CleanupSystemConn(t, newNS)
@ -6328,20 +6407,24 @@ func TestAddQuotaObj(t *testing.T) {
t.Fatalf("unexpected object list length: got %d, want %d", got, want) t.Fatalf("unexpected object list length: got %d, want %d", got, want)
} }
o1, ok := obj[0].(*nftables.QuotaObj) o1, ok := obj[0].(*nftables.ObjAttr)
if !ok { if !ok {
t.Fatalf("unexpected type: got %T, want *QuotaObj", obj[0]) t.Fatalf("unexpected type: got %T, want *ObjAttr", obj[0])
} }
if got, want := o1.Name, o.Name; got != want { if got, want := o1.Name, o.Name; got != want {
t.Fatalf("quota name mismatch: got %s, want %s", got, want) t.Fatalf("quota name mismatch: got %s, want %s", got, want)
} }
if got, want := o1.Bytes, o.Bytes; got != want { q, ok := o1.Obj.(*expr.Quota)
if !ok {
t.Fatalf("unexpected type: got %T, want *expr.Quota", o1.Obj)
}
if got, want := q.Bytes, o.Bytes; got != want {
t.Fatalf("quota bytes mismatch: got %d, want %d", got, want) t.Fatalf("quota bytes mismatch: got %d, want %d", got, want)
} }
if got, want := o1.Consumed, o.Consumed; got != want { if got, want := q.Consumed, o.Consumed; got != want {
t.Fatalf("quota consumed mismatch: got %d, want %d", got, want) t.Fatalf("quota consumed mismatch: got %d, want %d", got, want)
} }
if got, want := o1.Over, o.Over; got != want { if got, want := q.Over, o.Over; got != want {
t.Fatalf("quota over mismatch: got %v, want %v", got, want) t.Fatalf("quota over mismatch: got %v, want %v", got, want)
} }
} }
@ -6452,7 +6535,17 @@ func TestDeleteQuotaObj(t *testing.T) {
t.Fatalf("unexpected number of objects: got %d, want %d", got, want) t.Fatalf("unexpected number of objects: got %d, want %d", got, want)
} }
if got, want := obj[0], o; !reflect.DeepEqual(got, want) { want := &nftables.ObjAttr{
Table: tr,
Name: "q_test",
Type: nftables.ObjTypeQuota,
Obj: &expr.Quota{
Bytes: o.Bytes,
Consumed: o.Consumed,
Over: o.Over,
},
}
if got, want := obj[0], want; !reflect.DeepEqual(got, want) {
t.Errorf("got = %+v, want = %+v", got, want) t.Errorf("got = %+v, want = %+v", got, want)
} }

144
obj.go
View File

@ -18,6 +18,9 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/google/nftables/internal/parseexprfunc"
"github.com/mdlayher/netlink" "github.com/mdlayher/netlink"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -27,13 +30,70 @@ var (
delObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ) delObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ)
) )
type ObjType uint32
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=be0bae0ad31b0adb506f96de083f52a2bd0d4fbf#n1612
const (
ObjTypeCounter ObjType = unix.NFT_OBJECT_COUNTER
ObjTypeQuota ObjType = unix.NFT_OBJECT_QUOTA
ObjTypeCtHelper ObjType = unix.NFT_OBJECT_CT_HELPER
ObjTypeLimit ObjType = unix.NFT_OBJECT_LIMIT
ObjTypeConnLimit ObjType = unix.NFT_OBJECT_CONNLIMIT
ObjTypeTunnel ObjType = unix.NFT_OBJECT_TUNNEL
ObjTypeCtTimeout ObjType = unix.NFT_OBJECT_CT_TIMEOUT
ObjTypeSecMark ObjType = unix.NFT_OBJECT_SECMARK
ObjTypeCtExpect ObjType = unix.NFT_OBJECT_CT_EXPECT
ObjTypeSynProxy ObjType = unix.NFT_OBJECT_SYNPROXY
)
var objByObjTypeMagic = map[ObjType]string{
ObjTypeCounter: "counter",
ObjTypeQuota: "quota",
ObjTypeLimit: "limit",
ObjTypeConnLimit: "connlimit",
ObjTypeCtHelper: "cthelper", // not implemented in expr
ObjTypeTunnel: "tunnel", // not implemented in expr
ObjTypeCtTimeout: "cttimeout", // not implemented in expr
ObjTypeSecMark: "secmark", // not implemented in expr
ObjTypeCtExpect: "ctexpect", // not implemented in expr
ObjTypeSynProxy: "synproxy", // not implemented in expr
}
// Obj represents a netfilter stateful object. See also // Obj represents a netfilter stateful object. See also
// https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects // https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects
type Obj interface { type Obj interface {
table() *Table table() *Table
family() TableFamily family() TableFamily
unmarshal(*netlink.AttributeDecoder) error data() expr.Any
marshal(data bool) ([]byte, error) name() string
objType() ObjType
}
type ObjAttr struct {
Table *Table
Name string
Type ObjType
Obj expr.Any
}
func (o *ObjAttr) table() *Table {
return o.Table
}
func (o *ObjAttr) family() TableFamily {
return o.Table.Family
}
func (o *ObjAttr) data() expr.Any {
return o.Obj
}
func (o *ObjAttr) name() string {
return o.Name
}
func (o *ObjAttr) objType() ObjType {
return o.Type
} }
// AddObject adds the specified Obj. Alias of AddObj. // AddObject adds the specified Obj. Alias of AddObj.
@ -46,18 +106,27 @@ func (cc *Conn) AddObject(o Obj) Obj {
func (cc *Conn) AddObj(o Obj) Obj { func (cc *Conn) AddObj(o Obj) Obj {
cc.mu.Lock() cc.mu.Lock()
defer cc.mu.Unlock() defer cc.mu.Unlock()
data, err := o.marshal(true) data, err := expr.MarshalExprData(byte(o.family()), o.data())
if err != nil { if err != nil {
cc.setErr(err) cc.setErr(err)
return nil return nil
} }
attrs := []netlink.Attribute{
{Type: unix.NFTA_OBJ_TABLE, Data: []byte(o.table().Name + "\x00")},
{Type: unix.NFTA_OBJ_NAME, Data: []byte(o.name() + "\x00")},
{Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(o.objType()))},
}
if len(data) > 0 {
attrs = append(attrs, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA, Data: data})
}
cc.messages = append(cc.messages, netlink.Message{ cc.messages = append(cc.messages, netlink.Message{
Header: netlink.Header{ Header: netlink.Header{
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ), Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ),
Flags: netlink.Request | netlink.Acknowledge | netlink.Create, Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
}, },
Data: append(extraHeader(uint8(o.family()), 0), data...), Data: append(extraHeader(uint8(o.family()), 0), cc.marshalAttr(attrs)...),
}) })
return o return o
} }
@ -66,12 +135,12 @@ func (cc *Conn) AddObj(o Obj) Obj {
func (cc *Conn) DeleteObject(o Obj) { func (cc *Conn) DeleteObject(o Obj) {
cc.mu.Lock() cc.mu.Lock()
defer cc.mu.Unlock() defer cc.mu.Unlock()
data, err := o.marshal(false) attrs := []netlink.Attribute{
if err != nil { {Type: unix.NFTA_OBJ_TABLE, Data: []byte(o.table().Name + "\x00")},
cc.setErr(err) {Type: unix.NFTA_OBJ_NAME, Data: []byte(o.name() + "\x00")},
return {Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(o.objType()))},
} }
data := cc.marshalAttr(attrs)
data = append(data, cc.marshalAttr([]netlink.Attribute{{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA}})...) data = append(data, cc.marshalAttr([]netlink.Attribute{{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA}})...)
cc.messages = append(cc.messages, netlink.Message{ cc.messages = append(cc.messages, netlink.Message{
@ -150,38 +219,26 @@ func objFromMsg(msg netlink.Message) (Obj, error) {
case unix.NFTA_OBJ_TYPE: case unix.NFTA_OBJ_TYPE:
objectType = ad.Uint32() objectType = ad.Uint32()
case unix.NFTA_OBJ_DATA: case unix.NFTA_OBJ_DATA:
switch objectType { o := ObjAttr{
case unix.NFT_OBJECT_COUNTER: Table: table,
o := CounterObj{ Name: name,
Table: table, Type: ObjType(objectType),
Name: name,
}
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
return o.unmarshal(ad)
})
return &o, ad.Err()
case NFT_OBJECT_QUOTA:
o := QuotaObj{
Table: table,
Name: name,
}
ad.Do(func(b []byte) error {
ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
return o.unmarshal(ad)
})
return &o, ad.Err()
} }
objs, err := parseexprfunc.ParseExprBytesFunc(byte(o.family()), ad, objByObjTypeMagic[o.Type])
if err != nil {
return nil, err
}
exprs := make([]expr.Any, len(objs))
for i := range exprs {
exprs[i] = objs[i].(expr.Any)
}
if len(exprs) == 0 {
return nil, fmt.Errorf("objFromMsg: exprs is empty for obj %v", o)
}
o.Obj = exprs[0]
return &o, ad.Err()
} }
} }
if err := ad.Err(); err != nil { if err := ad.Err(); err != nil {
@ -201,7 +258,12 @@ func (cc *Conn) getObj(o Obj, t *Table, msgType uint16) ([]Obj, error) {
var flags netlink.HeaderFlags var flags netlink.HeaderFlags
if o != nil { if o != nil {
data, err = o.marshal(false) attrs := []netlink.Attribute{
{Type: unix.NFTA_OBJ_TABLE, Data: []byte(o.table().Name + "\x00")},
{Type: unix.NFTA_OBJ_NAME, Data: []byte(o.name() + "\x00")},
{Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(o.objType()))},
}
data = cc.marshalAttr(attrs)
} else { } else {
flags = netlink.Dump flags = netlink.Dump
data, err = netlink.MarshalAttributes([]netlink.Attribute{ data, err = netlink.MarshalAttributes([]netlink.Attribute{

View File

@ -16,15 +16,12 @@ package nftables
import ( import (
"github.com/google/nftables/binaryutil" "github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/mdlayher/netlink" "github.com/mdlayher/netlink"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
const ( // Deprecated: Use ObjAttr instead
NFTA_OBJ_USERDATA = 8
NFT_OBJECT_QUOTA = 2
)
type QuotaObj struct { type QuotaObj struct {
Table *Table Table *Table
Name string Name string
@ -63,7 +60,7 @@ func (q *QuotaObj) marshal(data bool) ([]byte, error) {
attrs := []netlink.Attribute{ attrs := []netlink.Attribute{
{Type: unix.NFTA_OBJ_TABLE, Data: []byte(q.Table.Name + "\x00")}, {Type: unix.NFTA_OBJ_TABLE, Data: []byte(q.Table.Name + "\x00")},
{Type: unix.NFTA_OBJ_NAME, Data: []byte(q.Name + "\x00")}, {Type: unix.NFTA_OBJ_NAME, Data: []byte(q.Name + "\x00")},
{Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(NFT_OBJECT_QUOTA)}, {Type: unix.NFTA_OBJ_TYPE, Data: binaryutil.BigEndian.PutUint32(unix.NFT_OBJECT_QUOTA)},
} }
if data { if data {
attrs = append(attrs, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA, Data: obj}) attrs = append(attrs, netlink.Attribute{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA, Data: obj})
@ -78,3 +75,19 @@ func (q *QuotaObj) table() *Table {
func (q *QuotaObj) family() TableFamily { func (q *QuotaObj) family() TableFamily {
return q.Table.Family return q.Table.Family
} }
func (q *QuotaObj) data() expr.Any {
return &expr.Quota{
Bytes: q.Bytes,
Consumed: q.Consumed,
Over: q.Over,
}
}
func (q *QuotaObj) name() string {
return q.Name
}
func (q *QuotaObj) objType() ObjType {
return ObjTypeQuota
}

2
set.go
View File

@ -321,7 +321,7 @@ func (s *SetElement) decode(fam byte) func(b []byte) error {
case unix.NFTA_SET_ELEM_EXPIRATION: case unix.NFTA_SET_ELEM_EXPIRATION:
s.Expires = time.Millisecond * time.Duration(ad.Uint64()) s.Expires = time.Millisecond * time.Duration(ad.Uint64())
case unix.NFTA_SET_ELEM_EXPR: case unix.NFTA_SET_ELEM_EXPR:
elems, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes()) elems, err := parseexprfunc.ParseExprBytesFunc(fam, ad)
if err != nil { if err != nil {
return err return err
} }