/
githubmirror
/
nftables
Обзор
Документация
Войти
/
githubmirror
/
nftables
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
table.go
269 строк
8 KB
Nick Garlis
Stop requesting ACKs (#336)
14 ноя 2025, 13:00
Не верифицирован
14 ноя 2025, 13:00
dca01dd
Код
Авторство
О чём код?
// 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" "github.com/google/nftables/binaryutil" "github.com/mdlayher/netlink" "golang.org/x/sys/unix" ) var ( newTableHeaderType = nftMsgNewTable.HeaderType() delTableHeaderType = nftMsgDelTable.HeaderType() destroyTableHeaderType = nftMsgDestroyTable.HeaderType() ) // TableFamily specifies the address family for this table. type TableFamily byte // Possible TableFamily values. const ( TableFamilyUnspecified TableFamily = unix.NFPROTO_UNSPEC TableFamilyINet TableFamily = unix.NFPROTO_INET TableFamilyIPv4 TableFamily = unix.NFPROTO_IPV4 TableFamilyIPv6 TableFamily = unix.NFPROTO_IPV6 TableFamilyARP TableFamily = unix.NFPROTO_ARP TableFamilyNetdev TableFamily = unix.NFPROTO_NETDEV TableFamilyBridge TableFamily = unix.NFPROTO_BRIDGE ) const ( // https://github.com/torvalds/linux/blob/cbd2257dc96e3e46217540fcb095a757ffa20d96/include/uapi/linux/netfilter/nf_tables.h#L211 nftaTableOwner = 0x07 // https://github.com/torvalds/linux/blob/cbd2257dc96e3e46217540fcb095a757ffa20d96/include/uapi/linux/netfilter/nf_tables.h#L185 nftTableFDormant = 0x1 nftTableFOwner = 0x2 nftTableFPersist = 0x4 ) type TableFlags uint32 const ( // Use TableFlagDormant to create the table in dormant state. A dormant // table does not process packets until it is explicitly activated. TableFlagDormant TableFlags = nftTableFDormant // Use TableFlagOwner to set the owner of the table to the // port ID of the creating connection. The table lifetime will // then be bound to the lifetime of that connection unless the // TableFlagPersist flag is also set. Should be used with lasting // connections. TableFlagOwner TableFlags = nftTableFOwner // Use TableFlagPersist to make the table persistent, when used // together with TableFlagOwner. A persistent table is not // automatically removed when the creating connection is closed. TableFlagPersist TableFlags = nftTableFPersist ) // A Table contains Chains. See also // https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables type Table struct { Name string // NFTA_TABLE_NAME Use uint32 // NFTA_TABLE_USE (Number of chains in table) Flags TableFlags // NFTA_TABLE_FLAGS Owner uint32 // NFTA_TABLE_OWNER Family TableFamily } // DelTable deletes a specific table, along with all chains/rules it contains. func (cc *Conn) DelTable(t *Table) { cc.delTable(t, delTableHeaderType) } // DestroyTable is like DelTable, but not an error if table doesn't exists func (cc *Conn) DestroyTable(t *Table) { cc.delTable(t, destroyTableHeaderType) } func (cc *Conn) delTable(t *Table, hdrType netlink.HeaderType) { cc.mu.Lock() defer cc.mu.Unlock() data := cc.marshalAttr([]netlink.Attribute{ {Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")}, {Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}}, }) cc.messages = append(cc.messages, netlinkMessage{ Header: netlink.Header{ Type: hdrType, Flags: netlink.Request, }, Data: append(extraHeader(uint8(t.Family), 0), data...), }) } func (cc *Conn) addTable(t *Table, flag netlink.HeaderFlags) *Table { cc.mu.Lock() defer cc.mu.Unlock() attrs := []netlink.Attribute{ {Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")}, } if t.Flags&TableFlagOwner == TableFlagOwner { pid, err := cc.getPortIDUnderLock() if err != nil { cc.setErr(fmt.Errorf("failed to get port ID: %v", err)) } attrs = append(attrs, netlink.Attribute{Type: nftaTableOwner, Data: binaryutil.BigEndian.PutUint32(pid)}) } attrs = append(attrs, netlink.Attribute{Type: unix.NFTA_TABLE_FLAGS, Data: binaryutil.BigEndian.PutUint32(uint32(t.Flags))}) data := cc.marshalAttr(attrs) cc.messages = append(cc.messages, netlinkMessage{ Header: netlink.Header{ Type: nftMsgNewTable.HeaderType(), Flags: netlink.Request | flag, }, Data: append(extraHeader(uint8(t.Family), 0), data...), }) return t } // AddTable adds the specified Table, just like `nft add table ...`. // See also https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables func (cc *Conn) AddTable(t *Table) *Table { return cc.addTable(t, netlink.Create) } // CreateTable create the specified Table if it do not existed. // just like `nft create table ...`. func (cc *Conn) CreateTable(t *Table) *Table { return cc.addTable(t, netlink.Excl) } // FlushTable removes all rules in all chains within the specified Table. See also // https://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables#Flushing_tables func (cc *Conn) FlushTable(t *Table) { cc.mu.Lock() defer cc.mu.Unlock() data := cc.marshalAttr([]netlink.Attribute{ {Type: unix.NFTA_RULE_TABLE, Data: []byte(t.Name + "\x00")}, }) cc.messages = append(cc.messages, netlinkMessage{ Header: netlink.Header{ Type: nftMsgDelRule.HeaderType(), Flags: netlink.Request, }, Data: append(extraHeader(uint8(t.Family), 0), data...), }) } // ListTable returns table found for the specified name. Searches for // the table under IPv4 family. As per nft man page: "When no address // family is specified, ip is used by default." func (cc *Conn) ListTable(name string) (*Table, error) { return cc.ListTableOfFamily(name, TableFamilyIPv4) } // ListTableOfFamily returns table found for the specified name and table family func (cc *Conn) ListTableOfFamily(name string, family TableFamily) (*Table, error) { t, err := cc.listTablesOfNameAndFamily(name, family) if err != nil { return nil, err } if got, want := len(t), 1; got != want { return nil, fmt.Errorf("expected table count %d, got %d", want, got) } return t[0], nil } // ListTables returns currently configured tables in the kernel func (cc *Conn) ListTables() ([]*Table, error) { return cc.ListTablesOfFamily(TableFamilyUnspecified) } // ListTablesOfFamily returns currently configured tables for the specified table family // in the kernel. It lists all tables if family is TableFamilyUnspecified. func (cc *Conn) ListTablesOfFamily(family TableFamily) ([]*Table, error) { return cc.listTablesOfNameAndFamily("", family) } func (cc *Conn) listTablesOfNameAndFamily(name string, family TableFamily) ([]*Table, error) { conn, closer, err := cc.netlinkConn() if err != nil { return nil, err } defer func() { _ = closer() }() data := extraHeader(uint8(family), 0) flags := netlink.Request | netlink.Dump if name != "" { data = append(data, cc.marshalAttr([]netlink.Attribute{ {Type: unix.NFTA_TABLE_NAME, Data: []byte(name + "\x00")}, })...) flags = netlink.Request } msg := netlink.Message{ Header: netlink.Header{ Type: nftMsgGetTable.HeaderType(), Flags: flags, }, Data: data, } response, err := conn.Execute(msg) if err != nil { return nil, err } var tables []*Table for _, m := range response { t, err := tableFromMsg(m) if err != nil { return nil, err } tables = append(tables, t) } return tables, nil } func tableFromMsg(msg netlink.Message) (*Table, error) { if got, want1, want2 := msg.Header.Type, newTableHeaderType, delTableHeaderType; got != want1 && got != want2 { return nil, fmt.Errorf("unexpected header type: got %v, want %v or %v", got, want1, want2) } var t Table t.Family = TableFamily(msg.Data[0]) ad, err := netlink.NewAttributeDecoder(msg.Data[4:]) if err != nil { return nil, err } ad.ByteOrder = binary.BigEndian for ad.Next() { switch ad.Type() { case unix.NFTA_TABLE_NAME: t.Name = ad.String() case unix.NFTA_TABLE_USE: t.Use = ad.Uint32() case unix.NFTA_TABLE_FLAGS: t.Flags = TableFlags(ad.Uint32()) case nftaTableOwner: t.Owner = ad.Uint32() } } return &t, nil }