Skip to content

nickgarlis/nftnl

Repository files navigation

nftnl

PkgGoDev GitHub Go Report Card

A low-level Go library for interacting with nftables via netlink. It can be used directly or as a building block for higher-level libraries.

Example

The following builds this ruleset and queries the tables back:

table inet mytable {
    chain input {
        type filter hook input priority filter; policy accept;
    }
}
package main

import (
	"fmt"

	"github.com/mdlayher/netlink"
	"github.com/nickgarlis/nftnl"
)

func main() {
	conn, err := nftnl.Open(&nftnl.Config{})
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	batch := nftnl.NewBatch()
	batch.Add(nftnl.Msg{
		Type:   nftnl.MsgNewTable,
		Family: nftnl.FamilyInet,
		Flags:  netlink.Request | netlink.Create,
		Attrs:  &nftnl.Table{Name: "mytable"},
	})
	batch.Add(nftnl.Msg{
		Type:   nftnl.MsgNewChain,
		Family: nftnl.FamilyInet,
		Flags:  netlink.Request | netlink.Create,
		Attrs: &nftnl.Chain{
			Table:  "mytable",
			Name:   "input",
			Type:   "filter",
			Hook:   &nftnl.Hook{HookNum: nftnl.HookLocalIn, Priority: nftnl.PriorityFilter},
			Policy: new(nftnl.ChainPolicyAccept),
		},
	})
	if _, err := conn.SendBatch(batch); err != nil {
		panic(err)
	}

	// Read back all tables.
	msgs, err := conn.Send(nftnl.Msg{
		Type:   nftnl.MsgGetTable,
		Family: nftnl.FamilyInet,
		Flags:  netlink.Request | netlink.Dump,
	})
	if err != nil {
		panic(err)
	}
	for _, msg := range msgs {
		if t, ok := nftnl.As[*nftnl.Table](msg.Attrs); ok {
			fmt.Println(t.Name)
		}
	}
}

Flags

netlink flags go directly on each Msg. Use netlink.Echo to get the committed object back in the response, useful when you need the kernel-assigned handle without a separate get query:

msgs, err := conn.Send(nftnl.Msg{
	Type:   nftnl.MsgNewRule,
	Family: nftnl.FamilyInet,
	Flags:  netlink.Request | netlink.Create | netlink.Append | netlink.Echo,
	Attrs: &nftnl.Rule{
		Table:       "mytable",
		Chain:       new("input"),
		Expressions: []nftnl.Expr{ /* ... */ },
	},
})
if err != nil {
	panic(err)
}
// The response contains the committed rule with its kernel-assigned handle.
if rule, ok := nftnl.As[*nftnl.Rule](msgs[0].Attrs); ok {
	// Use rule.Handle to insert another rule after this one via Position.
	fmt.Println("handle:", *rule.Handle)
}

Helpers

The nftnl/util package provides expression builders for common rule patterns:

import "github.com/nickgarlis/nftnl/util"

exprs := util.Exprs(
    util.NFProtoIPv4(),
    util.IPv4SaddrPrefix(netip.MustParsePrefix("10.0.0.0/8")),
    util.Accept(),
)

exprs := util.Exprs(
    util.CTState(nftnl.CTStateEstablished | nftnl.CTStateRelated),
    util.Accept(),
)

exprs := util.Exprs(util.IIFName("eth0"), util.Drop())

Design

One struct per object type. The kernel uses the same attribute set for new/get/delete operations on any given object. Chain, Rule, Set, etc. work for creating, querying, and deleting alike.

Pointer fields mean optional. A *T field is sent only when set. A plain T field is always sent. Which fields are required for a given operation is for the caller to know. When in doubt, check nf_tables.h.

License

MIT, see LICENSE.

About

A low-level Go library for interacting with nftables via netlink in pure Go

Resources

License

Stars

3 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages