2019-05-03 16:54:09 -05:00
|
|
|
// Copyright 2018 Google LLC. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package nftables
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
|
2024-07-29 01:43:58 -05:00
|
|
|
"github.com/google/nftables/binaryutil"
|
|
|
|
"github.com/google/nftables/expr"
|
|
|
|
"github.com/google/nftables/internal/parseexprfunc"
|
2019-05-03 16:54:09 -05:00
|
|
|
"github.com/mdlayher/netlink"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
2025-02-26 05:27:31 -06:00
|
|
|
const (
|
2023-12-13 01:23:07 -06:00
|
|
|
newObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ)
|
|
|
|
delObjHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ)
|
|
|
|
)
|
2019-05-03 16:54:09 -05:00
|
|
|
|
2024-07-29 01:43:58 -05:00
|
|
|
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",
|
2024-08-15 01:47:35 -05:00
|
|
|
ObjTypeCtHelper: "cthelper",
|
2024-09-11 01:27:40 -05:00
|
|
|
ObjTypeTunnel: "tunnel", // not implemented in expr
|
|
|
|
ObjTypeCtTimeout: "cttimeout",
|
2024-09-09 15:56:09 -05:00
|
|
|
ObjTypeSecMark: "secmark",
|
2024-09-09 01:35:05 -05:00
|
|
|
ObjTypeCtExpect: "ctexpect",
|
|
|
|
ObjTypeSynProxy: "synproxy",
|
2024-07-29 01:43:58 -05:00
|
|
|
}
|
|
|
|
|
2019-05-03 16:54:09 -05:00
|
|
|
// Obj represents a netfilter stateful object. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects
|
|
|
|
type Obj interface {
|
2020-01-21 01:36:27 -06:00
|
|
|
table() *Table
|
2019-05-03 16:54:09 -05:00
|
|
|
family() TableFamily
|
2024-07-29 01:43:58 -05:00
|
|
|
data() expr.Any
|
|
|
|
name() string
|
|
|
|
objType() ObjType
|
|
|
|
}
|
|
|
|
|
|
|
|
// NamedObj 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 NamedObj struct {
|
|
|
|
Table *Table
|
|
|
|
Name string
|
|
|
|
Type ObjType
|
|
|
|
Obj expr.Any
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *NamedObj) table() *Table {
|
|
|
|
return o.Table
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *NamedObj) family() TableFamily {
|
|
|
|
return o.Table.Family
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *NamedObj) data() expr.Any {
|
|
|
|
return o.Obj
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *NamedObj) name() string {
|
|
|
|
return o.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *NamedObj) objType() ObjType {
|
|
|
|
return o.Type
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
|
2020-03-09 02:43:47 -05:00
|
|
|
// AddObject adds the specified Obj. Alias of AddObj.
|
|
|
|
func (cc *Conn) AddObject(o Obj) Obj {
|
|
|
|
return cc.AddObj(o)
|
|
|
|
}
|
|
|
|
|
2019-05-03 16:54:09 -05:00
|
|
|
// AddObj adds the specified Obj. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Stateful_objects
|
|
|
|
func (cc *Conn) AddObj(o Obj) Obj {
|
2022-05-09 06:25:29 -05:00
|
|
|
cc.mu.Lock()
|
|
|
|
defer cc.mu.Unlock()
|
2024-07-29 01:43:58 -05:00
|
|
|
data, err := expr.MarshalExprData(byte(o.family()), o.data())
|
2019-05-03 16:54:09 -05:00
|
|
|
if err != nil {
|
|
|
|
cc.setErr(err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-29 01:43:58 -05:00
|
|
|
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})
|
|
|
|
}
|
|
|
|
|
Set rule handle during flush
This change makes it possible to delete rules after inserting them,
without needing to query the rules first. Rules can be deleted both
before and after they are flushed. Additionally, this allows positioning
a new rule next to an existing rule, both before and after the existing
rule is flushed.
There are two ways to refer to a rule: Either by ID or by handle. The ID
is assigned by userspace, and is only valid within a transaction, so it
can only be used before the flush. The handle is assigned by the kernel
when the transaction is committed, and can thus only be used after the
flush. We thus need to set an ID on each newly created rule, and
retrieve the handle of the rule during the flush.
There was an existing mechanism to allocate IDs for sets, but this was
using a global counter without any synchronization to prevent data
races. I replaced this by a new mechanism which uses a connection-scoped
counter.
I implemented a new mechanism for retrieving replies in Flush, and
handling these replies by adding a callback to netlink messages. There
was some existing code to handle "overrun", which I deleted, because it
was nonsensical and just worked by accident. NLMSG_OVERRUN is in fact
not a flag, but a complete message type, so the (re&netlink.Overrun)
masking makes no sense. Even better, NLMSG_OVERRUN is never actually
used by Linux. What this code was actually doing was skipping over the
NFT_MSG_NEWRULE replies, and possibly a NFT_MSG_NEWGEN reply.
I had to update all existing tests which compared generated netlink
messages against a reference, by inserting the newly added ID attribute.
We also need to generate replies for the NFT_MSG_NEWRULE messages with a
handle added.
2025-02-20 13:12:30 -06:00
|
|
|
cc.messages = append(cc.messages, netlinkMessage{
|
2019-05-03 16:54:09 -05:00
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWOBJ),
|
|
|
|
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
|
|
|
|
},
|
2024-07-29 01:43:58 -05:00
|
|
|
Data: append(extraHeader(uint8(o.family()), 0), cc.marshalAttr(attrs)...),
|
2019-05-03 16:54:09 -05:00
|
|
|
})
|
|
|
|
return o
|
|
|
|
}
|
|
|
|
|
2020-03-09 02:43:47 -05:00
|
|
|
// DeleteObject deletes the specified Obj
|
|
|
|
func (cc *Conn) DeleteObject(o Obj) {
|
2022-05-09 06:25:29 -05:00
|
|
|
cc.mu.Lock()
|
|
|
|
defer cc.mu.Unlock()
|
2024-07-29 01:43:58 -05:00
|
|
|
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()))},
|
2020-03-09 02:43:47 -05:00
|
|
|
}
|
2024-07-29 01:43:58 -05:00
|
|
|
data := cc.marshalAttr(attrs)
|
2020-03-09 02:43:47 -05:00
|
|
|
data = append(data, cc.marshalAttr([]netlink.Attribute{{Type: unix.NLA_F_NESTED | unix.NFTA_OBJ_DATA}})...)
|
|
|
|
|
Set rule handle during flush
This change makes it possible to delete rules after inserting them,
without needing to query the rules first. Rules can be deleted both
before and after they are flushed. Additionally, this allows positioning
a new rule next to an existing rule, both before and after the existing
rule is flushed.
There are two ways to refer to a rule: Either by ID or by handle. The ID
is assigned by userspace, and is only valid within a transaction, so it
can only be used before the flush. The handle is assigned by the kernel
when the transaction is committed, and can thus only be used after the
flush. We thus need to set an ID on each newly created rule, and
retrieve the handle of the rule during the flush.
There was an existing mechanism to allocate IDs for sets, but this was
using a global counter without any synchronization to prevent data
races. I replaced this by a new mechanism which uses a connection-scoped
counter.
I implemented a new mechanism for retrieving replies in Flush, and
handling these replies by adding a callback to netlink messages. There
was some existing code to handle "overrun", which I deleted, because it
was nonsensical and just worked by accident. NLMSG_OVERRUN is in fact
not a flag, but a complete message type, so the (re&netlink.Overrun)
masking makes no sense. Even better, NLMSG_OVERRUN is never actually
used by Linux. What this code was actually doing was skipping over the
NFT_MSG_NEWRULE replies, and possibly a NFT_MSG_NEWGEN reply.
I had to update all existing tests which compared generated netlink
messages against a reference, by inserting the newly added ID attribute.
We also need to generate replies for the NFT_MSG_NEWRULE messages with a
handle added.
2025-02-20 13:12:30 -06:00
|
|
|
cc.messages = append(cc.messages, netlinkMessage{
|
2020-03-09 02:43:47 -05:00
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELOBJ),
|
|
|
|
Flags: netlink.Request | netlink.Acknowledge,
|
|
|
|
},
|
|
|
|
Data: append(extraHeader(uint8(o.family()), 0), data...),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
// GetObj is a legacy method that return all Obj that belongs
|
|
|
|
// to the same table as the given one
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function returns the same concrete type as passed,
|
|
|
|
// e.g. QuotaObj, CounterObj or NamedObj. Prefer using the more
|
|
|
|
// generic NamedObj over the legacy QuotaObj and CounterObj types.
|
2019-05-03 16:54:09 -05:00
|
|
|
func (cc *Conn) GetObj(o Obj) ([]Obj, error) {
|
2024-07-29 01:43:58 -05:00
|
|
|
return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ, cc.useLegacyObjType(o))
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
// GetObjReset is a legacy method that reset all Obj that belongs
|
|
|
|
// the same table as the given one
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function returns the same concrete type as passed,
|
|
|
|
// e.g. QuotaObj, CounterObj or NamedObj. Prefer using the more
|
|
|
|
// generic NamedObj over the legacy QuotaObj and CounterObj types.
|
2019-05-03 16:54:09 -05:00
|
|
|
func (cc *Conn) GetObjReset(o Obj) ([]Obj, error) {
|
2024-07-29 01:43:58 -05:00
|
|
|
return cc.getObjWithLegacyType(nil, o.table(), unix.NFT_MSG_GETOBJ_RESET, cc.useLegacyObjType(o))
|
2020-01-21 01:36:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetObject gets the specified Object
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function returns the same concrete type as passed,
|
|
|
|
// e.g. QuotaObj, CounterObj or NamedObj. Prefer using the more
|
|
|
|
// generic NamedObj over the legacy QuotaObj and CounterObj types.
|
2020-01-21 01:36:27 -06:00
|
|
|
func (cc *Conn) GetObject(o Obj) (Obj, error) {
|
|
|
|
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ)
|
2020-03-09 02:43:47 -05:00
|
|
|
|
|
|
|
if len(objs) == 0 {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
return objs[0], err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetObjects get all the Obj that belongs to the given table
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function will always return legacy QuotaObj/CounterObj
|
|
|
|
// types for backwards compatibility
|
2020-01-21 01:36:27 -06:00
|
|
|
func (cc *Conn) GetObjects(t *Table) ([]Obj, error) {
|
|
|
|
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ)
|
|
|
|
}
|
|
|
|
|
2024-08-14 01:10:09 -05:00
|
|
|
// GetNamedObjects get all the Obj that belongs to the given table
|
|
|
|
// This function always return NamedObj types
|
|
|
|
func (cc *Conn) GetNamedObjects(t *Table) ([]Obj, error) {
|
|
|
|
return cc.getObjWithLegacyType(nil, t, unix.NFT_MSG_GETOBJ, false)
|
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
// ResetObject reset the given Obj
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function returns the same concrete type as passed,
|
|
|
|
// e.g. QuotaObj, CounterObj or NamedObj. Prefer using the more
|
|
|
|
// generic NamedObj over the legacy QuotaObj and CounterObj types.
|
2020-01-21 01:36:27 -06:00
|
|
|
func (cc *Conn) ResetObject(o Obj) (Obj, error) {
|
|
|
|
objs, err := cc.getObj(o, o.table(), unix.NFT_MSG_GETOBJ_RESET)
|
2020-03-09 02:43:47 -05:00
|
|
|
|
|
|
|
if len(objs) == 0 {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
return objs[0], err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResetObjects reset all the Obj that belongs to the given table
|
2024-07-29 01:43:58 -05:00
|
|
|
// This function will always return legacy QuotaObj/CounterObj
|
|
|
|
// types for backwards compatibility
|
2020-01-21 01:36:27 -06:00
|
|
|
func (cc *Conn) ResetObjects(t *Table) ([]Obj, error) {
|
|
|
|
return cc.getObj(nil, t, unix.NFT_MSG_GETOBJ_RESET)
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
|
2024-08-14 01:10:09 -05:00
|
|
|
// ResetNamedObjects reset all the Obj that belongs to the given table
|
|
|
|
// This function always return NamedObj types
|
|
|
|
func (cc *Conn) ResetNamedObjects(t *Table) ([]Obj, error) {
|
|
|
|
return cc.getObjWithLegacyType(nil, t, unix.NFT_MSG_GETOBJ_RESET, false)
|
|
|
|
}
|
|
|
|
|
2024-07-29 01:43:58 -05:00
|
|
|
func objFromMsg(msg netlink.Message, returnLegacyType bool) (Obj, error) {
|
2023-12-13 01:23:07 -06:00
|
|
|
if got, want1, want2 := msg.Header.Type, newObjHeaderType, delObjHeaderType; got != want1 && got != want2 {
|
|
|
|
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ad.ByteOrder = binary.BigEndian
|
|
|
|
var (
|
|
|
|
table *Table
|
|
|
|
name string
|
|
|
|
objectType uint32
|
|
|
|
)
|
|
|
|
for ad.Next() {
|
|
|
|
switch ad.Type() {
|
|
|
|
case unix.NFTA_OBJ_TABLE:
|
|
|
|
table = &Table{Name: ad.String(), Family: TableFamily(msg.Data[0])}
|
|
|
|
case unix.NFTA_OBJ_NAME:
|
|
|
|
name = ad.String()
|
|
|
|
case unix.NFTA_OBJ_TYPE:
|
|
|
|
objectType = ad.Uint32()
|
|
|
|
case unix.NFTA_OBJ_DATA:
|
2024-07-29 01:43:58 -05:00
|
|
|
if returnLegacyType {
|
|
|
|
return objDataFromMsgLegacy(ad, table, name, objectType)
|
|
|
|
}
|
|
|
|
|
|
|
|
o := NamedObj{
|
|
|
|
Table: table,
|
|
|
|
Name: name,
|
|
|
|
Type: ObjType(objectType),
|
|
|
|
}
|
|
|
|
|
|
|
|
objs, err := parseexprfunc.ParseExprBytesFromNameFunc(byte(o.family()), ad, objByObjTypeMagic[o.Type])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(objs) == 0 {
|
|
|
|
return nil, fmt.Errorf("objFromMsg: objs is empty for obj %v", o)
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
2024-07-29 01:43:58 -05:00
|
|
|
exprs := make([]expr.Any, len(objs))
|
|
|
|
for i := range exprs {
|
|
|
|
exprs[i] = objs[i].(expr.Any)
|
|
|
|
}
|
|
|
|
|
|
|
|
o.Obj = exprs[0]
|
|
|
|
return &o, ad.Err()
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := ad.Err(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("malformed stateful object")
|
|
|
|
}
|
|
|
|
|
2024-07-29 01:43:58 -05:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
func (cc *Conn) getObj(o Obj, t *Table, msgType uint16) ([]Obj, error) {
|
2024-07-29 01:43:58 -05:00
|
|
|
return cc.getObjWithLegacyType(o, t, msgType, cc.useLegacyObjType(o))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cc *Conn) getObjWithLegacyType(o Obj, t *Table, msgType uint16, returnLegacyObjType bool) ([]Obj, error) {
|
2022-05-09 06:25:29 -05:00
|
|
|
conn, closer, err := cc.netlinkConn()
|
2019-05-03 16:54:09 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-05-09 06:25:29 -05:00
|
|
|
defer func() { _ = closer() }()
|
2019-05-03 16:54:09 -05:00
|
|
|
|
2020-01-21 01:36:27 -06:00
|
|
|
var data []byte
|
|
|
|
var flags netlink.HeaderFlags
|
|
|
|
|
|
|
|
if o != nil {
|
2024-07-29 01:43:58 -05:00
|
|
|
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)
|
2020-01-21 01:36:27 -06:00
|
|
|
} else {
|
|
|
|
flags = netlink.Dump
|
|
|
|
data, err = netlink.MarshalAttributes([]netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")},
|
|
|
|
})
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
2021-12-09 16:08:38 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 16:54:09 -05:00
|
|
|
|
|
|
|
message := netlink.Message{
|
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | msgType),
|
2020-01-21 01:36:27 -06:00
|
|
|
Flags: netlink.Request | netlink.Acknowledge | flags,
|
2019-05-03 16:54:09 -05:00
|
|
|
},
|
2020-01-21 01:36:27 -06:00
|
|
|
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := conn.SendMessages([]netlink.Message{message}); err != nil {
|
|
|
|
return nil, fmt.Errorf("SendMessages: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-10-02 09:01:48 -05:00
|
|
|
reply, err := receiveAckAware(conn, message.Header.Flags)
|
2019-05-03 16:54:09 -05:00
|
|
|
if err != nil {
|
2024-08-11 03:00:48 -05:00
|
|
|
return nil, fmt.Errorf("receiveAckAware: %v", err)
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
var objs []Obj
|
|
|
|
for _, msg := range reply {
|
2024-07-29 01:43:58 -05:00
|
|
|
o, err := objFromMsg(msg, returnLegacyObjType)
|
2019-05-03 16:54:09 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
objs = append(objs, o)
|
|
|
|
}
|
|
|
|
|
|
|
|
return objs, nil
|
|
|
|
}
|
2024-07-29 01:43:58 -05:00
|
|
|
|
|
|
|
func (cc *Conn) useLegacyObjType(o Obj) bool {
|
|
|
|
useLegacyType := true
|
|
|
|
if o != nil {
|
|
|
|
switch o.(type) {
|
|
|
|
case *NamedObj:
|
|
|
|
useLegacyType = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return useLegacyType
|
|
|
|
}
|