diff --git a/expr/bitwise.go b/expr/bitwise.go index 62f7f9b..5f3cdea 100644 --- a/expr/bitwise.go +++ b/expr/bitwise.go @@ -31,6 +31,17 @@ type Bitwise struct { } 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{ {Type: unix.NFTA_DATA_VALUE, Data: e.Mask}, }) @@ -44,20 +55,13 @@ func (e *Bitwise) marshal(fam byte) ([]byte, error) { 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_DREG, Data: binaryutil.BigEndian.PutUint32(e.DestRegister)}, {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_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 { diff --git a/expr/byteorder.go b/expr/byteorder.go index 2450e8f..cf9e2fe 100644 --- a/expr/byteorder.go +++ b/expr/byteorder.go @@ -38,13 +38,7 @@ type Byteorder struct { } func (e *Byteorder) marshal(fam byte) ([]byte, error) { - data, err := 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)}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { return fmt.Errorf("not yet implemented") } diff --git a/expr/connlimit.go b/expr/connlimit.go index b712967..11bd07b 100644 --- a/expr/connlimit.go +++ b/expr/connlimit.go @@ -37,10 +37,7 @@ type Connlimit struct { } func (e *Connlimit) marshal(fam byte) ([]byte, error) { - data, err := netlink.MarshalAttributes([]netlink.Attribute{ - {Type: NFTA_CONNLIMIT_COUNT, Data: binaryutil.BigEndian.PutUint32(e.Count)}, - {Type: NFTA_CONNLIMIT_FLAGS, Data: binaryutil.BigEndian.PutUint32(e.Flags)}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/counter.go b/expr/counter.go index dd6eab3..7483ee4 100644 --- a/expr/counter.go +++ b/expr/counter.go @@ -28,10 +28,7 @@ type Counter struct { } func (e *Counter) marshal(fam byte) ([]byte, error) { - data, err := 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)}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/ct.go b/expr/ct.go index 1a0ee68..4efea02 100644 --- a/expr/ct.go +++ b/expr/ct.go @@ -64,7 +64,19 @@ type Ct struct { } 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( []netlink.Attribute{ {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 } exprData = append(exprData, regData...) - - 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}, - }) + return exprData, nil } func (e *Ct) unmarshal(fam byte, data []byte) error { diff --git a/expr/dup.go b/expr/dup.go index 0114fa7..9012fda 100644 --- a/expr/dup.go +++ b/expr/dup.go @@ -29,16 +29,7 @@ type Dup struct { } func (e *Dup) marshal(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)}) - } - - data, err := netlink.MarshalAttributes(attrs) - + data, err := e.marshalData(fam) if err != nil { 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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/dynset.go b/expr/dynset.go index e44f772..aa6bc79 100644 --- a/expr/dynset.go +++ b/expr/dynset.go @@ -44,6 +44,18 @@ type Dynset struct { } 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 var opAttrs []netlink.Attribute 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: unix.NFTA_DYNSET_FLAGS, Data: binaryutil.BigEndian.PutUint32(flags)}) - - 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}, - }) + return netlink.MarshalAttributes(opAttrs) } 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: e.Invert = (ad.Uint32() & unix.NFT_DYNSET_F_INV) != 0 case unix.NFTA_DYNSET_EXPR: - exprs, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes()) + exprs, err := parseexprfunc.ParseExprBytesFunc(fam, ad) if err != nil { return err } diff --git a/expr/expr.go b/expr/expr.go index a4d970f..dd898ec 100644 --- a/expr/expr.go +++ b/expr/expr.go @@ -25,8 +25,8 @@ import ( ) func init() { - parseexprfunc.ParseExprBytesFunc = func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error) { - exprs, err := exprsFromBytes(fam, ad, b) + parseExprBytesCommonFunc := func(exprsFromBytesFunc func() ([]Any, error)) ([]interface{}, error) { + exprs, err := exprsFromBytesFunc() if err != nil { return nil, err } @@ -36,6 +36,17 @@ func init() { } return result, nil } + + parseexprfunc.ParseExprBytesFromNameFunc = func(fam byte, ad *netlink.AttributeDecoder, exprName string) ([]interface{}, error) { + return parseExprBytesCommonFunc(func() ([]Any, error) { + return exprsBytesFromName(fam, ad, exprName) + }) + } + parseexprfunc.ParseExprBytesFunc = func(fam byte, ad *netlink.AttributeDecoder) ([]interface{}, error) { + return parseExprBytesCommonFunc(func() ([]Any, error) { + return exprsFromBytes(fam, ad) + }) + } parseexprfunc.ParseExprMsgFunc = func(fam byte, b []byte) ([]interface{}, error) { ad, err := netlink.NewAttributeDecoder(b) if err != nil { @@ -44,7 +55,7 @@ func init() { ad.ByteOrder = binary.BigEndian var exprs []interface{} for ad.Next() { - e, err := parseexprfunc.ParseExprBytesFunc(fam, ad, b) + e, err := parseexprfunc.ParseExprBytesFunc(fam, ad) if err != nil { return e, err } @@ -59,15 +70,35 @@ func Marshal(fam byte, e Any) ([]byte, error) { 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. func Unmarshal(fam byte, data []byte, e Any) error { return e.unmarshal(fam, data) } +// exprsBytesFromName parses raw expressions bytes +// based on provided expr name +func exprsBytesFromName(fam byte, ad *netlink.AttributeDecoder, name string) ([]Any, error) { + var exprs []Any + e := exprFromName(name) + 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() +} + // exprsFromBytes parses nested raw expressions bytes // to construct nftables expressions -func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, error) { +func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder) ([]Any, error) { var exprs []Any + ad.Do(func(b []byte) error { ad, err := netlink.NewAttributeDecoder(b) if err != nil { @@ -84,65 +115,12 @@ func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, er exprs = append(exprs, e) } case unix.NFTA_EXPR_DATA: - 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{} - } + e := exprFromName(name) if e == nil { // TODO: introduce an opaque expression type so that users know // something is here. continue // unsupported expression type } - ad.Do(func(b []byte) error { if err := Unmarshal(fam, b, e); err != nil { return err @@ -166,9 +144,67 @@ func exprsFromBytes(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]Any, er 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. type Any interface { marshal(fam byte) ([]byte, error) + marshalData(fam byte) ([]byte, error) unmarshal(fam byte, data []byte) error } @@ -214,7 +250,19 @@ type Meta struct { } 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( []netlink.Attribute{ {Type: unix.NFTA_META_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))}, @@ -240,11 +288,7 @@ func (e *Meta) marshal(fam byte) ([]byte, error) { return nil, err } exprData = append(exprData, regData...) - - 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}, - }) + return exprData, nil } func (e *Meta) unmarshal(fam byte, data []byte) error { @@ -291,6 +335,17 @@ const ( ) 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{} if !e.ToPorts { flags := uint32(0) @@ -327,10 +382,7 @@ func (e *Masq) marshal(fam byte) ([]byte, error) { msgData = append(msgData, regsData...) } } - 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}, - }) + return msgData, nil } func (e *Masq) unmarshal(fam byte, data []byte) error { @@ -377,17 +429,7 @@ type Cmp struct { } func (e *Cmp) marshal(fam byte) ([]byte, error) { - cmpData, err := netlink.MarshalAttributes([]netlink.Attribute{ - {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}, - }) + exprData, err := e.marshalData(fam) if err != nil { return nil, err } @@ -397,6 +439,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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/exthdr.go b/expr/exthdr.go index df0c7db..0a9d9fc 100644 --- a/expr/exthdr.go +++ b/expr/exthdr.go @@ -40,6 +40,17 @@ type Exthdr struct { } 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 // 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)}) } - data, err := 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}, - }) + return netlink.MarshalAttributes(attr) } func (e *Exthdr) unmarshal(fam byte, data []byte) error { diff --git a/expr/fib.go b/expr/fib.go index f7ee704..62a717c 100644 --- a/expr/fib.go +++ b/expr/fib.go @@ -37,6 +37,17 @@ type Fib struct { } 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{} reg, err := netlink.MarshalAttributes([]netlink.Attribute{ {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...) } - - 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}, - }) + return data, nil } func (e *Fib) unmarshal(fam byte, data []byte) error { diff --git a/expr/flow_offload.go b/expr/flow_offload.go index 54f956f..de4949a 100644 --- a/expr/flow_offload.go +++ b/expr/flow_offload.go @@ -28,9 +28,7 @@ type FlowOffload struct { } func (e *FlowOffload) marshal(fam byte) ([]byte, error) { - data, err := netlink.MarshalAttributes([]netlink.Attribute{ - {Type: NFTNL_EXPR_FLOW_TABLE_NAME, Data: []byte(e.Name)}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/hash.go b/expr/hash.go index e8506b9..92b9eea 100644 --- a/expr/hash.go +++ b/expr/hash.go @@ -41,6 +41,17 @@ type Hash struct { } 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{ {Type: unix.NFTA_HASH_SREG, Data: binaryutil.BigEndian.PutUint32(uint32(e.SourceRegister))}, {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_TYPE, Data: binaryutil.BigEndian.PutUint32(uint32(e.Type))}, }...) - data, err := 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}, - }) + return netlink.MarshalAttributes(hashAttrs) } func (e *Hash) unmarshal(fam byte, data []byte) error { diff --git a/expr/immediate.go b/expr/immediate.go index 99531f8..19eea44 100644 --- a/expr/immediate.go +++ b/expr/immediate.go @@ -29,6 +29,17 @@ type Immediate struct { } 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{ {Type: unix.NFTA_DATA_VALUE, Data: e.Data}, }) @@ -36,17 +47,10 @@ func (e *Immediate) marshal(fam byte) ([]byte, error) { 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.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 { diff --git a/expr/limit.go b/expr/limit.go index 9ecb41f..9d2facc 100644 --- a/expr/limit.go +++ b/expr/limit.go @@ -72,6 +72,18 @@ type Limit struct { } 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 if l.Over { 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)}, } - data, err := 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}, - }) + return netlink.MarshalAttributes(attrs) } func (l *Limit) unmarshal(fam byte, data []byte) error { diff --git a/expr/log.go b/expr/log.go index a712b99..eaa057a 100644 --- a/expr/log.go +++ b/expr/log.go @@ -69,6 +69,18 @@ type Log struct { } 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 attrs := make([]netlink.Attribute, 0) if e.Key&(1< 0 { 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)}) } - data, err := 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}, - }) + return netlink.MarshalAttributes(attrs) } func (e *Redir) unmarshal(fam byte, data []byte) error { diff --git a/expr/reject.go b/expr/reject.go index a742626..7fe216d 100644 --- a/expr/reject.go +++ b/expr/reject.go @@ -28,10 +28,7 @@ type Reject struct { } func (e *Reject) marshal(fam byte) ([]byte, error) { - data, err := 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}}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { ad, err := netlink.NewAttributeDecoder(data) if err != nil { diff --git a/expr/rt.go b/expr/rt.go index c3be7ff..21c3a63 100644 --- a/expr/rt.go +++ b/expr/rt.go @@ -37,10 +37,7 @@ type Rt struct { } func (e *Rt) marshal(fam byte) ([]byte, error) { - data, err := 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)}, - }) + data, err := e.marshalData(fam) if err != nil { 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 { return fmt.Errorf("not yet implemented") } diff --git a/expr/socket.go b/expr/socket.go index 1b6bc24..e3843cc 100644 --- a/expr/socket.go +++ b/expr/socket.go @@ -49,23 +49,26 @@ const ( ) 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: // http://git.netfilter.org/nftables/tree/src/netlink_linearize.c?id=0583bac241ea18c9d7f61cb20ca04faa1e043b78#n319 - exprData, err := netlink.MarshalAttributes( + return netlink.MarshalAttributes( []netlink.Attribute{ {Type: NFTA_SOCKET_DREG, Data: binaryutil.BigEndian.PutUint32(e.Register)}, {Type: NFTA_SOCKET_KEY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Key))}, {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 { diff --git a/expr/target.go b/expr/target.go index e531a9f..d1c800b 100644 --- a/expr/target.go +++ b/expr/target.go @@ -21,6 +21,17 @@ type Target struct { } 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 name := e.Name // 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}, } - data, err := 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}, - }) + return netlink.MarshalAttributes(attrs) } func (e *Target) unmarshal(fam byte, data []byte) error { diff --git a/expr/tproxy.go b/expr/tproxy.go index 2846aab..142740c 100644 --- a/expr/tproxy.go +++ b/expr/tproxy.go @@ -40,6 +40,17 @@ type TProxy struct { } 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{ {Type: NFTA_TPROXY_FAMILY, Data: binaryutil.BigEndian.PutUint32(uint32(e.Family))}, {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) - 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}, - }) + return netlink.MarshalAttributes(attrs) } func (e *TProxy) unmarshal(fam byte, data []byte) error { diff --git a/expr/verdict.go b/expr/verdict.go index 421fa06..239b408 100644 --- a/expr/verdict.go +++ b/expr/verdict.go @@ -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{ {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 } - 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.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 { diff --git a/internal/parseexprfunc/parseexprfunc.go b/internal/parseexprfunc/parseexprfunc.go index 523859d..5861461 100644 --- a/internal/parseexprfunc/parseexprfunc.go +++ b/internal/parseexprfunc/parseexprfunc.go @@ -5,6 +5,7 @@ import ( ) var ( - ParseExprBytesFunc func(fam byte, ad *netlink.AttributeDecoder, b []byte) ([]interface{}, error) - ParseExprMsgFunc func(fam byte, b []byte) ([]interface{}, error) + ParseExprBytesFromNameFunc func(fam byte, ad *netlink.AttributeDecoder, exprName string) ([]interface{}, error) + ParseExprBytesFunc func(fam byte, ad *netlink.AttributeDecoder) ([]interface{}, error) + ParseExprMsgFunc func(fam byte, b []byte) ([]interface{}, error) ) diff --git a/set.go b/set.go index 192c619..36163a9 100644 --- a/set.go +++ b/set.go @@ -321,7 +321,7 @@ func (s *SetElement) decode(fam byte) func(b []byte) error { case unix.NFTA_SET_ELEM_EXPIRATION: s.Expires = time.Millisecond * time.Duration(ad.Uint64()) case unix.NFTA_SET_ELEM_EXPR: - elems, err := parseexprfunc.ParseExprBytesFunc(fam, ad, ad.Bytes()) + elems, err := parseexprfunc.ParseExprBytesFunc(fam, ad) if err != nil { return err }