File: kernel_test.go

package info (click to toggle)
golang-github-cloudflare-cbpfc 0.0~git20231012.992ed75-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 232 kB
  • sloc: makefile: 4
file content (78 lines) | stat: -rw-r--r-- 1,946 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package cbpfc

import (
	"bytes"
	"net"
	"testing"
	"time"
	"unsafe"

	"golang.org/x/net/bpf"
	"golang.org/x/sys/unix"
)

// kernelBackend is a backend that runs cBPF in the kernel
func kernelBackend(tb testing.TB, insns []bpf.Instruction, in []byte) result {
	filter, err := bpf.Assemble(insns)
	if err != nil {
		tb.Fatal(err)
	}

	// Use a unix socket to test the filter
	// This doesn't risk interfering with any other network traffic, doesn't require / add special
	// headers (as would be the case if we used UDP for example) that the XDP tests don't deal with,
	// and doesn't require any special permissions
	read, err := net.ListenUnixgram("unixgram", &net.UnixAddr{Name: "", Net: "unixgram"})
	if err != nil {
		tb.Fatal(err)
	}
	defer read.Close()
	readConn, err := read.SyscallConn()
	if err != nil {
		tb.Fatal(err)
	}
	err = readConn.Control(func(fd uintptr) {
		err := unix.SetsockoptSockFprog(int(fd), unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, &unix.SockFprog{
			Len:    uint16(len(filter)),
			Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])),
		})
		if err != nil {
			tb.Fatal(err)
		}
	})
	if err != nil {
		tb.Fatal(err)
	}

	write, err := net.Dial("unixgram", read.LocalAddr().String())
	if err != nil {
		tb.Fatal(err)
	}
	defer write.Close()

	if _, err := write.Write(in); err != nil {
		tb.Fatal(err)
	}

	read.SetDeadline(time.Now().Add(50 * time.Millisecond))

	// SocketFilters only allow matching packets through
	// If the packet does not match, the only signal we have is the absence of a packet
	var out [1500]byte
	n, err := read.Read(out[:])
	if err != nil {
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			return noMatch
		}

		tb.Fatal(err)
	}

	// Sanity check we received the right packet
	// Received packet is truncated to the SocketFilter's return value
	if !bytes.Equal(in[:n], out[:n]) {
		tb.Fatalf("Received unexpected packet:\nSent: %v\nGot: %v\n", in, out[:n])
	}

	return match
}