| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- // 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"
- "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.
- 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)
- )
- // ChainHookRef returns a pointer to a ChainHookRef value.
- func ChainHookRef(h ChainHook) *ChainHook {
- return &h
- }
- // 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.
- 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)
- )
- // ChainPriorityRef returns a pointer to a ChainPriority value.
- func ChainPriorityRef(p ChainPriority) *ChainPriority {
- return &p
- }
- // 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"
- )
- // ChainPolicy defines what this chain default policy will be.
- type ChainPolicy uint32
- // Possible ChainPolicy values.
- const (
- ChainPolicyDrop ChainPolicy = iota
- ChainPolicyAccept
- )
- // A Chain contains Rules. See also
- // https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
- type Chain struct {
- Name string
- Table *Table
- Hooknum *ChainHook
- Priority *ChainPriority
- Type ChainType
- Policy *ChainPolicy
- }
- // 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 {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- 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")},
- })
- if c.Hooknum != nil && c.Priority != nil {
- hookAttr := []netlink.Attribute{
- {Type: unix.NFTA_HOOK_HOOKNUM, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Hooknum))},
- {Type: unix.NFTA_HOOK_PRIORITY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Priority))},
- }
- data = append(data, cc.marshalAttr([]netlink.Attribute{
- {Type: unix.NLA_F_NESTED | unix.NFTA_CHAIN_HOOK, Data: cc.marshalAttr(hookAttr)},
- })...)
- }
- if c.Policy != nil {
- data = append(data, cc.marshalAttr([]netlink.Attribute{
- {Type: unix.NFTA_CHAIN_POLICY, Data: binaryutil.BigEndian.PutUint32(uint32(*c.Policy))},
- })...)
- }
- if c.Type != "" {
- data = append(data, cc.marshalAttr([]netlink.Attribute{
- {Type: unix.NFTA_CHAIN_TYPE, Data: []byte(c.Type + "\x00")},
- })...)
- }
- cc.messages = append(cc.messages, netlink.Message{
- 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
- }
- // 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) {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- 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")},
- })
- cc.messages = append(cc.messages, netlink.Message{
- 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...),
- })
- }
- // 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) {
- cc.mu.Lock()
- defer cc.mu.Unlock()
- 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")},
- })
- cc.messages = append(cc.messages, netlink.Message{
- 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...),
- })
- }
- // ListChains returns currently configured chains in the kernel
- func (cc *Conn) ListChains() ([]*Chain, error) {
- return cc.ListChainsOfTableFamily(TableFamilyUnspecified)
- }
- // 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) {
- conn, closer, err := cc.netlinkConn()
- if err != nil {
- return nil, err
- }
- defer func() { _ = closer() }()
- msg := netlink.Message{
- Header: netlink.Header{
- Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_GETCHAIN),
- Flags: netlink.Request | netlink.Dump,
- },
- Data: extraHeader(uint8(family), 0),
- }
- 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) {
- chainHeaderType := netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWCHAIN)
- if got, want := msg.Header.Type, chainHeaderType; got != want {
- return nil, fmt.Errorf("unexpected header type: got %v, want %v", got, want)
- }
- 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()}
- // msg[0] carries TableFamily byte indicating whether it is IPv4, IPv6 or something else
- c.Table.Family = TableFamily(msg.Data[0])
- case unix.NFTA_CHAIN_TYPE:
- c.Type = ChainType(ad.String())
- case unix.NFTA_CHAIN_POLICY:
- policy := ChainPolicy(binaryutil.BigEndian.Uint32(ad.Bytes()))
- c.Policy = &policy
- case unix.NFTA_CHAIN_HOOK:
- ad.Do(func(b []byte) error {
- c.Hooknum, c.Priority, err = hookFromMsg(b)
- return err
- })
- }
- }
- return &c, nil
- }
- func hookFromMsg(b []byte) (*ChainHook, *ChainPriority, error) {
- ad, err := netlink.NewAttributeDecoder(b)
- if err != nil {
- return nil, nil, err
- }
- 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())
- }
- }
- return &hooknum, &prio, nil
- }
|