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 (
|
2019-06-19 06:14:23 -05:00
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
2019-05-03 16:54:09 -05:00
|
|
|
"math"
|
|
|
|
|
|
|
|
"github.com/google/nftables/binaryutil"
|
|
|
|
"github.com/mdlayher/netlink"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ChainHook specifies at which step in packet processing the Chain should be
|
|
|
|
// executed. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_hooks
|
|
|
|
type ChainHook uint32
|
|
|
|
|
|
|
|
// Possible ChainHook values.
|
2022-09-06 10:27:20 -05:00
|
|
|
var (
|
|
|
|
ChainHookPrerouting *ChainHook = ChainHookRef(unix.NF_INET_PRE_ROUTING)
|
|
|
|
ChainHookInput *ChainHook = ChainHookRef(unix.NF_INET_LOCAL_IN)
|
|
|
|
ChainHookForward *ChainHook = ChainHookRef(unix.NF_INET_FORWARD)
|
|
|
|
ChainHookOutput *ChainHook = ChainHookRef(unix.NF_INET_LOCAL_OUT)
|
|
|
|
ChainHookPostrouting *ChainHook = ChainHookRef(unix.NF_INET_POST_ROUTING)
|
|
|
|
ChainHookIngress *ChainHook = ChainHookRef(unix.NF_NETDEV_INGRESS)
|
2024-03-12 09:13:11 -05:00
|
|
|
ChainHookEgress *ChainHook = ChainHookRef(unix.NF_NETDEV_EGRESS)
|
2019-05-03 16:54:09 -05:00
|
|
|
)
|
|
|
|
|
2022-09-06 10:27:20 -05:00
|
|
|
// ChainHookRef returns a pointer to a ChainHookRef value.
|
|
|
|
func ChainHookRef(h ChainHook) *ChainHook {
|
|
|
|
return &h
|
|
|
|
}
|
|
|
|
|
2019-05-03 16:54:09 -05:00
|
|
|
// ChainPriority orders the chain relative to Netfilter internal operations. See
|
|
|
|
// also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority
|
|
|
|
type ChainPriority int32
|
|
|
|
|
|
|
|
// Possible ChainPriority values.
|
2022-09-06 10:27:20 -05:00
|
|
|
var ( // from /usr/include/linux/netfilter_ipv4.h
|
|
|
|
ChainPriorityFirst *ChainPriority = ChainPriorityRef(math.MinInt32)
|
|
|
|
ChainPriorityConntrackDefrag *ChainPriority = ChainPriorityRef(-400)
|
|
|
|
ChainPriorityRaw *ChainPriority = ChainPriorityRef(-300)
|
|
|
|
ChainPrioritySELinuxFirst *ChainPriority = ChainPriorityRef(-225)
|
|
|
|
ChainPriorityConntrack *ChainPriority = ChainPriorityRef(-200)
|
|
|
|
ChainPriorityMangle *ChainPriority = ChainPriorityRef(-150)
|
|
|
|
ChainPriorityNATDest *ChainPriority = ChainPriorityRef(-100)
|
|
|
|
ChainPriorityFilter *ChainPriority = ChainPriorityRef(0)
|
|
|
|
ChainPrioritySecurity *ChainPriority = ChainPriorityRef(50)
|
|
|
|
ChainPriorityNATSource *ChainPriority = ChainPriorityRef(100)
|
|
|
|
ChainPrioritySELinuxLast *ChainPriority = ChainPriorityRef(225)
|
|
|
|
ChainPriorityConntrackHelper *ChainPriority = ChainPriorityRef(300)
|
|
|
|
ChainPriorityConntrackConfirm *ChainPriority = ChainPriorityRef(math.MaxInt32)
|
|
|
|
ChainPriorityLast *ChainPriority = ChainPriorityRef(math.MaxInt32)
|
2019-05-03 16:54:09 -05:00
|
|
|
)
|
|
|
|
|
2022-09-06 10:27:20 -05:00
|
|
|
// ChainPriorityRef returns a pointer to a ChainPriority value.
|
|
|
|
func ChainPriorityRef(p ChainPriority) *ChainPriority {
|
|
|
|
return &p
|
|
|
|
}
|
|
|
|
|
2019-05-03 16:54:09 -05:00
|
|
|
// ChainType defines what this chain will be used for. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types
|
|
|
|
type ChainType string
|
|
|
|
|
|
|
|
// Possible ChainType values.
|
|
|
|
const (
|
|
|
|
ChainTypeFilter ChainType = "filter"
|
|
|
|
ChainTypeRoute ChainType = "route"
|
|
|
|
ChainTypeNAT ChainType = "nat"
|
|
|
|
)
|
|
|
|
|
2019-10-16 04:43:00 -05:00
|
|
|
// ChainPolicy defines what this chain default policy will be.
|
|
|
|
type ChainPolicy uint32
|
|
|
|
|
|
|
|
// Possible ChainPolicy values.
|
|
|
|
const (
|
|
|
|
ChainPolicyDrop ChainPolicy = iota
|
|
|
|
ChainPolicyAccept
|
|
|
|
)
|
|
|
|
|
2019-05-03 16:54:09 -05:00
|
|
|
// A Chain contains Rules. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
|
|
|
|
type Chain struct {
|
|
|
|
Name string
|
|
|
|
Table *Table
|
2022-09-06 10:27:20 -05:00
|
|
|
Hooknum *ChainHook
|
|
|
|
Priority *ChainPriority
|
2019-05-03 16:54:09 -05:00
|
|
|
Type ChainType
|
2019-10-16 04:43:47 -05:00
|
|
|
Policy *ChainPolicy
|
2024-03-12 09:14:24 -05:00
|
|
|
Device string
|
2019-05-03 16:54:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddChain adds the specified Chain. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Adding_base_chains
|
|
|
|
func (cc *Conn) AddChain(c *Chain) *Chain {
|
2022-05-09 06:25:29 -05:00
|
|
|
cc.mu.Lock()
|
|
|
|
defer cc.mu.Unlock()
|
2019-05-03 16:54:09 -05:00
|
|
|
data := cc.marshalAttr([]netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_CHAIN_TABLE, Data: []byte(c.Table.Name + "\x00")},
|
|
|
|
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(c.Name + "\x00")},
|
|
|
|
})
|
|
|
|
|
2022-09-06 10:27:20 -05:00
|
|
|
if c.Hooknum != nil && c.Priority != nil {
|
2019-07-20 11:32:43 -05:00
|
|
|
hookAttr := []netlink.Attribute{
|
2022-09-06 10:27:20 -05:00
|
|
|
{Type: unix.NFTA_HOOK_HOOKNUM, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Hooknum))},
|
|
|
|
{Type: unix.NFTA_HOOK_PRIORITY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Priority))},
|
2019-07-20 11:32:43 -05:00
|
|
|
}
|
2024-03-12 09:14:24 -05:00
|
|
|
|
|
|
|
if c.Device != "" {
|
|
|
|
hookAttr = append(hookAttr, netlink.Attribute{Type: unix.NFTA_HOOK_DEV, Data: []byte(c.Device + "\x00")})
|
|
|
|
}
|
|
|
|
|
2019-07-20 11:32:43 -05:00
|
|
|
data = append(data, cc.marshalAttr([]netlink.Attribute{
|
|
|
|
{Type: unix.NLA_F_NESTED | unix.NFTA_CHAIN_HOOK, Data: cc.marshalAttr(hookAttr)},
|
|
|
|
})...)
|
|
|
|
}
|
|
|
|
|
2019-10-16 04:43:47 -05:00
|
|
|
if c.Policy != nil {
|
2019-07-20 11:32:43 -05:00
|
|
|
data = append(data, cc.marshalAttr([]netlink.Attribute{
|
2019-10-16 04:43:47 -05:00
|
|
|
{Type: unix.NFTA_CHAIN_POLICY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Policy))},
|
2019-07-20 11:32:43 -05:00
|
|
|
})...)
|
|
|
|
}
|
|
|
|
if c.Type != "" {
|
2019-06-24 11:00:28 -05:00
|
|
|
data = append(data, cc.marshalAttr([]netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_CHAIN_TYPE, Data: []byte(c.Type + "\x00")},
|
|
|
|
})...)
|
|
|
|
}
|
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_NEWCHAIN),
|
|
|
|
Flags: netlink.Request | netlink.Acknowledge | netlink.Create,
|
|
|
|
},
|
|
|
|
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
|
|
|
|
})
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
2019-06-19 06:14:23 -05:00
|
|
|
|
2019-07-11 07:30:38 -05:00
|
|
|
// DelChain deletes the specified Chain. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Deleting_chains
|
|
|
|
func (cc *Conn) DelChain(c *Chain) {
|
2022-05-09 06:25:29 -05:00
|
|
|
cc.mu.Lock()
|
|
|
|
defer cc.mu.Unlock()
|
2019-07-11 07:30:38 -05:00
|
|
|
data := cc.marshalAttr([]netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_CHAIN_TABLE, Data: []byte(c.Table.Name + "\x00")},
|
|
|
|
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(c.Name + "\x00")},
|
|
|
|
})
|
|
|
|
|
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-07-11 07:30:38 -05:00
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELCHAIN),
|
|
|
|
Flags: netlink.Request | netlink.Acknowledge,
|
|
|
|
},
|
|
|
|
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-23 07:18:45 -05:00
|
|
|
// FlushChain removes all rules within the specified Chain. See also
|
|
|
|
// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Flushing_chain
|
|
|
|
func (cc *Conn) FlushChain(c *Chain) {
|
2022-05-09 06:25:29 -05:00
|
|
|
cc.mu.Lock()
|
|
|
|
defer cc.mu.Unlock()
|
2019-10-23 07:18:45 -05:00
|
|
|
data := cc.marshalAttr([]netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_RULE_TABLE, Data: []byte(c.Table.Name + "\x00")},
|
|
|
|
{Type: unix.NFTA_RULE_CHAIN, Data: []byte(c.Name + "\x00")},
|
|
|
|
})
|
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-10-23 07:18:45 -05:00
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELRULE),
|
|
|
|
Flags: netlink.Request | netlink.Acknowledge,
|
|
|
|
},
|
|
|
|
Data: append(extraHeader(uint8(c.Table.Family), 0), data...),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-19 06:14:23 -05:00
|
|
|
// ListChains returns currently configured chains in the kernel
|
|
|
|
func (cc *Conn) ListChains() ([]*Chain, error) {
|
2022-06-07 10:23:05 -05:00
|
|
|
return cc.ListChainsOfTableFamily(TableFamilyUnspecified)
|
|
|
|
}
|
|
|
|
|
2024-04-14 04:19:27 -05:00
|
|
|
// ListChain returns a single chain configured in the specified table
|
|
|
|
func (cc *Conn) ListChain(table *Table, chain string) (*Chain, error) {
|
|
|
|
conn, closer, err := cc.netlinkConn()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer func() { _ = closer() }()
|
|
|
|
|
|
|
|
attrs := []netlink.Attribute{
|
|
|
|
{Type: unix.NFTA_TABLE_NAME, Data: []byte(table.Name + "\x00")},
|
|
|
|
{Type: unix.NFTA_CHAIN_NAME, Data: []byte(chain + "\x00")},
|
|
|
|
}
|
|
|
|
msg := netlink.Message{
|
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETCHAIN),
|
|
|
|
Flags: netlink.Request,
|
|
|
|
},
|
|
|
|
Data: append(extraHeader(uint8(table.Family), 0), cc.marshalAttr(attrs)...),
|
|
|
|
}
|
|
|
|
|
|
|
|
response, err := conn.Execute(msg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("conn.Execute failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := len(response), 1; got != want {
|
|
|
|
return nil, fmt.Errorf("expected %d response message for chain, got %d", want, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
ch, err := chainFromMsg(response[0])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ch, nil
|
|
|
|
}
|
|
|
|
|
2022-06-07 10:23:05 -05:00
|
|
|
// ListChainsOfTableFamily returns currently configured chains for the specified
|
|
|
|
// family in the kernel. It lists all chains ins all tables if family is
|
|
|
|
// TableFamilyUnspecified.
|
|
|
|
func (cc *Conn) ListChainsOfTableFamily(family TableFamily) ([]*Chain, error) {
|
2022-05-09 06:25:29 -05:00
|
|
|
conn, closer, err := cc.netlinkConn()
|
2019-06-19 06:14:23 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-05-09 06:25:29 -05:00
|
|
|
defer func() { _ = closer() }()
|
2019-06-19 06:14:23 -05:00
|
|
|
|
|
|
|
msg := netlink.Message{
|
|
|
|
Header: netlink.Header{
|
|
|
|
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETCHAIN),
|
|
|
|
Flags: netlink.Request | netlink.Dump,
|
|
|
|
},
|
2022-06-07 10:23:05 -05:00
|
|
|
Data: extraHeader(uint8(family), 0),
|
2019-06-19 06:14:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
response, err := conn.Execute(msg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var chains []*Chain
|
|
|
|
for _, m := range response {
|
|
|
|
c, err := chainFromMsg(m)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
chains = append(chains, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
return chains, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func chainFromMsg(msg netlink.Message) (*Chain, error) {
|
2023-12-13 01:23:07 -06:00
|
|
|
newChainHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWCHAIN)
|
|
|
|
delChainHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELCHAIN)
|
|
|
|
if got, want1, want2 := msg.Header.Type, newChainHeaderType, delChainHeaderType; got != want1 && got != want2 {
|
|
|
|
return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2)
|
2019-06-19 06:14:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
var c Chain
|
|
|
|
|
|
|
|
ad, err := netlink.NewAttributeDecoder(msg.Data[4:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for ad.Next() {
|
|
|
|
switch ad.Type() {
|
|
|
|
case unix.NFTA_CHAIN_NAME:
|
|
|
|
c.Name = ad.String()
|
|
|
|
case unix.NFTA_TABLE_NAME:
|
|
|
|
c.Table = &Table{Name: ad.String()}
|
2019-08-12 01:51:06 -05:00
|
|
|
// msg[0] carries TableFamily byte indicating whether it is IPv4, IPv6 or something else
|
|
|
|
c.Table.Family = TableFamily(msg.Data[0])
|
2019-06-19 06:14:23 -05:00
|
|
|
case unix.NFTA_CHAIN_TYPE:
|
|
|
|
c.Type = ChainType(ad.String())
|
2019-07-20 11:32:43 -05:00
|
|
|
case unix.NFTA_CHAIN_POLICY:
|
2022-02-06 11:44:06 -06:00
|
|
|
policy := ChainPolicy(binaryutil.BigEndian.Uint32(ad.Bytes()))
|
2019-10-16 04:43:47 -05:00
|
|
|
c.Policy = &policy
|
2019-06-19 06:14:23 -05:00
|
|
|
case unix.NFTA_CHAIN_HOOK:
|
|
|
|
ad.Do(func(b []byte) error {
|
|
|
|
c.Hooknum, c.Priority, err = hookFromMsg(b)
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &c, nil
|
|
|
|
}
|
|
|
|
|
2022-09-06 10:27:20 -05:00
|
|
|
func hookFromMsg(b []byte) (*ChainHook, *ChainPriority, error) {
|
2019-06-19 06:14:23 -05:00
|
|
|
ad, err := netlink.NewAttributeDecoder(b)
|
|
|
|
if err != nil {
|
2022-09-06 10:27:20 -05:00
|
|
|
return nil, nil, err
|
2019-06-19 06:14:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ad.ByteOrder = binary.BigEndian
|
|
|
|
|
|
|
|
var hooknum ChainHook
|
|
|
|
var prio ChainPriority
|
|
|
|
|
|
|
|
for ad.Next() {
|
|
|
|
switch ad.Type() {
|
|
|
|
case unix.NFTA_HOOK_HOOKNUM:
|
|
|
|
hooknum = ChainHook(ad.Uint32())
|
|
|
|
case unix.NFTA_HOOK_PRIORITY:
|
|
|
|
prio = ChainPriority(ad.Uint32())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-06 10:27:20 -05:00
|
|
|
return &hooknum, &prio, nil
|
2019-06-19 06:14:23 -05:00
|
|
|
}
|