Compare commits

..

2 Commits

Author SHA1 Message Date
turekt e82ba6dbb9
Merge 533a9343c8 into aa8348f790 2024-06-25 21:07:54 +00:00
turekt 533a9343c8 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-06-25 21:07:40 +00:00
1 changed files with 51 additions and 86 deletions

137
obj.go
View File

@ -69,9 +69,6 @@ type Obj interface {
objType() ObjType objType() ObjType
} }
// ObjAttr represents nftables stateful object attributes
// Corresponds to netfilter nft_object_attributes as per
// https://git.netfilter.org/libnftnl/tree/include/linux/netfilter/nf_tables.h?id=116e95aa7b6358c917de8c69f6f173874030b46b#n1626
type ObjAttr struct { type ObjAttr struct {
Table *Table Table *Table
Name string Name string
@ -157,32 +154,17 @@ func (cc *Conn) DeleteObject(o Obj) {
// GetObj is a legacy method that return all Obj that belongs // GetObj is a legacy method that return all Obj that belongs
// to the same table as the given one // to the same table as the given one
// This function will determine whether returned object will be
// one of legacy types QuotaObj/CounterObj or the new ObjAttr
// type struct based passed o parameter type
// If o is of type ObjAttr, the implementation will work with
// the new ObjAttr type, otherwise falls back to legacy QuotaObj/CounterObj
func (cc *Conn) GetObj(o Obj) ([]Obj, error) { func (cc *Conn) GetObj(o Obj) ([]Obj, error) {
return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ, cc.useLegacyObjType(o)) return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ, cc.useLegacyObjType(o))
} }
// GetObjReset is a legacy method that reset all Obj that belongs // GetObjReset is a legacy method that reset all Obj that belongs
// the same table as the given one // the same table as the given one
// This function will determine whether returned object will be
// one of legacy types QuotaObj/CounterObj or the new ObjAttr
// type struct based passed o parameter type
// If o is of type ObjAttr, the implementation will work with
// the new ObjAttr type, otherwise falls back to legacy QuotaObj/CounterObj
func (cc *Conn) GetObjReset(o Obj) ([]Obj, error) { func (cc *Conn) GetObjReset(o Obj) ([]Obj, error) {
return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ_RESET, cc.useLegacyObjType(o)) return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ_RESET, cc.useLegacyObjType(o))
} }
// GetObject gets the specified Object // GetObject gets the specified Object
// This function will determine whether returned object will be
// one of legacy types QuotaObj/CounterObj or the new ObjAttr
// type struct based passed o parameter type
// If o is of type ObjAttr, the implementation will work with
// the new ObjAttr type, otherwise falls back to legacy QuotaObj/CounterObj
func (cc *Conn) GetObject(o Obj) (Obj, error) { func (cc *Conn) GetObject(o Obj) (Obj, error) {
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ) objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ)
@ -194,18 +176,11 @@ func (cc *Conn) GetObject(o Obj) (Obj, error) {
} }
// GetObjects get all the Obj that belongs to the given table // GetObjects get all the Obj that belongs to the given table
// This function will always return legacy QuotaObj/CounterObj
// types for backwards compatibility
func (cc *Conn) GetObjects(t *Table) ([]Obj, error) { func (cc *Conn) GetObjects(t *Table) ([]Obj, error) {
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ) return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ)
} }
// ResetObject reset the given Obj // ResetObject reset the given Obj
// This function will determine whether returned object will be
// one of legacy types QuotaObj/CounterObj or the new ObjAttr
// type struct based passed o parameter type
// If o is of type ObjAttr, the implementation will work with
// the new ObjAttr type, otherwise falls back to legacy QuotaObj/CounterObj
func (cc *Conn) ResetObject(o Obj) (Obj, error) { func (cc *Conn) ResetObject(o Obj) (Obj, error) {
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ_RESET) objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ_RESET)
@ -217,8 +192,6 @@ func (cc *Conn) ResetObject(o Obj) (Obj, error) {
} }
// ResetObjects reset all the Obj that belongs to the given table // ResetObjects reset all the Obj that belongs to the given table
// This function will always return legacy QuotaObj/CounterObj
// types for backwards compatibility
func (cc *Conn) ResetObjects(t *Table) ([]Obj, error) { func (cc *Conn) ResetObjects(t *Table) ([]Obj, error) {
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ_RESET) return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ_RESET)
} }
@ -246,30 +219,61 @@ func objFromMsg(msg netlink.Message, returnLegacyType bool) (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:
if returnLegacyType { if !returnLegacyType {
return objDataFromMsgLegacy(ad, table, name, objectType) o := ObjAttr{
Table: table,
Name: name,
Type: ObjType(objectType),
}
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()
} }
o := ObjAttr{ switch objectType {
Table: table, case unix.NFT_OBJECT_COUNTER:
Name: name, o := CounterObj{
Type: ObjType(objectType), Table: table,
} Name: name,
}
objs, err := parseexprfunc.ParseExprBytesFunc(byte(o.family()), ad, objByObjTypeMagic[o.Type]) ad.Do(func(b []byte) error {
if err != nil { ad, err := netlink.NewAttributeDecoder(b)
return nil, err if err != nil {
} return err
exprs := make([]expr.Any, len(objs)) }
for i := range exprs { ad.ByteOrder = binary.BigEndian
exprs[i] = objs[i].(expr.Any) return o.unmarshal(ad)
} })
if len(exprs) == 0 { return &o, ad.Err()
return nil, fmt.Errorf("objFromMsg: exprs is empty for obj %v", o) case unix.NFT_OBJECT_QUOTA:
} o := QuotaObj{
Table: table,
Name: name,
}
o.Obj = exprs[0] ad.Do(func(b []byte) error {
return &o, ad.Err() ad, err := netlink.NewAttributeDecoder(b)
if err != nil {
return err
}
ad.ByteOrder = binary.BigEndian
return o.unmarshal(ad)
})
return &o, ad.Err()
}
} }
} }
if err := ad.Err(); err != nil { if err := ad.Err(); err != nil {
@ -278,45 +282,6 @@ func objFromMsg(msg netlink.Message, returnLegacyType bool) (Obj, error) {
return nil, fmt.Errorf("malformed stateful object") return nil, fmt.Errorf("malformed stateful object")
} }
func objDataFromMsgLegacy(ad *netlink.AttributeDecoder, table *Table, name string, objectType uint32) (Obj, error) {
switch objectType {
case unix.NFT_OBJECT_COUNTER:
o := CounterObj{
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()
case unix.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()
}
if err := ad.Err(); err != nil {
return nil, err
}
return nil, fmt.Errorf("malformed stateful object")
}
func (cc *Conn) getObj(o Obj, t *Table, msgType uint16) ([]Obj, error) { func (cc *Conn) getObj(o Obj, t *Table, msgType uint16) ([]Obj, error) {
return cc.getObjWithLegacyType(o, t, msgType, cc.useLegacyObjType(o)) return cc.getObjWithLegacyType(o, t, msgType, cc.useLegacyObjType(o))
} }