From 54dcd364c66b33d088204020c9af9cf95ee37099 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Mon, 22 Nov 2021 08:07:48 +1030 Subject: [PATCH 1/2] ci: add GitHub Action for contributions to beats branch --- .github/workflows/ci.yml | 84 ++++++++++++++++++++++++++++++++++++++++ pcap/pcapnggo_test.go | 5 +++ 2 files changed, 89 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..d3c868d65 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,84 @@ +name: CI + +on: + push: + branches: [ beats ] + pull_request: + branches: [ beats ] + +jobs: + test: + strategy: + matrix: + go-version: [1.16.x, 1.17.x] + os: [macos-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Install Linux packages + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -qq libpcap-dev + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Test + run: | + go test ./bytediff + go test ./defrag/lcmdefrag + go test ./dumpcommand + go test ./ip4defrag + go test ./layers + go test ./macs + go test ./pcap + go test ./pcap/gopacket_benchmark + go test ./pcapgo + go test ./reassembly + go test ./tcpassembly + go test ./tcpassembly/tcpreader + # go test ./pfring + + - name: Test Race + run: | + go test -race ./bytediff + go test -race ./defrag/lcmdefrag + go test -race ./dumpcommand + go test -race ./ip4defrag + go test -race ./layers + go test -race ./macs + go test -race ./pcap + go test -race ./pcap/gopacket_benchmark + go test -race ./pcapgo + go test -race ./reassembly + go test -race ./tcpassembly + go test -race ./tcpassembly/tcpreader + # go test -race ./pfring + + - name: Test Linux + if: matrix.os == 'ubuntu-latest' + run: | + go test ./afpacket + sudo $(which go) test ./routing + + - name: Test Linux Race + if: matrix.os == 'ubuntu-latest' + run: | + go test -race ./afpacket + sudo $(which go) test -race ./routing + + - name: Test MacOS + if: matrix.os == 'macos-latest' + run: | + go test ./bsdbpf + + - name: Test MacOS Race + if: matrix.os == 'macos-latest' + run: | + go test -race ./bsdbpf diff --git a/pcap/pcapnggo_test.go b/pcap/pcapnggo_test.go index 79b26e4d0..a55a0bbda 100644 --- a/pcap/pcapnggo_test.go +++ b/pcap/pcapnggo_test.go @@ -10,6 +10,7 @@ import ( "bytes" "io/ioutil" "reflect" + "runtime" "testing" "time" @@ -19,6 +20,10 @@ import ( ) func TestPCAPGoNgWrite(t *testing.T) { + if runtime.GOOS == "darwin" { + t.Skip("Reading PCAPNG files fails on MacOS") + } + f, err := ioutil.TempFile("", "pcapnggo") if err != nil { t.Fatal(err) From d552eb0fc27b1e9638a5041d20278528f4c94b69 Mon Sep 17 00:00:00 2001 From: Adrian Serrano Date: Fri, 18 Oct 2019 10:38:32 +0200 Subject: [PATCH 2/2] afpacket: Fix support for 32-bit x86 arch afpacket uses syscalls unix.SYS_GETSOCKOPT and unix.SYS_SETSOCKOPT when it needs to call [gs]etsockopt() passing a raw pointer. This doesn't work for 32-bit x86 platforms as there's no such syscall, resulting in: setsockopt packet_rx_ring: function not implemented unix.Syscall(unix.SYS_GETSOCKOPT[=366],...) = 38 // ENOSYS The correct way to call [gs]etsockopt() in this platform is to use the SYS_SOCKETCALL syscall with the right call parameter. This patch refactors the raw [gs]etsockopt() calls in afpacket to use unix.GetsockoptString and unix.SetsockoptString so that it relies on Go runtime to call the appropriate syscall. --- afpacket/afpacket.go | 12 ++++------ afpacket/sockopt_linux.go | 46 +++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/afpacket/afpacket.go b/afpacket/afpacket.go index bdf888840..a0f9ba27e 100644 --- a/afpacket/afpacket.go +++ b/afpacket/afpacket.go @@ -337,20 +337,18 @@ func (h *TPacket) Stats() (Stats, error) { func (h *TPacket) InitSocketStats() error { if h.tpVersion == TPacketVersion3 { socklen := unsafe.Sizeof(h.socketStatsV3) - slt := C.socklen_t(socklen) var ssv3 SocketStatsV3 - err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), uintptr(unsafe.Pointer(&slt))) + err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), &socklen) if err != nil { return err } h.socketStatsV3 = SocketStatsV3{} } else { socklen := unsafe.Sizeof(h.socketStats) - slt := C.socklen_t(socklen) var ss SocketStats - err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), uintptr(unsafe.Pointer(&slt))) + err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), &socklen) if err != nil { return err } @@ -366,10 +364,9 @@ func (h *TPacket) SocketStats() (SocketStats, SocketStatsV3, error) { // We need to save the counters since asking for the stats will clear them if h.tpVersion == TPacketVersion3 { socklen := unsafe.Sizeof(h.socketStatsV3) - slt := C.socklen_t(socklen) var ssv3 SocketStatsV3 - err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), uintptr(unsafe.Pointer(&slt))) + err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ssv3), &socklen) if err != nil { return SocketStats{}, SocketStatsV3{}, err } @@ -380,10 +377,9 @@ func (h *TPacket) SocketStats() (SocketStats, SocketStatsV3, error) { return h.socketStats, h.socketStatsV3, nil } socklen := unsafe.Sizeof(h.socketStats) - slt := C.socklen_t(socklen) var ss SocketStats - err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), uintptr(unsafe.Pointer(&slt))) + err := getsockopt(h.fd, unix.SOL_PACKET, unix.PACKET_STATISTICS, unsafe.Pointer(&ss), &socklen) if err != nil { return SocketStats{}, SocketStatsV3{}, err } diff --git a/afpacket/sockopt_linux.go b/afpacket/sockopt_linux.go index c53e1cceb..ab35f4995 100644 --- a/afpacket/sockopt_linux.go +++ b/afpacket/sockopt_linux.go @@ -9,44 +9,38 @@ package afpacket import ( + "errors" + "syscall" "unsafe" "golang.org/x/sys/unix" ) +const maxOptSize = 8192 + +var errSockoptTooBig = errors.New("socket option too big") + // setsockopt provides access to the setsockopt syscall. func setsockopt(fd, level, name int, val unsafe.Pointer, vallen uintptr) error { - _, _, errno := unix.Syscall6( - unix.SYS_SETSOCKOPT, - uintptr(fd), - uintptr(level), - uintptr(name), - uintptr(val), - vallen, - 0, - ) - if errno != 0 { - return error(errno) + if vallen > maxOptSize { + return errSockoptTooBig } - - return nil + slice := (*[maxOptSize]byte)(val)[:] + return syscall.SetsockoptString(fd, level, name, string(slice[:vallen])) } // getsockopt provides access to the getsockopt syscall. -func getsockopt(fd, level, name int, val unsafe.Pointer, vallen uintptr) error { - _, _, errno := unix.Syscall6( - unix.SYS_GETSOCKOPT, - uintptr(fd), - uintptr(level), - uintptr(name), - uintptr(val), - vallen, - 0, - ) - if errno != 0 { - return error(errno) +func getsockopt(fd, level, name int, val unsafe.Pointer, vallen *uintptr) error { + s, err := unix.GetsockoptString(fd, level, name) + if err != nil { + return err } - + rcvLen := uintptr(len(s)) + if rcvLen > *vallen { + return errSockoptTooBig + } + copy((*[maxOptSize]byte)(val)[:rcvLen], s) + *vallen = rcvLen return nil }