Skip to content

Commit

Permalink
link: add netfilter support
Browse files Browse the repository at this point in the history
Signed-off-by: Mehrdad Arshad Rad <arshad.rad@gmail.com>
  • Loading branch information
mehrdadrad committed Jan 17, 2024
1 parent bfbacc1 commit 68e0e76
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 0 deletions.
11 changes: 11 additions & 0 deletions internal/cmd/gentypes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ import (
rename("cnt", "count"),
},
},
{
"LinkCreateNetfilter", retFd, "link_create", "BPF_LINK_CREATE",
[]patch{
chooseNth(4, 5),
modify(func(m *btf.Member) error {
return rename("flags", "netfilter_flags")(m.Type.(*btf.Struct))
}, "netfilter"),
flattenAnon,
},
},
{
"LinkCreateTracing", retFd, "link_create", "BPF_LINK_CREATE",
[]patch{
Expand Down Expand Up @@ -548,6 +558,7 @@ import (
{"TcxLinkInfo", "tcx", []patch{
replace(enumTypes["AttachType"], "attach_type"),
}},
{"NFLinkInfo", "netfilter", nil},
}

sort.Slice(linkInfoExtraTypes, func(i, j int) bool {
Expand Down
27 changes: 27 additions & 0 deletions internal/sys/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions link/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ func wrapRawLink(raw *RawLink) (_ Link, err error) {
return nil, fmt.Errorf("recovering perf event fd: %w", ErrNotSupported)
case TCXType:
return &tcxLink{*raw}, nil
case NFType:
return &nfLink{*raw}, nil
default:
return raw, nil
}
Expand Down Expand Up @@ -135,6 +137,7 @@ type CgroupInfo sys.CgroupLinkInfo
type NetNsInfo sys.NetNsLinkInfo
type XDPInfo sys.XDPLinkInfo
type TCXInfo sys.TcxLinkInfo
type NFInfo sys.NFLinkInfo

// Tracing returns tracing type-specific link info.
//
Expand Down Expand Up @@ -176,6 +179,14 @@ func (r Info) TCX() *TCXInfo {
return e
}

// NF returns netfilter type-specific link info.
//
// Returns nil if the type-specific link info isn't available.
func (r Info) NF() *NFInfo {
e, _ := r.extra.(*NFInfo)
return e
}

// RawLink is the low-level API to bpf_link.
//
// You should consider using the higher level interfaces in this
Expand Down Expand Up @@ -328,6 +339,8 @@ func (l *RawLink) Info() (*Info, error) {
// Extra metadata not supported.
case TCXType:
extra = &TCXInfo{}
case NFType:
extra = &NFInfo{}
default:
return nil, fmt.Errorf("unknown link info type: %d", info.Type)
}
Expand Down
5 changes: 5 additions & 0 deletions link/link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ func testLink(t *testing.T, link Link, prog *ebpf.Program) {
if tcx.Ifindex == 0 {
t.Fatalf("Failed to get link TCX extra info")
}
case sys.BPF_LINK_TYPE_NETFILTER:
nf := info.NF()
if nf.Priority == 0 {
t.Fatalf("Failed to get link Netfilter extra info")
}
}
})

Expand Down
92 changes: 92 additions & 0 deletions link/netfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package link

import (
"fmt"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal/sys"
)

const NFIPDefrag NFAttachFlags = 0 // Enable IP packet defragmentation

const (
NFINETPrerouting NFHook = iota // NF_INET_PRE_ROUTING
NFINETLocalIn // NF_INET_LOCAL_IN
NFINETForward // NF_INET_FORWARD
NFINETLocalOut // NF_INET_LOCAL_OUT
NFINETPostrouting // NF_INET_POST_ROUTING
NFINETIngress // NF_INET_INGRESS
)

const (
ProtoUnspec NFProtoFamily = 0 // NFPROTO_UNSPEC
ProtoInet NFProtoFamily = 1 // NFPROTO_INET
ProtoIPv4 NFProtoFamily = 2 // NFPROTO_IPV4
ProtoARP NFProtoFamily = 3 // NFPROTO_ARP
ProtoNetDev NFProtoFamily = 5 // NFPROTO_NETDEV
ProtoBridge NFProtoFamily = 7 // NFPROTO_BRIDGE
ProtoIPv6 NFProtoFamily = 10 // NFPROTO_IPV6
ProtoDECNet NFProtoFamily = 12 // NFPROTO_DECNET
)

type NFProtoFamily uint8
type NFHook uint8
type NFAttachFlags uint32

type NetfilterOptions struct {
// Program must be a netfilter BPF program.
Program *ebpf.Program
// The protocol family.
ProtocolFamily NFProtoFamily
// The number of the hook you are interested in.
HookNumber NFHook
// Priority within hook
Priority int32
// Extra link flags
Flags uint32
// Netfilter flags
NetfilterFlags NFAttachFlags
}

type nfLink struct {
RawLink
}

// AttachNetfilter links a netfilter BPF program to a netfilter hook.
func AttachNetfilter(opts NetfilterOptions) (Link, error) {
if opts.Program == nil {
return nil, fmt.Errorf("netfilter program is nil")
}

if t := opts.Program.Type(); t != ebpf.Netfilter {
return nil, fmt.Errorf("invalid program type %s, expected netfilter", t)
}

progFd := opts.Program.FD()
if progFd < 0 {
return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
}

attr := sys.LinkCreateNetfilterAttr{
ProgFd: uint32(opts.Program.FD()),
AttachType: uint32(sys.BPF_NETFILTER),
Flags: opts.Flags,
Pf: uint32(opts.ProtocolFamily),
Hooknum: uint32(opts.HookNumber),
Priority: opts.Priority,
NetfilterFlags: uint32(opts.NetfilterFlags),
}

fd, err := sys.LinkCreateNetfilter(&attr)
if err != nil {
return nil, fmt.Errorf("attach netfilter link: %w", err)
}

return &nfLink{RawLink{fd, ""}}, nil
}

func (*nfLink) Update(new *ebpf.Program) error {
return fmt.Errorf("netfilter update: %w", ErrNotSupported)
}

var _ Link = (*nfLink)(nil)
26 changes: 26 additions & 0 deletions link/netfilter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package link

import (
"testing"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal/testutils"
)

func TestAttachNetfilter(t *testing.T) {
testutils.SkipOnOldKernel(t, "6.4", "BPF_LINK_TYPE_NETFILTER")

prog := mustLoadProgram(t, ebpf.Netfilter, ebpf.AttachNetfilter, "")

l, err := AttachNetfilter(NetfilterOptions{
Program: prog,
ProtocolFamily: ProtoIPv4,
HookNumber: NFINETLocalOut,
Priority: -128,
})
if err != nil {
t.Fatal(err)
}

testLink(t, l, prog)
}
1 change: 1 addition & 0 deletions link/syscalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT
KprobeMultiType = sys.BPF_LINK_TYPE_KPROBE_MULTI
TCXType = sys.BPF_LINK_TYPE_TCX
NFType = sys.BPF_LINK_TYPE_NETFILTER
)

var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
Expand Down

0 comments on commit 68e0e76

Please sign in to comment.