├── .gitignore ├── .dockerignore ├── CODEOWNERS ├── .gitattributes ├── internal ├── bpf │ ├── arch │ │ ├── common.go │ │ ├── common_test.go │ │ ├── arm64.go │ │ ├── amd64.go │ │ ├── 386.go │ │ └── arm.go │ ├── consumer.go │ ├── whitelist_attacher.go │ ├── event.go │ ├── kprobe_attacher.go │ ├── tracepoint_attacher.go │ ├── event_processor.go │ └── attacher.go ├── logger │ └── logger.go ├── workload │ ├── runtime.go │ ├── runtime_handlers.go │ ├── resolve.go │ └── sha_resolver.go ├── profile │ ├── pprof.go │ └── pyroscope.go ├── app │ ├── delete_pods.go │ └── app.go ├── sig │ └── handler.go ├── metrics │ ├── server.go │ └── counters.go └── kernel │ └── version.go ├── SECURITY.md ├── .goreleaser.yml ├── cmd └── bpfsnitch │ └── main.go ├── .github └── workflows │ ├── lint.yml │ └── release.yml ├── bpf ├── main.c ├── tracepoint │ └── trace_syscall.c ├── build.sh ├── core.h └── kprobe │ ├── trace_udp.c │ └── trace_tcp.c ├── LICENSE ├── go.mod ├── Makefile ├── .golangci.yml ├── deployments ├── Dockerfile └── daemonset.yaml ├── pkg ├── network │ ├── converter.go │ └── converter_test.go └── lru │ ├── lru.go │ └── lru_test.go ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── go.sum └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | *.o 3 | dev/ -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .*/ 2 | *.o 3 | dev 4 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @nullswan @gmarcha @naofel1 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | bpf/vmlinux.h linguist-vendored 2 | -------------------------------------------------------------------------------- /internal/bpf/arch/common.go: -------------------------------------------------------------------------------- 1 | package bpfarch 2 | 3 | // TODO: build with the same target as bpf/build.sh 4 | const bpfProgramName = "bpfsnitch_lib" 5 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | ^1.0.0 | :white_check_mark: | 8 | 9 | ## Reporting a Vulnerability 10 | 11 | Email me at [email](mailto:pro@nullswan.io) 12 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | 7 | builds: 8 | - id: bpfsnitch 9 | goos: 10 | - linux 11 | goarch: 12 | - arm 13 | - arm64 14 | - amd64 15 | goarm: 16 | - "7" 17 | binary: bpfsnitch 18 | main: ./cmd/bpfsnitch/main.go 19 | 20 | checksum: 21 | algorithm: sha256 22 | -------------------------------------------------------------------------------- /cmd/bpfsnitch/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/nullswan/bpfsnitch/internal/app" 7 | "github.com/nullswan/bpfsnitch/internal/logger" 8 | ) 9 | 10 | func main() { 11 | log := logger.Init() 12 | 13 | if err := app.Run(log); err != nil { 14 | log.With("error", err).Error("Failed to run app") 15 | os.Exit(1) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /internal/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "log/slog" 5 | "os" 6 | ) 7 | 8 | func Init() *slog.Logger { 9 | loggerHandlerOpts := &slog.HandlerOptions{ 10 | Level: slog.LevelInfo, 11 | } 12 | 13 | if os.Getenv("DEBUG") != "" { 14 | loggerHandlerOpts.Level = slog.LevelDebug 15 | } 16 | 17 | return slog.New( 18 | slog.NewTextHandler(os.Stdout, loggerHandlerOpts), 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /internal/workload/runtime.go: -------------------------------------------------------------------------------- 1 | package workload 2 | 3 | import "os" 4 | 5 | var runtimeSockets = []string{ 6 | "/run/containerd/containerd.sock", 7 | "/run/crio/crio.sock", 8 | "/var/run/cri-dockerd.sock", 9 | } 10 | 11 | func IsSocketPresent() bool { 12 | for _, endpoint := range runtimeSockets { 13 | if _, err := os.Stat(endpoint); err == nil { 14 | return true 15 | } 16 | } 17 | 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /internal/profile/pprof.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import ( 4 | "net/http" 5 | "net/http/pprof" 6 | ) 7 | 8 | func SetupPprof() { 9 | http.HandleFunc("/debug/pprof/", pprof.Index) 10 | http.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 11 | http.HandleFunc("/debug/pprof/profile", pprof.Profile) 12 | http.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 13 | http.HandleFunc("/debug/pprof/trace", pprof.Trace) 14 | } 15 | -------------------------------------------------------------------------------- /internal/app/delete_pods.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | 7 | "github.com/nullswan/bpfsnitch/internal/metrics" 8 | ) 9 | 10 | func deletePods( 11 | ctx context.Context, 12 | logger *slog.Logger, 13 | deletedPodsChan chan string, 14 | ) { 15 | for { 16 | select { 17 | case <-ctx.Done(): 18 | return 19 | case podID := <-deletedPodsChan: 20 | for _, counter := range metrics.PodBasedMetrics { 21 | logger.With("pod", podID).Info("Deleted pod-based metrics") 22 | counter.DeleteLabelValues(podID) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout the repository 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: actions/setup-go@v5 20 | with: 21 | go-version-file: go.mod 22 | 23 | - name: Download Go module dependencies 24 | run: go mod download 25 | 26 | - name: golangci-lint 27 | uses: golangci/golangci-lint-action@v3 28 | with: 29 | skip-cache: true 30 | version: v1.61.0 31 | -------------------------------------------------------------------------------- /bpf/main.c: -------------------------------------------------------------------------------- 1 | //go:build exclude 2 | 3 | #include "tracepoint/trace_syscall.c" 4 | #include "kprobe/trace_udp.c" 5 | #include "kprobe/trace_tcp.c" 6 | 7 | static inline int is_local_ip(__be32 ip) { 8 | // Check for 127.0.0.0/8 9 | if ((ip & 0xFF000000) == 0x7F000000) { 10 | return 1; 11 | } 12 | 13 | // Check for 10.0.0.0/8 14 | if ((ip & 0xFF000000) == 0x0A000000) { 15 | return 1; 16 | } 17 | 18 | // Check for 172.16.0.0/12 19 | if ((ip & 0xFFF00000) == 0xAC100000) { 20 | return 1; 21 | } 22 | 23 | // Check for 192.168.0.0/16 24 | if ((ip & 0xFFFF0000) == 0xC0A80000) { 25 | return 1; 26 | } 27 | 28 | return 0; 29 | } 30 | 31 | char _license[] SEC("license") = "GPL"; 32 | #define KBUILD_MODNAME "bpfsnitch" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2024 @nullswan 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . -------------------------------------------------------------------------------- /internal/bpf/arch/common_test.go: -------------------------------------------------------------------------------- 1 | package bpfarch 2 | 3 | import "testing" 4 | 5 | func TestSyscallDefs(t *testing.T) { 6 | t.Parallel() 7 | 8 | for name, number := range SyscallToId { 9 | if mappedName, present := IdToSyscall[number]; !present || 10 | mappedName != name { 11 | t.Errorf( 12 | "Mismatch or missing entry: syscall name %s with number %d not found in reverse map", 13 | name, 14 | number, 15 | ) 16 | } 17 | } 18 | 19 | for number, name := range IdToSyscall { 20 | if mappedNumber, present := SyscallToId[name]; !present || 21 | mappedNumber != number { 22 | t.Errorf( 23 | "Mismatch or missing entry: syscall number %d with name %s not found in forward map", 24 | number, 25 | name, 26 | ) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /internal/sig/handler.go: -------------------------------------------------------------------------------- 1 | package sig 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | 10 | "github.com/nullswan/bpfsnitch/internal/bpf" 11 | ) 12 | 13 | func SetupHandler( 14 | cancel context.CancelFunc, 15 | bpfCtx *bpf.KBContext, 16 | log *slog.Logger, 17 | ) { 18 | sigChan := make(chan os.Signal, 1) 19 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 20 | go func() { 21 | sig := <-sigChan 22 | log.With("signal", sig).Info("Received signal, cancelling context") 23 | 24 | cancel() 25 | for _, tp := range bpfCtx.Tps { 26 | tp.Close() 27 | } 28 | for _, kp := range bpfCtx.Kps { 29 | kp.Close() 30 | } 31 | 32 | bpfCtx.SyscallRingBuffer.Close() 33 | bpfCtx.NetworkRingBuffer.Close() 34 | 35 | log.Info("Closed event reader") 36 | }() 37 | } 38 | -------------------------------------------------------------------------------- /bpf/tracepoint/trace_syscall.c: -------------------------------------------------------------------------------- 1 | #include "bpf/core.h" 2 | 3 | struct syscall_trace_enter_args { 4 | unsigned long long unused; 5 | long syscall_nr; 6 | long arg0; 7 | long arg1; 8 | long arg2; 9 | long arg3; 10 | long arg4; 11 | long arg5; 12 | }; 13 | 14 | SEC("tracepoint/syscalls/sys_enter") 15 | int tracepoint_sys_enter(struct syscall_trace_enter_args *ctx) { 16 | int syscall_nr = ctx->syscall_nr; 17 | 18 | if (bpf_map_lookup_elem(&syscall_whitelist, &syscall_nr) == NULL) { 19 | return 0; 20 | } 21 | 22 | u32 pid = bpf_get_current_pid_tgid() >> 32; 23 | u64 cgroup_id = bpf_get_current_cgroup_id(); 24 | 25 | struct syscall_event syscall_event = { 26 | .syscall_nr = ctx->syscall_nr, 27 | .cgroup_id = cgroup_id, 28 | .pid = pid 29 | }; 30 | 31 | bpf_ringbuf_output(&syscall_events_rb, &syscall_event, sizeof(syscall_event), BPF_RB_FORCE_WAKEUP); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /bpf/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | SOURCE_FILE=bpf/main.c 5 | LIBNAME=bpfsnitch_lib 6 | CFLAGS="-g -O2 -target bpf" 7 | 8 | if [ -n "$DEBUG" ]; then 9 | CFLAGS="$CFLAGS -DDEBUG" 10 | fi 11 | 12 | if [ -z "$TARGETARCH" ]; then 13 | echo "TARGETARCH is not set" 14 | exit 1 15 | fi 16 | 17 | case "$TARGETARCH" in 18 | "amd64") 19 | ARCH_FLAGS="-D__TARGET_ARCH_x86" 20 | OUTPUT_FILE="${LIBNAME}_amd64.o" 21 | ;; 22 | "arm64") 23 | ARCH_FLAGS="-D__TARGET_ARCH_arm64" 24 | OUTPUT_FILE="${LIBNAME}_arm64.o" 25 | ;; 26 | "arm") 27 | ARCH_FLAGS="-D__TARGET_ARCH_arm" 28 | OUTPUT_FILE="${LIBNAME}_arm.o" 29 | ;; 30 | "386") 31 | ARCH_FLAGS="-D__TARGET_ARCH_x86" 32 | OUTPUT_FILE="${LIBNAME}_x86.o" 33 | ;; 34 | *) 35 | echo "Unknown architecture: `$TARGETARCH`" 36 | exit 1 37 | ;; 38 | esac 39 | 40 | clang $CFLAGS $ARCH_FLAGS -c $SOURCE_FILE -o $OUTPUT_FILE -I. 41 | -------------------------------------------------------------------------------- /internal/bpf/consumer.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/binary" 7 | "log/slog" 8 | 9 | "github.com/cilium/ebpf/ringbuf" 10 | ) 11 | 12 | func ConsumeEvents[T Event]( 13 | ctx context.Context, 14 | log *slog.Logger, 15 | evReader *ringbuf.Reader, 16 | evCh chan *T, 17 | ) { 18 | log.Info("Starting event reader") 19 | 20 | for { 21 | select { 22 | case <-ctx.Done(): 23 | log.Info("Context done, stopping event reader") 24 | return 25 | default: 26 | record, err := evReader.Read() 27 | if err != nil { 28 | log.With("error", err).Error("Failed to read event") 29 | continue 30 | } 31 | 32 | ev := new(T) 33 | err = binary.Read( 34 | bytes.NewReader(record.RawSample), 35 | binary.LittleEndian, 36 | ev, 37 | ) 38 | if err != nil { 39 | log.With("error", err).Error("Failed to decode event") 40 | continue 41 | } 42 | 43 | evCh <- ev 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bpf/core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vmlinux.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define DIRECTION_INBOUND 0 11 | #define DIRECTION_OUTBOUND 1 12 | 13 | #define PROTOCOL_TCP 6 14 | #define PROTOCOL_UDP 17 15 | 16 | static inline int is_local_ip(__be32 ip); 17 | 18 | struct { 19 | __uint(type, BPF_MAP_TYPE_HASH); 20 | __type(key, __u32); 21 | __type(value, 0); 22 | __uint(max_entries, 1024); 23 | } syscall_whitelist SEC(".maps"); 24 | 25 | struct syscall_event { 26 | long syscall_nr; 27 | u64 cgroup_id; 28 | u64 pid; 29 | }; 30 | 31 | struct network_event { 32 | u64 pid; 33 | u64 cgroup_id; 34 | u64 size; 35 | 36 | u32 saddr; 37 | u32 daddr; 38 | 39 | u16 sport; 40 | u16 dport; 41 | 42 | u8 direction; 43 | u8 protocol; 44 | }; 45 | 46 | struct { 47 | __uint(type, BPF_MAP_TYPE_RINGBUF); 48 | __uint(max_entries, 1<<25); // 32MB 49 | } network_events_rb SEC(".maps"); 50 | 51 | struct { 52 | __uint(type, BPF_MAP_TYPE_RINGBUF); 53 | __uint(max_entries, 1<<24); // 16MB 54 | } syscall_events_rb SEC(".maps"); 55 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nullswan/bpfsnitch 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.22.4 6 | 7 | require ( 8 | github.com/cilium/ebpf v0.16.0 9 | github.com/grafana/pyroscope-go v1.2.0 10 | github.com/prometheus/client_golang v1.20.4 11 | google.golang.org/grpc v1.66.2 12 | k8s.io/cri-api v0.31.1 13 | ) 14 | 15 | require ( 16 | github.com/beorn7/perks v1.0.1 // indirect 17 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 18 | github.com/gogo/protobuf v1.3.2 // indirect 19 | github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect 20 | github.com/klauspost/compress v1.17.9 // indirect 21 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 22 | github.com/prometheus/client_model v0.6.1 // indirect 23 | github.com/prometheus/common v0.59.1 // indirect 24 | github.com/prometheus/procfs v0.15.1 // indirect 25 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect 26 | golang.org/x/net v0.29.0 // indirect 27 | golang.org/x/sys v0.25.0 // indirect 28 | golang.org/x/text v0.18.0 // indirect 29 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect 30 | google.golang.org/protobuf v1.34.2 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Automatically include environment variables from .env file 2 | ifneq (,$(wildcard ./.env)) 3 | include .env 4 | export $(shell sed 's/=.*//' .env) 5 | endif 6 | 7 | .PHONY: build-local 8 | build-local: 9 | DEBUG=1 TARGETARCH=$(shell go env GOARCH) ./bpf/build.sh 10 | go build -o ./dist/ -v ./... 11 | 12 | .PHONY: build-docker 13 | build-docker: 14 | docker build \ 15 | -t bpfsnitch:latest \ 16 | . -f deployments/Dockerfile 17 | 18 | .PHONY: build-docker-multiarch 19 | build-docker-multiarch: 20 | docker buildx build \ 21 | --platform linux/amd64,linux/arm64,linux/arm/v7 \ 22 | -t nullswan/bpfsnitch-dev:latest \ 23 | --push \ 24 | . -f deployments/Dockerfile 25 | 26 | .PHONY: build 27 | build: build-local build-docker 28 | 29 | .PHONY: build-binaries 30 | build-binaries: clean 31 | goreleaser build --snapshot 32 | 33 | .PHONY: build-multiarch 34 | build-multiarch: build-binaries build-docker-multiarch 35 | 36 | .PHONY: clean 37 | clean: 38 | rm -rf dist 39 | docker rmi bpfsnitch || true 40 | 41 | .PHONY: fmt 42 | fmt: 43 | golines . --write-output --max-len=80 --base-formatter="gofmt" --tab-len=2 44 | golangci-lint run --fix 45 | 46 | .PHONY: test 47 | test: 48 | go test -v -cover ./... 49 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - bodyclose 5 | - containedctx 6 | - contextcheck 7 | - durationcheck 8 | - errcheck 9 | - exhaustive 10 | - gocheckcompilerdirectives 11 | - gochecknoinits 12 | - goconst 13 | - gocritic 14 | - gocyclo 15 | - gofumpt 16 | - gosec 17 | - gosimple 18 | - govet 19 | - ineffassign 20 | - mnd 21 | - nilerr 22 | - nilnil 23 | - noctx 24 | - paralleltest 25 | - perfsprint 26 | - prealloc 27 | - protogetter 28 | - reassign 29 | - revive 30 | - rowserrcheck 31 | - sloglint 32 | - spancheck 33 | - sqlclosecheck 34 | - staticcheck 35 | - staticcheck 36 | - thelper 37 | - typecheck 38 | - unconvert 39 | - unparam 40 | - unused 41 | - unused 42 | - usestdlibvars 43 | - whitespace 44 | - whitespace 45 | - wrapcheck 46 | 47 | linters-settings: 48 | exhaustive: 49 | check: 50 | - switch 51 | - map 52 | default-signifies-exhaustive: true 53 | ignore-enum-members: ".+UNSPECIFIED" 54 | 55 | severity: 56 | default-severity: error 57 | 58 | run: 59 | timeout: 5m 60 | modules-download-mode: readonly 61 | -------------------------------------------------------------------------------- /deployments/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Golang alpine image as the build environment 2 | FROM golang:1.22-alpine AS builder 3 | 4 | # Set the target architecture 5 | ARG TARGETARCH 6 | ENV TARGETARCH=${TARGETARCH} 7 | ENV CGO_ENABLED=1 GOOS=linux GOARCH=${TARGETARCH} BPF_TARGET=${TARGETARCH} 8 | 9 | # Install necessary packages 10 | RUN apk add --no-cache clang llvm-dev libbpf-dev build-base 11 | 12 | # Set the working directory 13 | WORKDIR /build 14 | 15 | # Copy and build BPF artifacts 16 | COPY ./bpf ./bpf 17 | RUN chmod +x ./bpf/build.sh && TARGETARCH=${TARGETARCH} sh ./bpf/build.sh 18 | 19 | # Download Go module dependencies 20 | COPY go.mod go.sum ./ 21 | RUN go mod download 22 | 23 | # Copy the rest of the source code and build the project 24 | COPY . . 25 | RUN go build -o ./dist/ -v ./... 26 | 27 | # Use a minimal alpine image for the runtime environment 28 | FROM alpine:latest 29 | 30 | # Set the working directory 31 | WORKDIR /root/ 32 | 33 | # Copy the built executable from the builder stage 34 | COPY --from=builder /build/dist . 35 | COPY --from=builder /build/bpfsnitch_lib_*.o . 36 | 37 | # Ensure the main executable has the right permissions 38 | RUN chmod +x ./bpfsnitch 39 | 40 | # Specify the default command to run the executable 41 | CMD ["./bpfsnitch"] -------------------------------------------------------------------------------- /pkg/network/converter.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import "net" 4 | 5 | const SubnetMask24 = 0xFFFFFF00 // nolint:mnd 6 | 7 | func IntToIP(ip uint32) net.IP { 8 | return net.IPv4( 9 | byte(ip>>24), // nolint:mnd 10 | byte(ip>>16), // nolint:mnd 11 | byte(ip>>8), // nolint:mnd 12 | byte(ip), 13 | ) 14 | } 15 | 16 | func IntToSubnet(ip uint32, mask uint32) *net.IPNet { 17 | ipMask := net.IPv4Mask( 18 | byte(mask>>24), // nolint:mnd 19 | byte(mask>>16), // nolint:mnd 20 | byte(mask>>8), // nolint:mnd 21 | byte(mask), 22 | ) 23 | maskLength, _ := ipMask.Size() // Get the mask length in bits 24 | 25 | networkPart := ip & (0xFFFFFFFF << (32 - maskLength)) // nolint:mnd 26 | ipAddr := net.IPv4( 27 | byte(networkPart>>24), // nolint:mnd 28 | byte(networkPart>>16), // nolint:mnd 29 | byte(networkPart>>8), // nolint:mnd 30 | byte(networkPart), 31 | ) 32 | return &net.IPNet{ 33 | IP: ipAddr, 34 | Mask: ipMask, 35 | } 36 | } 37 | 38 | func Ntohs(val uint16) uint16 { 39 | return (val<<8)&0xff00 | val>>8 // nolint:mnd 40 | } 41 | 42 | func Ntohl(val uint32) uint32 { 43 | return (val<<24)&0xff000000 | // nolint:mnd 44 | (val<<8)&0x00ff0000 | // nolint:mnd 45 | (val>>8)&0x0000ff00 | // nolint:mnd 46 | (val>>24)&0x000000ff // nolint:mnd 47 | } 48 | -------------------------------------------------------------------------------- /internal/bpf/whitelist_attacher.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "log/slog" 7 | 8 | "github.com/cilium/ebpf" 9 | bpfarch "github.com/nullswan/bpfsnitch/internal/bpf/arch" 10 | ) 11 | 12 | const ( 13 | // Map name for the whitelist of syscalls. 14 | syscallsWhitelistMapName = "syscall_whitelist" 15 | intSz = 4 16 | ) 17 | 18 | func registerWhitelistedSyscalls( 19 | log *slog.Logger, 20 | maps map[string]*ebpf.Map, 21 | ) error { 22 | syscallMap, ok := maps[syscallsWhitelistMapName] 23 | if !ok { 24 | return fmt.Errorf( 25 | "failed to find map %s", 26 | syscallsWhitelistMapName, 27 | ) 28 | } 29 | 30 | for _, nbr := range bpfarch.WhitelistedSyscalls { 31 | syscallName := bpfarch.IdToSyscall[nbr] 32 | buf := make([]byte, intSz) 33 | binary.LittleEndian.PutUint32(buf, uint32(nbr)) //nolint: gosec 34 | 35 | placeholder := make([]byte, intSz) 36 | if err := syscallMap.Update( 37 | buf, 38 | placeholder, 39 | ebpf.UpdateAny, 40 | ); err != nil { 41 | return fmt.Errorf( 42 | "failed to update map %s: %w", 43 | syscallsWhitelistMapName, 44 | err, 45 | ) 46 | } 47 | 48 | log.With("syscall_name", syscallName).Info("Registered syscall") 49 | } 50 | 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /internal/bpf/event.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import bpfarch "github.com/nullswan/bpfsnitch/internal/bpf/arch" 4 | 5 | type Event interface { 6 | SyscallEvent | NetworkEvent 7 | } 8 | 9 | type SyscallEvent struct { 10 | SyscallNr int64 11 | CgroupID uint64 12 | Pid uint64 13 | } 14 | 15 | func (s SyscallEvent) GetSyscallName() string { 16 | return bpfarch.IdToSyscall[int(s.SyscallNr)] 17 | } 18 | 19 | type NetworkEvent struct { 20 | Pid uint64 21 | CgroupID uint64 22 | Size uint64 23 | 24 | Saddr uint32 25 | Daddr uint32 26 | 27 | Sport uint16 28 | Dport uint16 29 | 30 | Direction NetworkEventDirection 31 | Protocol NetworkEventProtocol 32 | } 33 | 34 | type NetworkEventDirection uint8 35 | 36 | const ( 37 | NetworkEventDirectionInbound NetworkEventDirection = 0 38 | NetworkEventDirectionOutbound NetworkEventDirection = 1 39 | ) 40 | 41 | func (d NetworkEventDirection) String() string { 42 | if d == NetworkEventDirectionInbound { 43 | return "inbound" 44 | } 45 | return "outbound" 46 | } 47 | 48 | type NetworkEventProtocol uint8 49 | 50 | const ( 51 | NetworkEventProtocolTCP NetworkEventProtocol = 6 52 | NetworkEventProtocolUDP NetworkEventProtocol = 17 53 | ) 54 | 55 | func (p NetworkEventProtocol) String() string { 56 | if p == NetworkEventProtocolTCP { 57 | return "tcp" 58 | } 59 | return "udp" 60 | } 61 | -------------------------------------------------------------------------------- /internal/profile/pyroscope.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log/slog" 7 | "os" 8 | 9 | "github.com/grafana/pyroscope-go" 10 | ) 11 | 12 | func SetupProfiling(log *slog.Logger) error { 13 | serverAddress := os.Getenv("PYROSCOPE_SERVER") 14 | if serverAddress == "" { 15 | return errors.New("PYROSCOPE_SERVER is not set") 16 | } 17 | 18 | user := os.Getenv("PYROSCOPE_USER") 19 | if user == "" { 20 | log.Warn("PYROSCOPE_USER is not set") 21 | } 22 | 23 | password := os.Getenv("PYROSCOPE_PASSWORD") 24 | if password == "" { 25 | log.Warn("PYROSCOPE_PASSWORD is not set") 26 | } 27 | 28 | _, err := pyroscope.Start(pyroscope.Config{ 29 | ApplicationName: "bpfsnitch", 30 | ServerAddress: serverAddress, 31 | BasicAuthUser: user, 32 | BasicAuthPassword: password, 33 | Logger: pyroscope.StandardLogger, 34 | Tags: map[string]string{"hostname": os.Getenv("HOSTNAME")}, 35 | ProfileTypes: []pyroscope.ProfileType{ 36 | pyroscope.ProfileCPU, 37 | pyroscope.ProfileAllocObjects, 38 | pyroscope.ProfileAllocSpace, 39 | pyroscope.ProfileInuseObjects, 40 | pyroscope.ProfileInuseSpace, 41 | pyroscope.ProfileGoroutines, 42 | pyroscope.ProfileMutexCount, 43 | pyroscope.ProfileMutexDuration, 44 | pyroscope.ProfileBlockCount, 45 | pyroscope.ProfileBlockDuration, 46 | }, 47 | }) 48 | if err != nil { 49 | return fmt.Errorf("failed to start pyroscope: %w", err) 50 | } 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /internal/metrics/server.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log/slog" 7 | "net/http" 8 | 9 | "github.com/prometheus/client_golang/prometheus" 10 | "github.com/prometheus/client_golang/prometheus/collectors" 11 | "github.com/prometheus/client_golang/prometheus/promhttp" 12 | ) 13 | 14 | func StartServer(log *slog.Logger, cancel context.CancelFunc, port uint64) { 15 | http.Handle("/metrics", promhttp.Handler()) 16 | 17 | log.With("port", port).Info("Starting metrics server") 18 | err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil) // nolint:gosec 19 | if err != nil { 20 | log.With("error", err).Error("Failed to start metrics server") 21 | cancel() 22 | } 23 | } 24 | 25 | const promPrefix = "bpfsnitch_" 26 | 27 | func RegisterMetrics() { 28 | // Remove all builtin metrics that are produced by prometheus client. 29 | // TODO: Remove promhttp_metric_handler_requests_total && promhttp_metric_handler_requests_in_flight 30 | prometheus.Unregister(collectors.NewGoCollector()) 31 | prometheus.Unregister(collectors.NewProcessCollector( 32 | collectors.ProcessCollectorOpts{}, 33 | )) 34 | 35 | // Create a custom registerer with a prefix 36 | registerer := prometheus.WrapRegistererWithPrefix( 37 | promPrefix, 38 | prometheus.DefaultRegisterer, 39 | ) 40 | 41 | registerer.MustRegister(SyscallCounter) 42 | registerer.MustRegister(DNSQueryCounter) 43 | registerer.MustRegister(NetworkReceivedBytesCounter) 44 | registerer.MustRegister(NetworkReceivedPacketsCounter) 45 | registerer.MustRegister(NetworkSentBytesCounter) 46 | registerer.MustRegister(NetworkSentPacketsCounter) 47 | } 48 | -------------------------------------------------------------------------------- /internal/metrics/counters.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import "github.com/prometheus/client_golang/prometheus" 4 | 5 | var DNSQueryCounter = prometheus.NewCounterVec( 6 | prometheus.CounterOpts{ 7 | Name: "dns_query_counter", 8 | Help: "Number of DNS queries", 9 | }, 10 | []string{"pod"}, 11 | ) 12 | 13 | var SyscallCounter = prometheus.NewCounterVec( 14 | prometheus.CounterOpts{ 15 | Name: "syscall_counter", 16 | Help: "Number of syscalls", 17 | }, 18 | []string{"syscall", "pod"}, 19 | ) 20 | 21 | var NetworkReceivedBytesCounter = prometheus.NewCounterVec( 22 | prometheus.CounterOpts{ 23 | Name: "network_received_bytes_counter", 24 | Help: "Number of bytes received", 25 | }, 26 | []string{"pod", "remote_subnet"}, 27 | ) 28 | 29 | var NetworkSentBytesCounter = prometheus.NewCounterVec( 30 | prometheus.CounterOpts{ 31 | Name: "network_sent_bytes_counter", 32 | Help: "Number of bytes sent", 33 | }, 34 | []string{"pod", "remote_subnet"}, 35 | ) 36 | 37 | var NetworkSentPacketsCounter = prometheus.NewCounterVec( 38 | prometheus.CounterOpts{ 39 | Name: "network_sent_packets_counter", 40 | Help: "Number of packets sent", 41 | }, 42 | []string{"pod", "remote_subnet"}, 43 | ) 44 | 45 | var NetworkReceivedPacketsCounter = prometheus.NewCounterVec( 46 | prometheus.CounterOpts{ 47 | Name: "network_received_packets_counter", 48 | Help: "Number of packets received", 49 | }, 50 | []string{"pod", "remote_subnet"}, 51 | ) 52 | 53 | var PodBasedMetrics = []*prometheus.CounterVec{ 54 | DNSQueryCounter, 55 | SyscallCounter, 56 | NetworkReceivedBytesCounter, 57 | NetworkSentBytesCounter, 58 | NetworkSentPacketsCounter, 59 | NetworkReceivedPacketsCounter, 60 | } 61 | -------------------------------------------------------------------------------- /internal/bpf/kprobe_attacher.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | 7 | "github.com/cilium/ebpf" 8 | "github.com/cilium/ebpf/link" 9 | ) 10 | 11 | // Struct that holds bpf kprobe required metadata 12 | type KProbeMeta struct { 13 | function string 14 | section string 15 | } 16 | 17 | var kpsMeta = []KProbeMeta{ 18 | { 19 | function: "udp_recvmsg", 20 | section: "trace_udp_recvmsg", 21 | }, 22 | { 23 | function: "udp_sendmsg", 24 | section: "trace_udp_sendmsg", 25 | }, 26 | { 27 | function: "tcp_recvmsg", 28 | section: "trace_tcp_recvmsg", 29 | }, 30 | { 31 | function: "tcp_sendmsg", 32 | section: "trace_tcp_sendmsg", 33 | }, 34 | } 35 | 36 | func attachKProbes( 37 | log *slog.Logger, 38 | coll *ebpf.Collection, 39 | ) ([]link.Link, error) { 40 | kps := make([]link.Link, 0, len(kpsMeta)) 41 | for _, kp := range kpsMeta { 42 | kpLink, err := attachKProbe(coll, kp, log) 43 | if err != nil { 44 | return nil, fmt.Errorf( 45 | "failed to attach kprobe %s: %w", 46 | kp.section, 47 | err, 48 | ) 49 | } 50 | 51 | kps = append(kps, kpLink) 52 | } 53 | 54 | return kps, nil 55 | } 56 | 57 | func attachKProbe( 58 | coll *ebpf.Collection, 59 | kp KProbeMeta, 60 | log *slog.Logger, 61 | ) (link.Link, error) { 62 | prog := coll.Programs[kp.section] 63 | if prog == nil { 64 | return nil, fmt.Errorf("failed to find program %s", kp.section) 65 | } 66 | 67 | kpLink, err := link.Kprobe(kp.function, prog, nil) 68 | if err != nil { 69 | return nil, fmt.Errorf( 70 | "failed to attach kprobe %s: %w", 71 | kp.function, 72 | err, 73 | ) 74 | } 75 | 76 | log.Info("Attached kprobe", "section", kp.section, "function", kp.function) 77 | 78 | return kpLink, nil 79 | } 80 | -------------------------------------------------------------------------------- /internal/kernel/version.go: -------------------------------------------------------------------------------- 1 | package kernel 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | // GetKernelVersion fetches the Linux kernel version without using exec commands. 11 | // It reads the version directly from /proc/sys/kernel/osrelease. 12 | func GetKernelVersion() (string, error) { 13 | data, err := os.ReadFile("/proc/sys/kernel/osrelease") 14 | if err != nil { 15 | return "", fmt.Errorf("failed to read kernel version: %w", err) 16 | } 17 | version := strings.TrimSpace(string(data)) 18 | return version, nil 19 | } 20 | 21 | // CompareVersions compares two kernel version strings. 22 | // It returns 1 if v1 > v2, -1 if v1 < v2, and 0 if they are equal. 23 | func CompareVersions(v1, v2 string) int { 24 | v1Parts := strings.Split(v1, ".") 25 | v2Parts := strings.Split(v2, ".") 26 | 27 | maxLen := len(v1Parts) 28 | if len(v2Parts) > maxLen { 29 | maxLen = len(v2Parts) 30 | } 31 | 32 | for i := 0; i < maxLen; i++ { 33 | var v1Num, v2Num int 34 | 35 | if i < len(v1Parts) { 36 | v1Num = extractLeadingNumber(v1Parts[i]) 37 | } 38 | if i < len(v2Parts) { 39 | v2Num = extractLeadingNumber(v2Parts[i]) 40 | } 41 | 42 | if v1Num > v2Num { 43 | return 1 44 | } else if v1Num < v2Num { 45 | return -1 46 | } 47 | } 48 | return 0 49 | } 50 | 51 | // extractLeadingNumber extracts the leading numeric part of a version string segment. 52 | func extractLeadingNumber(s string) int { 53 | numStr := strings.TrimLeftFunc(s, func(r rune) bool { 54 | return r < '0' || r > '9' 55 | }) 56 | numStr = strings.TrimRightFunc(numStr, func(r rune) bool { 57 | return r < '0' || r > '9' 58 | }) 59 | num, err := strconv.Atoi(numStr) 60 | if err != nil { 61 | return 0 62 | } 63 | return num 64 | } 65 | -------------------------------------------------------------------------------- /internal/bpf/tracepoint_attacher.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log/slog" 7 | 8 | "github.com/cilium/ebpf" 9 | "github.com/cilium/ebpf/link" 10 | bpfarch "github.com/nullswan/bpfsnitch/internal/bpf/arch" 11 | ) 12 | 13 | // Struct that holds bpf tracepoint required metadata 14 | type TpMeta struct { 15 | family string 16 | section string 17 | name string 18 | } 19 | 20 | func attachTracepoints( 21 | log *slog.Logger, 22 | coll *ebpf.Collection, 23 | ) ([]link.Link, error) { 24 | tps := make([]link.Link, 0, len(bpfarch.WhitelistedSyscalls)) 25 | for _, nbr := range bpfarch.WhitelistedSyscalls { 26 | syscallName := bpfarch.IdToSyscall[nbr] 27 | tp := TpMeta{ 28 | family: "syscalls", 29 | section: "tracepoint_sys_enter", 30 | name: "sys_enter_" + syscallName, 31 | } 32 | 33 | logCtx := log.With( 34 | "family", 35 | tp.family, 36 | "section", 37 | tp.section, 38 | "name", 39 | tp.name, 40 | ) 41 | 42 | tpLink, err := attachTracepoint(coll, tp) 43 | if err != nil { 44 | logCtx.Error( 45 | "Failed to attach tracepoint", 46 | "error", 47 | err, 48 | ) 49 | continue 50 | } 51 | 52 | logCtx.Info( 53 | "Attached tracepoint", 54 | ) 55 | 56 | tps = append(tps, tpLink) 57 | } 58 | 59 | if len(tps) == 0 { 60 | return nil, errors.New("failed to attach any tracepoints") 61 | } 62 | 63 | log.Info("Attached tracepoints", "count", len(tps)) 64 | 65 | return tps, nil 66 | } 67 | 68 | func attachTracepoint( 69 | coll *ebpf.Collection, 70 | tp TpMeta, 71 | ) (link.Link, error) { 72 | prog := coll.Programs[tp.section] 73 | if prog == nil { 74 | return nil, fmt.Errorf("failed to find program %s", tp.section) 75 | } 76 | 77 | tpLink, err := link.Tracepoint(tp.family, tp.name, prog, nil) 78 | if err != nil { 79 | return nil, fmt.Errorf( 80 | "failed to attach tracepoint %s: %w", 81 | tp.section, 82 | err, 83 | ) 84 | } 85 | 86 | return tpLink, nil 87 | } 88 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # https://goreleaser.com/ci/actions/ 2 | name: release 3 | 4 | on: 5 | push: 6 | tags: 7 | - "*" 8 | 9 | permissions: 10 | contents: write 11 | packages: write 12 | issues: write 13 | 14 | jobs: 15 | goreleaser: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Set up Go 24 | uses: actions/setup-go@v5 25 | with: 26 | go-version-file: go.mod 27 | 28 | - name: Download Go module dependencies 29 | run: go mod download 30 | 31 | - name: Run GoReleaser 32 | uses: goreleaser/goreleaser-action@v6 33 | with: 34 | distribution: goreleaser 35 | version: "~> v2" 36 | args: release --clean 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | 40 | docker-push: 41 | runs-on: ubuntu-latest 42 | needs: goreleaser 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v4 46 | with: 47 | fetch-depth: 0 48 | 49 | - name: Set up QEMU 50 | uses: docker/setup-qemu-action@v2 51 | 52 | - name: Set up Docker Buildx 53 | uses: docker/setup-buildx-action@v3 54 | 55 | - name: Login to DockerHub 56 | uses: docker/login-action@v2 57 | with: 58 | username: ${{ secrets.DOCKER_USERNAME }} 59 | password: ${{ secrets.DOCKER_PASSWORD }} 60 | 61 | - name: Docker meta 62 | id: meta 63 | uses: docker/metadata-action@v4 64 | with: 65 | images: ${{ secrets.DOCKERHUB_REPO}}/bpfsnitch 66 | 67 | - name: Build and push 68 | uses: docker/build-push-action@v5 69 | with: 70 | context: . 71 | file: ./deployments/Dockerfile 72 | platforms: linux/amd64,linux/arm64, linux/arm/v7 73 | push: ${{ github.event_name != 'pull_request' }} 74 | tags: ${{ steps.meta.outputs.tags }} 75 | labels: ${{ steps.meta.outputs.labels }} 76 | -------------------------------------------------------------------------------- /internal/workload/runtime_handlers.go: -------------------------------------------------------------------------------- 1 | package workload 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | "google.golang.org/grpc" 10 | "google.golang.org/grpc/credentials/insecure" 11 | runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 12 | ) 13 | 14 | func getRuntimeServiceClient() (runtimeapi.RuntimeServiceClient, *grpc.ClientConn, error) { 15 | var runtimeEndpoint string 16 | for _, endpoint := range runtimeSockets { 17 | if _, err := os.Stat(endpoint); err == nil { 18 | runtimeEndpoint = endpoint 19 | break 20 | } 21 | } 22 | 23 | if runtimeEndpoint == "" { 24 | return nil, nil, errors.New("no runtime socket found") 25 | } 26 | 27 | serverAddr := "unix://" + runtimeEndpoint 28 | conn, err := grpc.NewClient( 29 | serverAddr, 30 | grpc.WithTransportCredentials(insecure.NewCredentials()), 31 | ) 32 | if err != nil { 33 | return nil, nil, fmt.Errorf( 34 | "failed to connect to %s: %w", 35 | serverAddr, 36 | err, 37 | ) 38 | } 39 | 40 | runtimeClient := runtimeapi.NewRuntimeServiceClient(conn) 41 | return runtimeClient, conn, nil 42 | } 43 | 44 | func getContainers( 45 | ctx context.Context, 46 | runtimeClient runtimeapi.RuntimeServiceClient, 47 | ) ([]*runtimeapi.Container, error) { 48 | req := &runtimeapi.ListContainersRequest{ 49 | Filter: &runtimeapi.ContainerFilter{ 50 | State: &runtimeapi.ContainerStateValue{ 51 | State: runtimeapi.ContainerState_CONTAINER_RUNNING, 52 | }, 53 | }, 54 | } 55 | resp, err := runtimeClient.ListContainers(ctx, req) 56 | if err != nil { 57 | return nil, fmt.Errorf("failed to list containers: %w", err) 58 | } 59 | return resp.Containers, nil 60 | } 61 | 62 | func getPods( 63 | ctx context.Context, 64 | runtimeClient runtimeapi.RuntimeServiceClient, 65 | ) ([]*runtimeapi.PodSandbox, error) { 66 | req := &runtimeapi.ListPodSandboxRequest{ 67 | Filter: &runtimeapi.PodSandboxFilter{ 68 | State: &runtimeapi.PodSandboxStateValue{ 69 | State: runtimeapi.PodSandboxState_SANDBOX_READY, 70 | }, 71 | }, 72 | } 73 | resp, err := runtimeClient.ListPodSandbox(ctx, req) 74 | if err != nil { 75 | return nil, fmt.Errorf("failed to list pods: %w", err) 76 | } 77 | return resp.Items, nil 78 | } 79 | -------------------------------------------------------------------------------- /internal/bpf/event_processor.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "context" 5 | "log/slog" 6 | 7 | "github.com/nullswan/bpfsnitch/internal/metrics" 8 | "github.com/nullswan/bpfsnitch/pkg/network" 9 | ) 10 | 11 | func ProcessNetworkEvent( 12 | event *NetworkEvent, 13 | pod string, 14 | log *slog.Logger, 15 | ) { 16 | // Adjust endianness if necessary 17 | event.Saddr = network.Ntohl(event.Saddr) 18 | event.Daddr = network.Ntohl(event.Daddr) 19 | event.Sport = network.Ntohs(event.Sport) 20 | event.Dport = network.Ntohs(event.Dport) 21 | 22 | // Convert IP addresses to net.IP 23 | saddr := network.IntToSubnet(event.Saddr, network.SubnetMask24) 24 | daddr := network.IntToSubnet(event.Daddr, network.SubnetMask24) 25 | 26 | if log.Enabled(context.TODO(), slog.LevelDebug) { 27 | log.With("pid", event.Pid). 28 | With("cgroup_id", event.CgroupID). 29 | With("pod", pod). 30 | With("saddr", saddr). 31 | With("daddr", daddr). 32 | With("sport", event.Sport). 33 | With("dport", event.Dport). 34 | With("size", event.Size). 35 | Debug("Received network event") 36 | } 37 | 38 | if event.Protocol == NetworkEventProtocolUDP && 39 | event.Direction == NetworkEventDirectionOutbound && 40 | event.Dport == 53 { 41 | metrics.DNSQueryCounter.WithLabelValues(pod).Inc() 42 | } 43 | 44 | daddrStr := daddr.String() 45 | if event.Direction == 0 { 46 | metrics.NetworkSentBytesCounter.WithLabelValues(pod, daddrStr). 47 | Add(float64(event.Size)) 48 | metrics.NetworkSentPacketsCounter.WithLabelValues(pod, daddrStr). 49 | Inc() 50 | } else { 51 | metrics.NetworkReceivedBytesCounter.WithLabelValues(pod, daddrStr).Add(float64(event.Size)) 52 | metrics.NetworkReceivedPacketsCounter.WithLabelValues(pod, daddrStr).Inc() 53 | } 54 | } 55 | 56 | func ProcessSyscallEvent( 57 | event *SyscallEvent, 58 | pod string, 59 | log *slog.Logger, 60 | ) { 61 | // Check if debug logging is enabled for performance reasons 62 | if log.Enabled(context.TODO(), slog.LevelDebug) { 63 | log. 64 | With("syscall", event.GetSyscallName()). 65 | With("pid", event.Pid). 66 | With("cgroup_id", event.CgroupID). 67 | With("pod", pod). 68 | Debug("Received syscall event") 69 | } 70 | 71 | metrics.SyscallCounter.WithLabelValues(event.GetSyscallName(), pod). 72 | Inc() 73 | } 74 | -------------------------------------------------------------------------------- /pkg/lru/lru.go: -------------------------------------------------------------------------------- 1 | package lru 2 | 3 | import ( 4 | "container/list" 5 | "sync" 6 | ) 7 | 8 | // Cache is a thread-safe fixed size LRU cache. 9 | type Cache[K comparable, V any] struct { 10 | capacity int 11 | lock sync.Mutex 12 | cache map[K]*list.Element 13 | list *list.List 14 | } 15 | 16 | type pair[K comparable, V any] struct { 17 | key K 18 | value V 19 | } 20 | 21 | // New creates a new LRUCache with the given capacity. 22 | func New[K comparable, V any](capacity int) *Cache[K, V] { 23 | return &Cache[K, V]{ 24 | capacity: capacity, 25 | cache: make(map[K]*list.Element), 26 | list: list.New(), 27 | } 28 | } 29 | 30 | // Get retrieves the value of the key from the cache and marks the key as recently used. 31 | func (c *Cache[K, V]) Get(key K) (value V, ok bool) { 32 | c.lock.Lock() 33 | defer c.lock.Unlock() 34 | 35 | if elem, found := c.cache[key]; found { 36 | c.list.MoveToFront(elem) 37 | return elem.Value.(*pair[K, V]).value, true 38 | } 39 | var zeroValue V 40 | return zeroValue, false 41 | } 42 | 43 | // Put adds a key-value pair to the cache and evicts items if the cache is full. 44 | func (c *Cache[K, V]) Put(key K, value V) { 45 | c.lock.Lock() 46 | defer c.lock.Unlock() 47 | 48 | if elem, found := c.cache[key]; found { 49 | c.list.MoveToFront(elem) 50 | elem.Value.(*pair[K, V]).value = value 51 | return 52 | } 53 | 54 | if c.list.Len() >= c.capacity { 55 | backElem := c.list.Back() 56 | if backElem != nil { 57 | c.list.Remove(backElem) 58 | delete(c.cache, backElem.Value.(*pair[K, V]).key) 59 | } 60 | } 61 | 62 | entry := &pair[K, V]{key: key, value: value} 63 | elem := c.list.PushFront(entry) 64 | c.cache[key] = elem 65 | } 66 | 67 | // Remove removes the key from the cache. 68 | func (c *Cache[K, V]) Remove(key K) { 69 | c.lock.Lock() 70 | defer c.lock.Unlock() 71 | 72 | if elem, found := c.cache[key]; found { 73 | c.list.Remove(elem) 74 | delete(c.cache, key) 75 | } 76 | } 77 | 78 | // ForEach iterates over all elements in the cache and calls the given function for each element. 79 | func (c *Cache[K, V]) ForEach(fn func(key K, value V) bool) { 80 | c.lock.Lock() 81 | defer c.lock.Unlock() 82 | 83 | for elem := c.list.Front(); elem != nil; elem = elem.Next() { 84 | p := elem.Value.(*pair[K, V]) 85 | if !fn(p.key, p.value) { 86 | break 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /internal/workload/resolve.go: -------------------------------------------------------------------------------- 1 | package workload 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "log/slog" 8 | "os" 9 | "regexp" 10 | "strings" 11 | 12 | "github.com/nullswan/bpfsnitch/pkg/lru" 13 | ) 14 | 15 | var ( 16 | ErrCgroupIDBanned = errors.New("cgroup id is banned") 17 | ErrCgroupIDNotContainer = errors.New("cgroup id is not container") 18 | ) 19 | 20 | func ResolvePod( 21 | pid uint64, 22 | cgroupID uint64, 23 | pidToShaLRU *lru.Cache[uint64, string], 24 | bannedCgroupIDs *lru.Cache[uint64, struct{}], 25 | shaResolver *ShaResolver, 26 | procPath string, 27 | log *slog.Logger, 28 | ) (string, error) { 29 | if _, ok := bannedCgroupIDs.Get(cgroupID); ok { 30 | return "", ErrCgroupIDBanned 31 | } 32 | 33 | sha, ok := pidToShaLRU.Get(pid) 34 | if !ok { 35 | sha, err := readShaFromCgroup( 36 | pid, 37 | cgroupID, 38 | bannedCgroupIDs, 39 | procPath, 40 | log, 41 | ) 42 | if err != nil { 43 | return "", fmt.Errorf("failed to read sha from cgroup: %w", err) 44 | } 45 | pidToShaLRU.Put(pid, sha) 46 | } 47 | 48 | pod, err := shaResolver.Resolve(sha) 49 | if err != nil { 50 | return "", fmt.Errorf("failed to resolve sha: %w", err) 51 | } 52 | 53 | return pod, nil 54 | } 55 | 56 | var reKubeContainerd = regexp.MustCompile(`([a-f0-9]{64})\.scope`) 57 | 58 | func readShaFromCgroup( 59 | pid uint64, 60 | cgroupID uint64, 61 | bannedCgroupIDs *lru.Cache[uint64, struct{}], 62 | procPath string, 63 | log *slog.Logger, 64 | ) (string, error) { 65 | fd, err := os.Open(fmt.Sprintf("/%s/%d/cgroup", procPath, pid)) 66 | if err != nil { 67 | return "", fmt.Errorf("failed to open cgroup file: %w", err) 68 | } 69 | defer fd.Close() 70 | 71 | content, err := io.ReadAll(fd) 72 | if err != nil { 73 | return "", fmt.Errorf("failed to read cgroup file: %w", err) 74 | } 75 | 76 | // format local containerd 77 | contentStr := string(content) 78 | if strings.Contains(contentStr, "k8s.io") { 79 | sha := strings.TrimSpace( 80 | contentStr[strings.LastIndex(contentStr, "/")+1:], 81 | ) 82 | return sha, nil 83 | } 84 | 85 | // format SCW, AWS 86 | // 0::/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod7bd1a2a3_0861_4fe1_be78_9c76385b3dc0.slice/cri-containerd-1579a01cfce4b1e74529c17bed485d86b871b58f13348c773076b101df4ff62d.scope 87 | if strings.Contains(contentStr, "cri-containerd") { 88 | match := reKubeContainerd.FindStringSubmatch(contentStr) 89 | if len(match) == 2 { // nolint: mnd 90 | return match[1], nil 91 | } 92 | } 93 | 94 | log.With("cgroup_id", cgroupID).Debug("Banning cgroup id") 95 | bannedCgroupIDs.Put(cgroupID, struct{}{}) 96 | return "", ErrCgroupIDNotContainer 97 | } 98 | -------------------------------------------------------------------------------- /bpf/kprobe/trace_udp.c: -------------------------------------------------------------------------------- 1 | #include "bpf/core.h" 2 | 3 | struct udp_recvmsg_args { 4 | struct sock *sk; 5 | struct msghdr *msg; 6 | size_t size; 7 | int flags; 8 | int *addr_len; 9 | }; 10 | 11 | SEC("kprobe/udp_recvmsg") 12 | int trace_udp_recvmsg(struct udp_recvmsg_args *ctx) { 13 | u64 cgroup_id = bpf_get_current_cgroup_id(); 14 | u32 pid = bpf_get_current_pid_tgid() >> 32; 15 | 16 | struct sock *sk = ctx->sk; 17 | size_t size = ctx->size; 18 | 19 | __u64 err; 20 | __be32 saddr; 21 | __be32 daddr; 22 | __be16 dport; 23 | __u16 sport; 24 | 25 | err = bpf_probe_read(&saddr, sizeof(saddr), &sk->__sk_common.skc_rcv_saddr); 26 | if (err != 0) 27 | return 0; 28 | err = bpf_probe_read(&daddr, sizeof(daddr), &sk->__sk_common.skc_daddr); 29 | if (err != 0) 30 | return 0; 31 | err = bpf_probe_read(&dport, sizeof(dport), &sk->__sk_common.skc_dport); 32 | if (err != 0) 33 | return 0; 34 | err = bpf_probe_read(&sport, sizeof(sport), &sk->__sk_common.skc_num); 35 | if (err != 0) 36 | return 0; 37 | 38 | if (is_local_ip(saddr) || is_local_ip(daddr)) { 39 | return 0; 40 | } 41 | 42 | struct network_event e = {}; 43 | e.pid = pid; 44 | e.cgroup_id = cgroup_id; 45 | e.size = size; 46 | e.saddr = saddr; 47 | e.daddr = daddr; 48 | e.sport = sport; 49 | e.dport = dport; 50 | e.direction = DIRECTION_INBOUND; 51 | e.protocol = PROTOCOL_UDP; 52 | 53 | bpf_ringbuf_output(&network_events_rb, &e, sizeof(e), BPF_RB_FORCE_WAKEUP); 54 | return 0; 55 | } 56 | 57 | struct udp_sendmsg_args { 58 | struct sock *sk; 59 | struct msghdr *msg; 60 | size_t len; 61 | }; 62 | 63 | SEC("kprobe/udp_sendmsg") 64 | int trace_udp_sendmsg(struct udp_sendmsg_args *ctx) { 65 | u64 cgroup_id = bpf_get_current_cgroup_id(); 66 | u32 pid = bpf_get_current_pid_tgid() >> 32; 67 | 68 | struct sock *sk = ctx->sk; 69 | size_t size = ctx->len; 70 | 71 | __u64 err; 72 | __be32 saddr; 73 | __be32 daddr; 74 | __be16 sport; 75 | __be16 dport; 76 | 77 | err = bpf_probe_read(&saddr, sizeof(saddr), &sk->__sk_common.skc_rcv_saddr); 78 | if (err != 0) 79 | return 0; 80 | err = bpf_probe_read(&daddr, sizeof(daddr), &sk->__sk_common.skc_daddr); 81 | if (err != 0) 82 | return 0; 83 | err = bpf_probe_read(&dport, sizeof(dport), &sk->__sk_common.skc_dport); 84 | if (err != 0) 85 | return 0; 86 | err = bpf_probe_read(&sport, sizeof(sport), &sk->__sk_common.skc_num); 87 | if (err != 0) 88 | return 0; 89 | 90 | if (is_local_ip(saddr) || is_local_ip(daddr)) { 91 | return 0; 92 | } 93 | 94 | struct network_event e = {}; 95 | e.pid = pid; 96 | e.cgroup_id = cgroup_id; 97 | e.size = size; 98 | e.saddr = saddr; 99 | e.daddr = daddr; 100 | e.sport = sport; 101 | e.dport = dport; 102 | e.direction = DIRECTION_OUTBOUND; 103 | e.protocol = PROTOCOL_UDP; 104 | 105 | bpf_ringbuf_output(&network_events_rb, &e, sizeof(e), BPF_RB_FORCE_WAKEUP); 106 | return 0; 107 | } -------------------------------------------------------------------------------- /bpf/kprobe/trace_tcp.c: -------------------------------------------------------------------------------- 1 | #include "bpf/core.h" 2 | 3 | struct tcp_recvmsg_args { 4 | struct sock *sk; 5 | struct msghdr *msg; 6 | size_t len; 7 | int nonblock; 8 | int flags; 9 | int *addr_len; 10 | }; 11 | 12 | SEC("kprobe/tcp_recvmsg") 13 | int trace_tcp_recvmsg(struct tcp_recvmsg_args *ctx) { 14 | u64 cgroup_id = bpf_get_current_cgroup_id(); 15 | u32 pid = bpf_get_current_pid_tgid() >> 32; 16 | 17 | struct sock *sk = ctx->sk; 18 | size_t size = ctx->len; 19 | 20 | __u64 err; 21 | __be32 saddr; 22 | __be32 daddr; 23 | __be16 sport; 24 | __be16 dport; 25 | 26 | err = bpf_probe_read(&saddr, sizeof(saddr), &sk->__sk_common.skc_rcv_saddr); 27 | if (err != 0) 28 | return 0; 29 | err = bpf_probe_read(&daddr, sizeof(daddr), &sk->__sk_common.skc_daddr); 30 | if (err != 0) 31 | return 0; 32 | err = bpf_probe_read(&dport, sizeof(dport), &sk->__sk_common.skc_dport); 33 | if (err != 0) 34 | return 0; 35 | err = bpf_probe_read(&sport, sizeof(sport), &sk->__sk_common.skc_num); 36 | if (err != 0) 37 | return 0; 38 | 39 | if (is_local_ip(saddr) || is_local_ip(daddr)) { 40 | return 0; 41 | } 42 | 43 | struct network_event e = {}; 44 | e.pid = pid; 45 | e.cgroup_id = cgroup_id; 46 | e.size = size; 47 | e.saddr = saddr; 48 | e.daddr = daddr; 49 | e.sport = sport; 50 | e.dport = dport; 51 | e.direction = DIRECTION_INBOUND; 52 | e.protocol = PROTOCOL_TCP; 53 | 54 | bpf_ringbuf_output(&network_events_rb, &e, sizeof(e), BPF_RB_FORCE_WAKEUP); 55 | return 0; 56 | } 57 | 58 | struct tcp_sendmsg_args { 59 | struct sock *sk; 60 | struct msghdr *msg; 61 | size_t size; 62 | }; 63 | 64 | SEC("kprobe/tcp_sendmsg") 65 | int trace_tcp_sendmsg(struct tcp_sendmsg_args *ctx) { 66 | u64 cgroup_id = bpf_get_current_cgroup_id(); 67 | u32 pid = bpf_get_current_pid_tgid() >> 32; 68 | struct sock *sk = ctx->sk; 69 | size_t size = ctx->size; 70 | 71 | __u64 err; 72 | __be32 saddr; 73 | __be32 daddr; 74 | __be16 sport; 75 | __be16 dport; 76 | 77 | err = bpf_probe_read(&saddr, sizeof(saddr), &sk->__sk_common.skc_rcv_saddr); 78 | if (err != 0) 79 | return 0; 80 | err = bpf_probe_read(&daddr, sizeof(daddr), &sk->__sk_common.skc_daddr); 81 | if (err != 0) 82 | return 0; 83 | err = bpf_probe_read(&dport, sizeof(dport), &sk->__sk_common.skc_dport); 84 | if (err != 0) 85 | return 0; 86 | err = bpf_probe_read(&sport, sizeof(sport), &sk->__sk_common.skc_num); 87 | if (err != 0) 88 | return 0; 89 | 90 | if (is_local_ip(saddr) || is_local_ip(daddr)) { 91 | return 0; 92 | } 93 | 94 | struct network_event e = {}; 95 | e.pid = pid; 96 | e.cgroup_id = cgroup_id; 97 | e.size = size; 98 | e.saddr = saddr; 99 | e.daddr = daddr; 100 | e.sport = sport; 101 | e.dport = dport; 102 | e.direction = DIRECTION_OUTBOUND; 103 | e.protocol = PROTOCOL_TCP; 104 | 105 | bpf_ringbuf_output(&network_events_rb, &e, sizeof(e), BPF_RB_FORCE_WAKEUP); 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /internal/bpf/attacher.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | 7 | "github.com/cilium/ebpf" 8 | "github.com/cilium/ebpf/link" 9 | "github.com/cilium/ebpf/ringbuf" 10 | "github.com/cilium/ebpf/rlimit" 11 | ) 12 | 13 | // Define a Kernel BPF context. 14 | type KBContext struct { 15 | SyscallRingBuffer *ringbuf.Reader 16 | NetworkRingBuffer *ringbuf.Reader 17 | 18 | Tps []link.Link 19 | Kps []link.Link 20 | } 21 | 22 | func Attach( 23 | log *slog.Logger, 24 | bpfProgramElf string, 25 | ) (*KBContext, error) { 26 | if err := rlimit.RemoveMemlock(); err != nil { 27 | return nil, fmt.Errorf("failed to remove memlock limit: %w", err) 28 | } 29 | 30 | spec, err := ebpf.LoadCollectionSpec(bpfProgramElf) 31 | if err != nil { 32 | return nil, fmt.Errorf("failed to create eBPF program: %w", err) 33 | } 34 | 35 | coll, err := ebpf.NewCollection(spec) 36 | if err != nil { 37 | return nil, fmt.Errorf("failed to create eBPF collection: %w", err) 38 | } 39 | defer coll.Close() 40 | 41 | log.Info("Loaded eBPF program", "programs", coll.Programs) 42 | log.Info("Loaded eBPF maps", "maps", coll.Maps) 43 | 44 | err = registerWhitelistedSyscalls(log, coll.Maps) 45 | if err != nil { 46 | return nil, fmt.Errorf( 47 | "failed to register whitelisted syscalls: %w", 48 | err, 49 | ) 50 | } 51 | 52 | syscallRingBuffer, err := ringbuf.NewReader( 53 | coll.Maps["syscall_events_rb"], 54 | ) 55 | if err != nil { 56 | return nil, fmt.Errorf("failed to create ring buffer: %w", err) 57 | } 58 | 59 | networkRingBuffer, err := ringbuf.NewReader( 60 | coll.Maps["network_events_rb"], 61 | ) 62 | if err != nil { 63 | err2 := syscallRingBuffer.Close() 64 | 65 | if err2 != nil { 66 | log.With("error", err2). 67 | Error("Failed to close ring buffer") 68 | } 69 | 70 | return nil, fmt.Errorf("failed to create ring buffer: %w", err) 71 | } 72 | 73 | tps, err := attachTracepoints(log, coll) 74 | if err != nil { 75 | err2 := syscallRingBuffer.Close() 76 | if err2 != nil { 77 | log.With("error", err2). 78 | Error("Failed to close perf reader") 79 | } 80 | 81 | err2 = networkRingBuffer.Close() 82 | if err2 != nil { 83 | log.With("error", err2). 84 | Error("Failed to close perf reader") 85 | } 86 | 87 | return nil, fmt.Errorf("failed to attach tps: %w", err) 88 | } 89 | 90 | kps, err := attachKProbes(log, coll) 91 | if err != nil { 92 | err2 := syscallRingBuffer.Close() 93 | if err2 != nil { 94 | log.With("error", err2). 95 | Error("Failed to close perf reader") 96 | } 97 | 98 | err2 = networkRingBuffer.Close() 99 | if err2 != nil { 100 | log.With("error", err2). 101 | Error("Failed to close perf reader") 102 | } 103 | 104 | for _, tp := range tps { 105 | tp.Close() 106 | } 107 | 108 | return nil, fmt.Errorf("failed to attach kps: %w", err) 109 | } 110 | 111 | return &KBContext{ 112 | SyscallRingBuffer: syscallRingBuffer, 113 | NetworkRingBuffer: networkRingBuffer, 114 | Tps: tps, 115 | Kps: kps, 116 | }, nil 117 | } 118 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 15 | do not have permission to do that, you may request the second reviewer to merge it for you. 16 | 17 | ## Code of Conduct 18 | 19 | ### Our Pledge 20 | 21 | In the interest of fostering an open and welcoming environment, we as 22 | contributors and maintainers pledge to making participation in our project and 23 | our community a harassment-free experience for everyone, regardless of age, body 24 | size, disability, ethnicity, gender identity and expression, level of experience, 25 | nationality, personal appearance, race, religion, or sexual identity and 26 | orientation. 27 | 28 | ### Our Standards 29 | 30 | Examples of behavior that contributes to creating a positive environment 31 | include: 32 | 33 | * Using welcoming and inclusive language 34 | * Being respectful of differing viewpoints and experiences 35 | * Gracefully accepting constructive criticism 36 | * Focusing on what is best for the community 37 | * Showing empathy towards other community members 38 | 39 | Examples of unacceptable behavior by participants include: 40 | 41 | * The use of sexualized language or imagery and unwelcome sexual attention or 42 | advances 43 | * Trolling, insulting/derogatory comments, and personal or political attacks 44 | * Public or private harassment 45 | * Publishing others' private information, such as a physical or electronic 46 | address, without explicit permission 47 | * Other conduct which could reasonably be considered inappropriate in a 48 | professional setting 49 | 50 | ### Our Responsibilities 51 | 52 | Project maintainers are responsible for clarifying the standards of acceptable 53 | behavior and are expected to take appropriate and fair corrective action in 54 | response to any instances of unacceptable behavior. 55 | 56 | Project maintainers have the right and responsibility to remove, edit, or 57 | reject comments, commits, code, wiki edits, issues, and other contributions 58 | that are not aligned to this Code of Conduct, or to ban temporarily or 59 | permanently any contributor for other behaviors that they deem inappropriate, 60 | threatening, offensive, or harmful. 61 | 62 | ### Scope 63 | 64 | This Code of Conduct applies both within project spaces and in public spaces 65 | when an individual is representing the project or its community. Examples of 66 | representing a project or community include using an official project e-mail 67 | address, posting via an official social media account, or acting as an appointed 68 | representative at an online or offline event. Representation of a project may be 69 | further defined and clarified by project maintainers. 70 | 71 | ### Enforcement 72 | 73 | All complaints will be reviewed and investigated and will result in a response that 74 | is deemed necessary and appropriate to the circumstances. The project team is 75 | obligated to maintain confidentiality with regard to the reporter of an incident. 76 | Further details of specific enforcement policies may be posted separately. 77 | 78 | Project maintainers who do not follow or enforce the Code of Conduct in good 79 | faith may face temporary or permanent repercussions as determined by other 80 | members of the project's leadership. 81 | 82 | ### Attribution 83 | 84 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 85 | available at [http://contributor-covenant.org/version/1/4][version] 86 | 87 | [homepage]: http://contributor-covenant.org 88 | [version]: http://contributor-covenant.org/version/1/4/ 89 | -------------------------------------------------------------------------------- /internal/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "log/slog" 9 | 10 | "github.com/nullswan/bpfsnitch/internal/bpf" 11 | bpfarch "github.com/nullswan/bpfsnitch/internal/bpf/arch" 12 | "github.com/nullswan/bpfsnitch/internal/kernel" 13 | "github.com/nullswan/bpfsnitch/internal/metrics" 14 | "github.com/nullswan/bpfsnitch/internal/profile" 15 | "github.com/nullswan/bpfsnitch/internal/sig" 16 | "github.com/nullswan/bpfsnitch/internal/workload" 17 | "github.com/nullswan/bpfsnitch/pkg/lru" 18 | ) 19 | 20 | const ( 21 | bpfProgramElf = bpfarch.BpfProgramElf 22 | cacheBannedSz = 1000 23 | cachePidToShaSz = 1000 24 | defaultPrometheusPort = 9090 25 | minKernelVersion = "5.8" 26 | defaultMountedProcPath = "/host_proc" 27 | ) 28 | 29 | func Run( 30 | log *slog.Logger, 31 | ) error { 32 | kernelVersion, err := kernel.GetKernelVersion() 33 | if err != nil { 34 | return fmt.Errorf("failed to get kernel version: %w", err) 35 | } 36 | 37 | if kernel.CompareVersions(kernelVersion, minKernelVersion) < 0 { 38 | return fmt.Errorf( 39 | "kernel version %s is not supported, minimum is %s", 40 | kernelVersion, 41 | minKernelVersion, 42 | ) 43 | } 44 | 45 | if !workload.IsSocketPresent() { 46 | return errors.New("runtime socket not found") 47 | } 48 | 49 | var enablePprof bool 50 | flag.BoolVar(&enablePprof, "pprof", false, "Enable pprof") 51 | 52 | var enableProfiling bool 53 | flag.BoolVar(&enableProfiling, "profiling", false, "Enable profiling") 54 | 55 | var prometheusPort uint64 56 | flag.Uint64Var( 57 | &prometheusPort, 58 | "prometheus-port", 59 | defaultPrometheusPort, 60 | "Prometheus port", 61 | ) 62 | 63 | flag.Parse() 64 | 65 | if enableProfiling { 66 | log.Info("Profiling enabled") 67 | err := profile.SetupProfiling(log) 68 | if err != nil { 69 | return fmt.Errorf("failed to setup profiling: %w", err) 70 | } 71 | } 72 | 73 | bpfCtx, err := bpf.Attach(log, bpfProgramElf) 74 | if err != nil { 75 | return fmt.Errorf("failed while attaching bpf: %w", err) 76 | } 77 | 78 | ctx, cancel := context.WithCancel(context.Background()) 79 | defer cancel() 80 | 81 | // Set up signal handling to cancel context on termination. 82 | sig.SetupHandler(cancel, bpfCtx, log) 83 | 84 | metrics.RegisterMetrics() 85 | if enablePprof { 86 | log.Info("pprof enabled") 87 | profile.SetupPprof() 88 | } 89 | 90 | go metrics.StartServer(log, cancel, prometheusPort) 91 | 92 | deletedPodChan := make(chan string) 93 | shaResolver, err := workload.NewShaResolver(log, deletedPodChan) 94 | if err != nil { 95 | return fmt.Errorf("failed to create sha resolver: %w", err) 96 | } 97 | syscallEventChan := make(chan *bpf.SyscallEvent) 98 | networkEventChan := make(chan *bpf.NetworkEvent) 99 | go bpf.ConsumeEvents(ctx, log, bpfCtx.SyscallRingBuffer, syscallEventChan) 100 | go bpf.ConsumeEvents(ctx, log, bpfCtx.NetworkRingBuffer, networkEventChan) 101 | 102 | go deletePods(ctx, log, deletedPodChan) 103 | 104 | bannedCgroupIDs := lru.New[uint64, struct{}](cacheBannedSz) 105 | pidToShaLRU := lru.New[uint64, string](cachePidToShaSz) 106 | 107 | log. 108 | With("proc_path", defaultMountedProcPath). 109 | Info("Starting event processor") 110 | 111 | for { 112 | select { 113 | case <-ctx.Done(): 114 | log.Info("Context done, exiting") 115 | return nil 116 | case event := <-networkEventChan: 117 | pod, err := workload.ResolvePod( 118 | event.Pid, 119 | event.CgroupID, 120 | pidToShaLRU, 121 | bannedCgroupIDs, 122 | shaResolver, 123 | defaultMountedProcPath, 124 | log, 125 | ) 126 | if err != nil { 127 | if !errors.Is(err, workload.ErrCgroupIDBanned) { 128 | log.With("error", err).Debug("failed to resolve pod") 129 | } 130 | continue 131 | } 132 | 133 | bpf.ProcessNetworkEvent(event, pod, log) 134 | case event := <-syscallEventChan: 135 | pod, err := workload.ResolvePod( 136 | event.Pid, 137 | event.CgroupID, 138 | pidToShaLRU, 139 | bannedCgroupIDs, 140 | shaResolver, 141 | defaultMountedProcPath, 142 | log, 143 | ) 144 | if err != nil { 145 | if !errors.Is(err, workload.ErrCgroupIDBanned) { 146 | log.With("error", err). 147 | Debug("failed to resolve pod") 148 | } 149 | continue 150 | } 151 | 152 | bpf.ProcessSyscallEvent(event, pod, log) 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /deployments/daemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: bpfsnitch-agent 5 | namespace: kube-system 6 | labels: 7 | k8s-app: bpfsnitch-agent 8 | kubernetes.io/cluster-service: "true" 9 | spec: 10 | selector: 11 | matchLabels: 12 | k8s-app: bpfsnitch-agent 13 | kubernetes.io/cluster-service: "true" 14 | template: 15 | metadata: 16 | labels: 17 | k8s-app: bpfsnitch-agent 18 | kubernetes.io/cluster-service: "true" 19 | spec: 20 | affinity: 21 | nodeAffinity: 22 | requiredDuringSchedulingIgnoredDuringExecution: 23 | nodeSelectorTerms: 24 | - matchExpressions: 25 | - key: kubernetes.io/os 26 | operator: In 27 | values: 28 | - linux 29 | - key: kubernetes.io/arch 30 | operator: In 31 | values: 32 | - amd64 33 | - matchExpressions: 34 | - key: kubernetes.io/os 35 | operator: In 36 | values: 37 | - linux 38 | - key: kubernetes.io/arch 39 | operator: In 40 | values: 41 | - arm64 42 | - matchExpressions: 43 | - key: kubernetes.io/os 44 | operator: In 45 | values: 46 | - linux 47 | - key: kubernetes.io/arch 48 | operator: In 49 | values: 50 | - arm 51 | initContainers: 52 | - name: mount-bpf-fs 53 | image: alpine:3.20 54 | command: 55 | - /bin/sh 56 | - "-c" 57 | - "--" 58 | args: 59 | - >- 60 | mount | grep "/sys/fs/bpf type bpf" || mount -t bpf bpf /sys/fs/bpf 61 | volumeMounts: 62 | - name: bpf-maps 63 | mountPath: /sys/fs/bpf 64 | mountPropagation: Bidirectional 65 | terminationMessagePath: /dev/termination-log 66 | terminationMessagePolicy: FallbackToLogsOnError 67 | imagePullPolicy: IfNotPresent 68 | securityContext: 69 | privileged: true 70 | containers: 71 | - name: bpfsnitch-agent 72 | image: nullswan/bpfsnitch:latest 73 | imagePullPolicy: IfNotPresent 74 | args: 75 | - "./bpfsnitch" 76 | ports: 77 | - containerPort: 9090 78 | protocol: TCP 79 | securityContext: 80 | privileged: true 81 | capabilities: 82 | # TODO: sort out the capabilities 83 | add: 84 | - CHOWN 85 | - KILL 86 | - NET_ADMIN 87 | - NET_RAW 88 | - IPC_LOCK 89 | - SYS_MODULE 90 | - SYS_ADMIN 91 | - SYS_RESOURCE 92 | - DAC_OVERRIDE 93 | - FOWNER 94 | - SETGID 95 | - SETUID 96 | drop: 97 | - ALL 98 | volumeMounts: 99 | - name: bpf-maps 100 | mountPath: /sys/fs/bpf 101 | mountPropagation: HostToContainer 102 | - name: kernel-trace 103 | mountPath: /sys/kernel/tracing 104 | mountPropagation: HostToContainer 105 | - name: kernel-debug 106 | mountPath: /sys/kernel/debug 107 | mountPropagation: HostToContainer 108 | - name: host-proc 109 | mountPath: /host_proc 110 | mountPropagation: HostToContainer 111 | readOnly: true 112 | - name: containerd-sock 113 | mountPath: /run/containerd/containerd.sock 114 | mountPropagation: HostToContainer 115 | readOnly: true 116 | resources: 117 | limits: 118 | memory: "250Mi" 119 | cpu: "100m" 120 | requests: 121 | memory: "250Mi" 122 | cpu: "100m" 123 | volumes: 124 | - name: bpf-maps 125 | hostPath: 126 | path: /sys/fs/bpf 127 | type: DirectoryOrCreate 128 | - name: kernel-trace 129 | hostPath: 130 | path: /sys/kernel/tracing 131 | type: Directory 132 | - name: kernel-debug 133 | hostPath: 134 | path: /sys/kernel/debug 135 | type: Directory 136 | - name: host-proc 137 | hostPath: 138 | path: /proc 139 | type: Directory 140 | - name: containerd-sock 141 | hostPath: 142 | path: /run/containerd/containerd.sock 143 | type: Socket 144 | -------------------------------------------------------------------------------- /internal/workload/sha_resolver.go: -------------------------------------------------------------------------------- 1 | package workload 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log/slog" 7 | "sync" 8 | "time" 9 | 10 | "github.com/nullswan/bpfsnitch/pkg/lru" 11 | "google.golang.org/grpc" 12 | runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 13 | ) 14 | 15 | const ( 16 | internalLRUCacheSize = 1000 17 | shaResolverTimeout = 5 * time.Second 18 | ) 19 | 20 | // ContainerInfo stores information about a container's associated pod. 21 | type ContainerInfo struct { 22 | PodID string 23 | PodName string 24 | } 25 | 26 | type ContainerSha string 27 | 28 | type ShaResolver struct { 29 | containerToPodInfo *lru.Cache[ContainerSha, *ContainerInfo] 30 | 31 | logger *slog.Logger 32 | client runtimeapi.RuntimeServiceClient 33 | conn *grpc.ClientConn 34 | 35 | // Channel for expired pods 36 | ExpiredPodChan chan string 37 | 38 | // Map of known pod IDs to pod metadata 39 | knownPods map[string]*runtimeapi.PodSandbox 40 | knownPodsMutex sync.Mutex 41 | } 42 | 43 | // NewShaResolver creates a new ShaResolver instance. 44 | func NewShaResolver( 45 | logger *slog.Logger, 46 | expiredPodChan chan string, 47 | ) (*ShaResolver, error) { 48 | containerToPodInfo := lru.New[ContainerSha, *ContainerInfo]( 49 | internalLRUCacheSize, 50 | ) 51 | 52 | client, conn, err := getRuntimeServiceClient() 53 | if err != nil { 54 | return nil, fmt.Errorf("failed to get runtime service client: %w", err) 55 | } 56 | 57 | return &ShaResolver{ 58 | containerToPodInfo: containerToPodInfo, 59 | client: client, 60 | conn: conn, 61 | logger: logger, 62 | ExpiredPodChan: expiredPodChan, 63 | knownPods: make(map[string]*runtimeapi.PodSandbox), 64 | knownPodsMutex: sync.Mutex{}, 65 | }, nil 66 | } 67 | 68 | // Resolve returns the pod name associated with a given container SHA. 69 | func (r *ShaResolver) Resolve(inputSha string) (string, error) { 70 | sha := ContainerSha(inputSha) 71 | 72 | v, ok := r.containerToPodInfo.Get(sha) 73 | if ok { 74 | return v.PodName, nil 75 | } 76 | 77 | err := r.UpdateCache() 78 | if err != nil { 79 | return "", fmt.Errorf("failed to update cache: %w", err) 80 | } 81 | 82 | v, ok = r.containerToPodInfo.Get(sha) 83 | if !ok { 84 | return "", fmt.Errorf("sha %s not found in cache", sha) 85 | } 86 | 87 | return v.PodName, nil 88 | } 89 | 90 | // UpdateCache updates the cache with the latest pod and container information. 91 | func (r *ShaResolver) UpdateCache() error { 92 | ctx, cancel := context.WithTimeout(context.Background(), shaResolverTimeout) 93 | defer cancel() 94 | 95 | pods, err := getPods(ctx, r.client) 96 | if err != nil { 97 | return fmt.Errorf("failed to list pods: %w", err) 98 | } 99 | 100 | currentPods := make(map[string]*runtimeapi.PodSandbox) 101 | for _, pod := range pods { 102 | currentPods[pod.Id] = pod 103 | } 104 | 105 | r.detectExpiredPods(currentPods) 106 | 107 | r.knownPodsMutex.Lock() 108 | r.knownPods = currentPods 109 | r.knownPodsMutex.Unlock() 110 | 111 | containers, err := getContainers(ctx, r.client) 112 | if err != nil { 113 | return fmt.Errorf("failed to list containers: %w", err) 114 | } 115 | 116 | for _, container := range containers { 117 | containerID := container.GetId() 118 | podID := container.GetPodSandboxId() 119 | 120 | pod, ok := currentPods[podID] 121 | if !ok { 122 | r.logger.Warn( 123 | "container has no associated pod", 124 | "container_id", containerID, 125 | "pod_id", podID, 126 | ) 127 | continue 128 | } 129 | 130 | r.containerToPodInfo.Put( 131 | ContainerSha(containerID), 132 | &ContainerInfo{ 133 | PodID: podID, 134 | PodName: pod.GetMetadata().GetName(), 135 | }, 136 | ) 137 | } 138 | return nil 139 | } 140 | 141 | // detectExpiredPods detects pods that are no longer running and sends them to the expired pod channel. 142 | func (r *ShaResolver) detectExpiredPods( 143 | currentPods map[string]*runtimeapi.PodSandbox, 144 | ) { 145 | r.knownPodsMutex.Lock() 146 | defer r.knownPodsMutex.Unlock() 147 | 148 | for podID, pod := range r.knownPods { 149 | if _, exists := currentPods[podID]; !exists { 150 | r.logger.Info( 151 | "Pod expired", 152 | "pod_id", 153 | podID, 154 | "pod_name", 155 | pod.GetMetadata().GetName(), 156 | ) 157 | 158 | select { 159 | case r.ExpiredPodChan <- podID: 160 | default: 161 | r.logger.Warn("Expired pod channel is full", "pod_id", podID) 162 | } 163 | 164 | r.removePodFromCache(podID) 165 | } 166 | } 167 | } 168 | 169 | // removePodFromCache removes all containers associated with a given pod ID from the cache. 170 | func (r *ShaResolver) removePodFromCache(podID string) { 171 | keysToRemove := []ContainerSha{} 172 | 173 | r.containerToPodInfo.ForEach( 174 | func(containerID ContainerSha, info *ContainerInfo) bool { 175 | if info.PodID == podID { 176 | keysToRemove = append(keysToRemove, containerID) 177 | } 178 | return true 179 | }, 180 | ) 181 | 182 | for _, key := range keysToRemove { 183 | r.containerToPodInfo.Remove(key) 184 | } 185 | } 186 | 187 | // Close closes the ShaResolver instance. 188 | func (r *ShaResolver) Close() { 189 | r.conn.Close() 190 | } 191 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. 8 | 9 | ## Our Standards 10 | 11 | Examples of behavior that contributes to a positive environment for our community include: 12 | 13 | * Demonstrating empathy and kindness toward other people 14 | * Being respectful of differing opinions, viewpoints, and experiences 15 | * Giving and gracefully accepting constructive feedback 16 | * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience 17 | * Focusing on what is best not just for us as individuals, but for the overall community 18 | 19 | Examples of unacceptable behavior include: 20 | 21 | * The use of sexualized language or imagery, and sexual attention or advances of any kind 22 | * Trolling, insulting or derogatory comments, and personal or political attacks 23 | * Public or private harassment 24 | * Publishing others’ private information, such as a physical or email address, without their explicit permission 25 | * Other conduct which could reasonably be considered inappropriate in a professional setting 26 | 27 | ## Enforcement Responsibilities 28 | 29 | Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. 32 | 33 | ## Scope 34 | 35 | This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. 36 | 37 | ## Enforcement 38 | 39 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at pro@nullswan.io. All complaints will be reviewed and investigated promptly and fairly. 40 | 41 | All community leaders are obligated to respect the privacy and security of the reporter of any incident. 42 | 43 | ## Enforcement Guidelines 44 | 45 | Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: 46 | 47 | ### 1. Correction 48 | 49 | **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. 50 | 51 | **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. 52 | 53 | ### 2. Warning 54 | 55 | **Community Impact**: A violation through a single incident or series of actions. 56 | 57 | **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. 58 | 59 | ### 3. Temporary Ban 60 | 61 | **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. 62 | 63 | **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. 64 | 65 | ### 4. Permanent Ban 66 | 67 | **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. 68 | 69 | **Consequence**: A permanent ban from any sort of public interaction within the community. 70 | 71 | ## Attribution 72 | 73 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 74 | 75 | Community Impact Guidelines were inspired by [Mozilla’s code of conduct enforcement ladder](https://github.com/mozilla/diversity). 76 | 77 | [homepage]: https://www.contributor-covenant.org 78 | 79 | For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. -------------------------------------------------------------------------------- /pkg/network/converter_test.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "net" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestIntToIP(t *testing.T) { 10 | t.Parallel() 11 | tests := []struct { 12 | name string 13 | input uint32 14 | expected net.IP 15 | }{ 16 | { 17 | name: "Localhost", 18 | input: 0x7f000001, 19 | expected: net.IPv4(127, 0, 0, 1), 20 | }, 21 | { 22 | name: "Broadcast", 23 | input: 0xffffffff, 24 | expected: net.IPv4(255, 255, 255, 255), 25 | }, 26 | { 27 | name: "Zero", 28 | input: 0x00000000, 29 | expected: net.IPv4(0, 0, 0, 0), 30 | }, 31 | { 32 | name: "PrivateNetwork192", 33 | input: 0xc0a80001, 34 | expected: net.IPv4(192, 168, 0, 1), 35 | }, 36 | { 37 | name: "PrivateNetwork10", 38 | input: 0x0a000001, 39 | expected: net.IPv4(10, 0, 0, 1), 40 | }, 41 | { 42 | name: "PrivateNetwork172", 43 | input: 0xac100001, 44 | expected: net.IPv4(172, 16, 0, 1), 45 | }, 46 | { 47 | name: "Multicast", 48 | input: 0xe00000fb, 49 | expected: net.IPv4(224, 0, 0, 251), 50 | }, 51 | { 52 | name: "GoogleDNS", 53 | input: 0x08080808, 54 | expected: net.IPv4(8, 8, 8, 8), 55 | }, 56 | { 57 | name: "CloudflareDNS", 58 | input: 0x01010101, 59 | expected: net.IPv4(1, 1, 1, 1), 60 | }, 61 | { 62 | name: "RandomIP1", 63 | input: 0x12345678, 64 | expected: net.IPv4(18, 52, 86, 120), 65 | }, 66 | { 67 | name: "RandomIP2", 68 | input: 0x87654321, 69 | expected: net.IPv4(135, 101, 67, 33), 70 | }, 71 | { 72 | name: "RandomIP3", 73 | input: 0xaabbccdd, 74 | expected: net.IPv4(170, 187, 204, 221), 75 | }, 76 | { 77 | name: "MaxValue", 78 | input: 0xffffffff, 79 | expected: net.IPv4(255, 255, 255, 255), 80 | }, 81 | { 82 | name: "MinValue", 83 | input: 0x00000000, 84 | expected: net.IPv4(0, 0, 0, 0), 85 | }, 86 | } 87 | 88 | for _, test := range tests { 89 | test := test // capture range variable 90 | t.Run(test.name, func(t *testing.T) { 91 | t.Parallel() 92 | result := IntToIP(test.input) 93 | if !result.Equal(test.expected) { 94 | t.Errorf( 95 | "IntToIP(%#x) = %s; want %s", 96 | test.input, 97 | result, 98 | test.expected, 99 | ) 100 | } 101 | }) 102 | } 103 | } 104 | 105 | func TestNtohs(t *testing.T) { 106 | t.Parallel() 107 | tests := []struct { 108 | name string 109 | input uint16 110 | expected uint16 111 | }{ 112 | { 113 | name: "Zero", 114 | input: 0x0000, 115 | expected: 0x0000, 116 | }, 117 | { 118 | name: "MaxValue", 119 | input: 0xffff, 120 | expected: 0xffff, 121 | }, 122 | { 123 | name: "Port80", 124 | input: 0x5000, 125 | expected: 0x0050, 126 | }, 127 | { 128 | name: "Port443", 129 | input: 0xbb01, 130 | expected: 0x01bb, 131 | }, 132 | { 133 | name: "Port22", 134 | input: 0x1600, 135 | expected: 0x0016, 136 | }, 137 | { 138 | name: "RandomValue1", 139 | input: 0x3412, 140 | expected: 0x1234, 141 | }, 142 | { 143 | name: "RandomValue2", 144 | input: 0x7856, 145 | expected: 0x5678, 146 | }, 147 | { 148 | name: "RandomValue3", 149 | input: 0xa1b2, 150 | expected: 0xb2a1, 151 | }, 152 | { 153 | name: "HighByteZero", 154 | input: 0x00ff, 155 | expected: 0xff00, 156 | }, 157 | { 158 | name: "LowByteZero", 159 | input: 0xff00, 160 | expected: 0x00ff, 161 | }, 162 | { 163 | name: "AlternatingBits", 164 | input: 0xaa55, 165 | expected: 0x55aa, 166 | }, 167 | { 168 | name: "Palindrome", 169 | input: 0x1a1a, 170 | expected: 0x1a1a, 171 | }, 172 | } 173 | 174 | for _, test := range tests { 175 | test := test // capture range variable 176 | t.Run(test.name, func(t *testing.T) { 177 | t.Parallel() 178 | result := Ntohs(test.input) 179 | if result != test.expected { 180 | t.Errorf( 181 | "Ntohs(%#x) = %#x; want %#x", 182 | test.input, 183 | result, 184 | test.expected, 185 | ) 186 | } 187 | }) 188 | } 189 | } 190 | 191 | func TestNtohl(t *testing.T) { 192 | t.Parallel() 193 | tests := []struct { 194 | name string 195 | input uint32 196 | expected uint32 197 | }{ 198 | { 199 | name: "Zero", 200 | input: 0x00000000, 201 | expected: 0x00000000, 202 | }, 203 | { 204 | name: "MaxValue", 205 | input: 0xffffffff, 206 | expected: 0xffffffff, 207 | }, 208 | { 209 | name: "Localhost", 210 | input: 0x0100007f, 211 | expected: 0x7f000001, 212 | }, 213 | { 214 | name: "GoogleDNS", 215 | input: 0x08080808, 216 | expected: 0x08080808, 217 | }, 218 | { 219 | name: "PrivateNetwork192", 220 | input: 0xC0A80001, 221 | expected: 0x0100A8C0, 222 | }, 223 | { 224 | name: "RandomValue1", 225 | input: 0x78563412, 226 | expected: 0x12345678, 227 | }, 228 | { 229 | name: "RandomValue2", 230 | input: 0x44332211, 231 | expected: 0x11223344, 232 | }, 233 | { 234 | name: "HighBytesZero", 235 | input: 0x0000ffff, 236 | expected: 0xffff0000, 237 | }, 238 | { 239 | name: "LowBytesZero", 240 | input: 0xffff0000, 241 | expected: 0x0000ffff, 242 | }, 243 | { 244 | name: "AlternatingBits", 245 | input: 0xaa55aa55, 246 | expected: 0x55aa55aa, 247 | }, 248 | { 249 | name: "Palindrome", 250 | input: 0x1a2b2b1a, 251 | expected: 0x1a2b2b1a, 252 | }, 253 | { 254 | name: "Multicast", 255 | input: 0xfb0000e0, 256 | expected: 0xe00000fb, 257 | }, 258 | { 259 | name: "EdgeCase1", 260 | input: 0x00000001, 261 | expected: 0x01000000, 262 | }, 263 | { 264 | name: "EdgeCase2", 265 | input: 0x80000000, 266 | expected: 0x00000080, 267 | }, 268 | } 269 | 270 | for _, test := range tests { 271 | test := test // capture range variable 272 | t.Run(test.name, func(t *testing.T) { 273 | t.Parallel() 274 | result := Ntohl(test.input) 275 | if result != test.expected { 276 | t.Errorf( 277 | "Ntohl(%#x) = %#x; want %#x", 278 | test.input, 279 | result, 280 | test.expected, 281 | ) 282 | } 283 | }) 284 | } 285 | } 286 | 287 | func TestIntToSubnet(t *testing.T) { 288 | t.Parallel() 289 | 290 | tests := []struct { 291 | ip uint32 292 | mask uint32 293 | output *net.IPNet 294 | }{ 295 | { 296 | ip: 0xC0A80101, // 192.168.1.1 297 | mask: 0xFFFFFF00, // 255.255.255.0 298 | output: &net.IPNet{ 299 | IP: net.IPv4(192, 168, 1, 0), 300 | Mask: net.IPv4Mask(255, 255, 255, 0), 301 | }, 302 | }, 303 | { 304 | ip: 0x0A000001, // 10.0.0.1 305 | mask: 0xFF000000, // 255.0.0.0 306 | output: &net.IPNet{ 307 | IP: net.IPv4(10, 0, 0, 0), 308 | Mask: net.IPv4Mask(255, 0, 0, 0), 309 | }, 310 | }, 311 | { 312 | ip: 0xC0A80101, // 192.168.1.1 313 | mask: 0xFFFF0000, // 255.255.0.0 314 | output: &net.IPNet{ 315 | IP: net.IPv4(192, 168, 0, 0), // Host portion is zeroed out 316 | Mask: net.IPv4Mask(255, 255, 0, 0), 317 | }, 318 | }, 319 | { 320 | ip: 0xC0A80101, // 192.168.1.1 321 | mask: 0xFFFFFFFF, // 255.255.255.255 322 | output: &net.IPNet{ 323 | IP: net.IPv4(192, 168, 1, 1), // No part is zeroed out 324 | Mask: net.IPv4Mask(255, 255, 255, 255), 325 | }, 326 | }, 327 | { 328 | ip: 0x0A0A0A0A, // 10.10.10.10 329 | mask: 0xFFFFF000, // 255.255.240.0 330 | output: &net.IPNet{ 331 | IP: net.IPv4(10, 10, 0, 0), // Host portion is zeroed out 332 | Mask: net.IPv4Mask(255, 255, 240, 0), 333 | }, 334 | }, 335 | { 336 | ip: 0xAC100202, // 172.16.2.2 337 | mask: 0xFFFFFFF0, // 255.255.255.240 338 | output: &net.IPNet{ 339 | IP: net.IPv4( 340 | 172, 341 | 16, 342 | 2, 343 | 0, 344 | ), // Host portion is mostly zeroed out 345 | Mask: net.IPv4Mask(255, 255, 255, 240), 346 | }, 347 | }, 348 | } 349 | 350 | for _, tt := range tests { 351 | result := IntToSubnet(tt.ip, tt.mask) 352 | if !reflect.DeepEqual(result, tt.output) { 353 | t.Errorf( 354 | "IntToSubnet(%v, %v) = %v; want %v", 355 | tt.ip, 356 | tt.mask, 357 | result, 358 | tt.output, 359 | ) 360 | } 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 2 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 3 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 4 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 5 | github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= 6 | github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= 7 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 8 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 10 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 11 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 12 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 13 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 14 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 15 | github.com/grafana/pyroscope-go v1.2.0 h1:aILLKjTj8CS8f/24OPMGPewQSYlhmdQMBmol1d3KGj8= 16 | github.com/grafana/pyroscope-go v1.2.0/go.mod h1:2GHr28Nr05bg2pElS+dDsc98f3JTUh2f6Fz1hWXrqwk= 17 | github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg= 18 | github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= 19 | github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= 20 | github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= 21 | github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= 22 | github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= 23 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 24 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 25 | github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= 26 | github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 27 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 28 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 29 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 30 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 31 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 32 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 33 | github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= 34 | github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= 35 | github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= 36 | github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= 37 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 38 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 39 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 40 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 41 | github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= 42 | github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 43 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= 44 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 45 | github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= 46 | github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= 47 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 48 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 49 | github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= 50 | github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 51 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 52 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 53 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 54 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 55 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 56 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 57 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 58 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 59 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 60 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= 61 | golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 62 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 63 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 64 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 65 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 66 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 67 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 68 | golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= 69 | golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 70 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 71 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 72 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 73 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 74 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 75 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 76 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 77 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 78 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= 79 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 80 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 81 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 82 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 83 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 84 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 85 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 86 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 87 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 88 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 89 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 90 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 91 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 92 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= 93 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= 94 | google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= 95 | google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= 96 | google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 97 | google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 98 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 99 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 100 | k8s.io/cri-api v0.31.1 h1:x0aI8yTI7Ho4c8tpuig8NwI/MRe+VhjiYyyebC2xphQ= 101 | k8s.io/cri-api v0.31.1/go.mod h1:Po3TMAYH/+KrZabi7QiwQI4a692oZcUOUThd/rqwxrI= 102 | -------------------------------------------------------------------------------- /pkg/lru/lru_test.go: -------------------------------------------------------------------------------- 1 | package lru 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | func TestLRUCache(t *testing.T) { 9 | t.Parallel() 10 | 11 | cache := New[int, int](2) // Create LRUCache with capacity of 2 12 | 13 | cache.Put(1, 1) 14 | cache.Put(2, 2) 15 | 16 | if value, found := cache.Get(1); !found || value != 1 { 17 | t.Errorf( 18 | "Expected key 1 to have value 1, but got value %v found %v", 19 | value, 20 | found, 21 | ) 22 | } 23 | 24 | cache.Put(3, 3) 25 | 26 | if _, found := cache.Get(2); found { 27 | t.Errorf("Expected key 2 to be evicted, but it was found") 28 | } 29 | 30 | cache.Put(4, 4) 31 | 32 | if _, found := cache.Get(1); found { 33 | t.Errorf("Expected key 1 to be evicted, but it was found") 34 | } 35 | 36 | if value, found := cache.Get(3); !found || value != 3 { 37 | t.Errorf( 38 | "Expected key 3 to have value 3, but got value %v found %v", 39 | value, 40 | found, 41 | ) 42 | } 43 | 44 | if value, found := cache.Get(4); !found || value != 4 { 45 | t.Errorf( 46 | "Expected key 4 to have value 4, but got value %v found %v", 47 | value, 48 | found, 49 | ) 50 | } 51 | } 52 | 53 | func TestLRUCacheOverwrite(t *testing.T) { 54 | t.Parallel() 55 | 56 | cache := New[int, int](2) 57 | cache.Put(1, 1) 58 | cache.Put(1, 10) 59 | if value, found := cache.Get(1); !found || value != 10 { 60 | t.Errorf( 61 | "Expected key 1 to have value 10, but got value %v found %v", 62 | value, 63 | found, 64 | ) 65 | } 66 | } 67 | 68 | func TestLRUCacheEvictionOrder(t *testing.T) { 69 | t.Parallel() 70 | 71 | cache := New[int, int](3) 72 | cache.Put(1, 1) 73 | cache.Put(2, 2) 74 | cache.Put(3, 3) 75 | cache.Get(1) // Make key 1 the most recently used 76 | cache.Put(4, 4) 77 | if _, found := cache.Get(2); found { 78 | t.Errorf("Expected key 2 to be evicted, but it was found") 79 | } 80 | } 81 | 82 | func TestLRUCacheBoundaryUsage(t *testing.T) { 83 | t.Parallel() 84 | 85 | cache := New[int, int](1) 86 | cache.Put(1, 1) 87 | if value, found := cache.Get(1); !found || value != 1 { 88 | t.Errorf( 89 | "Expected key 1 to have value 1, but got value %v found %v", 90 | value, 91 | found, 92 | ) 93 | } 94 | cache.Put(2, 2) 95 | if _, found := cache.Get(1); found { 96 | t.Errorf("Expected key 1 to be evicted, but it was found") 97 | } 98 | if value, found := cache.Get(2); !found || value != 2 { 99 | t.Errorf( 100 | "Expected key 2 to have value 2, but got value %v found %v", 101 | value, 102 | found, 103 | ) 104 | } 105 | } 106 | 107 | func TestLRUCacheZeroCapacity(t *testing.T) { 108 | t.Parallel() 109 | 110 | cache := New[int, int](0) 111 | cache.Put(1, 1) 112 | if value, found := cache.Get(1); !found || value != 1 { 113 | t.Errorf( 114 | "Expected key 1 to be added with value 1, but got value %v found %v", 115 | value, 116 | found, 117 | ) 118 | } 119 | cache.Put(2, 2) 120 | if value, found := cache.Get(2); !found || value != 2 { 121 | t.Errorf( 122 | "Expected key 2 to be added with value 2, but got value %v found %v", 123 | value, 124 | found, 125 | ) 126 | } 127 | if _, found := cache.Get(1); found { 128 | t.Errorf( 129 | "Expected key 1 to be evicted after adding key 2, but it was found", 130 | ) 131 | } 132 | } 133 | 134 | func TestLRUCacheConcurrency(t *testing.T) { 135 | t.Parallel() 136 | 137 | cache := New[int, int](100) // Create LRUCache with capacity of 100 138 | wg := sync.WaitGroup{} 139 | 140 | // Function to perform a sequence of puts and gets 141 | concurrentAccess := func(start, end int) { 142 | defer wg.Done() 143 | for i := start; i < end; i++ { 144 | cache.Put(i, i) 145 | if value, found := cache.Get(i); !found || value != i { 146 | t.Errorf( 147 | "Expected key %v to have value %v, but got value %v found %v", 148 | i, 149 | i, 150 | value, 151 | found, 152 | ) 153 | } 154 | } 155 | } 156 | 157 | // Perform concurrent access to the cache 158 | threads := 10 159 | for i := 0; i < threads; i++ { 160 | wg.Add(1) 161 | go concurrentAccess(i*10, (i+1)*10) 162 | } 163 | 164 | wg.Wait() 165 | 166 | // Validate the cache contents 167 | for i := 0; i < 50; i++ { 168 | if value, found := cache.Get(i); !found || value != i { 169 | t.Errorf( 170 | "Expected key %v to have value %v, but got value %v found %v", 171 | i, 172 | i, 173 | value, 174 | found, 175 | ) 176 | } 177 | } 178 | } 179 | 180 | func TestLRUCacheEvictionPattern(t *testing.T) { 181 | t.Parallel() 182 | 183 | cache := New[int, int](3) 184 | cache.Put(1, 1) 185 | cache.Put(2, 2) 186 | cache.Put(3, 3) 187 | cache.Get(2) 188 | cache.Get(3) 189 | cache.Put(4, 4) 190 | if _, found := cache.Get(1); found { 191 | t.Errorf("Expected key 1 to be evicted, but it was found") 192 | } 193 | if value, found := cache.Get(2); !found || value != 2 { 194 | t.Errorf( 195 | "Expected key 2 to have value 2, but got value %v found %v", 196 | value, 197 | found, 198 | ) 199 | } 200 | if value, found := cache.Get(3); !found || value != 3 { 201 | t.Errorf( 202 | "Expected key 3 to have value 3, but got value %v found %v", 203 | value, 204 | found, 205 | ) 206 | } 207 | if value, found := cache.Get(4); !found || value != 4 { 208 | t.Errorf( 209 | "Expected key 4 to have value 4, but got value %v found %v", 210 | value, 211 | found, 212 | ) 213 | } 214 | } 215 | 216 | func TestLRUCacheMultipleEvictions(t *testing.T) { 217 | t.Parallel() 218 | 219 | cache := New[int, int](2) 220 | cache.Put(1, 1) 221 | cache.Put(2, 2) 222 | cache.Put(3, 3) // Causes eviction of key 1 223 | cache.Put(4, 4) // Causes eviction of key 2 224 | if _, found := cache.Get(1); found { 225 | t.Errorf("Expected key 1 to be evicted, but it was found") 226 | } 227 | if _, found := cache.Get(2); found { 228 | t.Errorf("Expected key 2 to be evicted, but it was found") 229 | } 230 | if value, found := cache.Get(3); !found || value != 3 { 231 | t.Errorf( 232 | "Expected key 3 to have value 3, but got value %v found %v", 233 | value, 234 | found, 235 | ) 236 | } 237 | if value, found := cache.Get(4); !found || value != 4 { 238 | t.Errorf( 239 | "Expected key 4 to have value 4, but got value %v found %v", 240 | value, 241 | found, 242 | ) 243 | } 244 | } 245 | 246 | func TestLRUCacheRemove(t *testing.T) { 247 | t.Parallel() 248 | 249 | cache := New[int, int](2) 250 | 251 | cache.Put(1, 100) 252 | cache.Put(2, 200) 253 | 254 | cache.Remove(1) 255 | 256 | if _, found := cache.Get(1); found { 257 | t.Errorf("Expected key 1 to be removed, but it was found") 258 | } 259 | 260 | if value, found := cache.Get(2); !found || value != 200 { 261 | t.Errorf( 262 | "Expected key 2 to have value 200, but got value %v found %v", 263 | value, 264 | found, 265 | ) 266 | } 267 | 268 | cache.Put(3, 300) 269 | 270 | if value, found := cache.Get(3); !found || value != 300 { 271 | t.Errorf( 272 | "Expected key 3 to have value 300, but got value %v found %v", 273 | value, 274 | found, 275 | ) 276 | } 277 | } 278 | 279 | func TestLRUCacheForEach(t *testing.T) { 280 | t.Parallel() 281 | 282 | cache := New[int, int](3) 283 | cache.Put(1, 100) 284 | cache.Put(2, 200) 285 | cache.Put(3, 300) 286 | 287 | // Expected order: 3 (MRU), 2, 1 (LRU) 288 | expectedKeys := []int{3, 2, 1} 289 | index := 0 290 | 291 | cache.ForEach(func(key int, _ int) bool { 292 | if index >= len(expectedKeys) { 293 | t.Errorf("Iterated over more elements than expected") 294 | return false 295 | } 296 | expectedKey := expectedKeys[index] 297 | if key != expectedKey { 298 | t.Errorf( 299 | "Expected key %v at index %v, but got key %v", 300 | expectedKey, 301 | index, 302 | key, 303 | ) 304 | } 305 | index++ 306 | return true 307 | }) 308 | 309 | if index != len(expectedKeys) { 310 | t.Errorf( 311 | "Expected to iterate over %v elements, but iterated over %v", 312 | len(expectedKeys), 313 | index, 314 | ) 315 | } 316 | } 317 | 318 | func TestLRUCacheForEachEarlyExit(t *testing.T) { 319 | t.Parallel() 320 | 321 | cache := New[int, int](1) 322 | cache.Put(1, 100) 323 | cache.Put(2, 200) 324 | cache.Put(3, 300) 325 | 326 | // Expected to stop after first element 327 | index := 0 328 | 329 | cache.ForEach(func(_ int, _ int) bool { 330 | index++ 331 | return false 332 | }) 333 | 334 | if index != 1 { 335 | t.Errorf( 336 | "Expected to iterate over 1 element, but iterated over %v", 337 | index, 338 | ) 339 | } 340 | } 341 | 342 | func TestLRUCacheForEachEmptyCache(t *testing.T) { 343 | t.Parallel() 344 | 345 | cache := New[int, int](1) 346 | 347 | called := false 348 | 349 | cache.ForEach(func(_ int, _ int) bool { 350 | called = true 351 | return true 352 | }) 353 | 354 | if called { 355 | t.Errorf("Expected ForEach not to call the function on an empty cache") 356 | } 357 | } 358 | 359 | func TestLRUCacheForEachAfterOperations(t *testing.T) { 360 | t.Parallel() 361 | 362 | cache := New[int, int](3) 363 | cache.Put(1, 100) // [1] 364 | cache.Put(2, 200) // [2, 1] 365 | cache.Get(1) // Make key 1 MRU [1, 2] 366 | cache.Put(3, 300) // [3, 1, 2] 367 | cache.Get(2) // Now key 2 is MRU [2, 3, 1] 368 | cache.Put(4, 400) // Evicts key 3 (LRU) [4, 2, 3] 369 | 370 | // Expected order: 2 (MRU), 1, 4 371 | expectedKeys := []int{4, 2, 3} 372 | index := 0 373 | 374 | cache.ForEach(func(key int, _ int) bool { 375 | if index >= len(expectedKeys) { 376 | t.Errorf("Iterated over more elements than expected") 377 | return false 378 | } 379 | expectedKey := expectedKeys[index] 380 | if key != expectedKey { 381 | t.Errorf( 382 | "Expected key %v at index %v, but got key %v", 383 | expectedKey, 384 | index, 385 | key, 386 | ) 387 | } 388 | index++ 389 | return true 390 | }) 391 | 392 | if index != len(expectedKeys) { 393 | t.Errorf( 394 | "Expected to iterate over %v elements, but iterated over %v", 395 | len(expectedKeys), 396 | index, 397 | ) 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bpfsnitch 2 | 3 | [![License: GPL](https://img.shields.io/badge/License-GPL-blue.svg)](LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/nullswan/bpfsnitch)](https://goreportcard.com/report/github.com/nullswan/bpfsnitch) 4 | 5 | bpfsnitch is an open-source, real-time monitoring tool for Linux systems and Kubernetes clusters. Inspired by GlassWire, bpfsnitch leverages eBPF (extended Berkeley Packet Filter) technology to provide observability at the lowest level possible by tracking system calls and network activities. It is capable of monitoring every syscall and network event in real-time, offering valuable insights into what's happening inside your systems and containers. 6 | 7 | --- 8 | 9 | ## Table of Contents 10 | 11 | - [bpfsnitch](#bpfsnitch) 12 | - [Table of Contents](#table-of-contents) 13 | - [Features](#features) 14 | - [Prerequisites](#prerequisites) 15 | - [Installation](#installation) 16 | - [On Kubernetes Clusters](#on-kubernetes-clusters) 17 | - [Metrics](#metrics) 18 | - [Key Metrics](#key-metrics) 19 | - [Example Metrics Output](#example-metrics-output) 20 | - [Performance](#performance) 21 | - [Configuration (soon)](#configuration-soon) 22 | - [Customizing Syscall Monitoring](#customizing-syscall-monitoring) 23 | - [Predefined Syscalls](#predefined-syscalls) 24 | - [Educational Value](#educational-value) 25 | - [License](#license) 26 | - [Future Plans](#future-plans) 27 | - [Contact](#contact) 28 | - [Acknowledgments](#acknowledgments) 29 | - [Join the Community](#join-the-community) 30 | 31 | --- 32 | 33 | ## Features 34 | 35 | - **Real-Time Monitoring**: Track every syscall and network event as they happen. 36 | - **eBPF Powered**: Utilizes eBPF for efficient, low-overhead monitoring at the kernel level. 37 | - **Kubernetes Support**: Deployable as a DaemonSet to monitor your entire Kubernetes cluster. 38 | - **Customizable Syscall Monitoring**: Predefined list of critical syscalls with plans to provide a configurable syscall whitelist. 39 | - **Prometheus Integration**: Exposes metrics via a Prometheus scrape endpoint for easy integration with your monitoring stack. 40 | - **Pod Awareness**: Labels metrics with pod names for granular visibility. 41 | - **Open Source**: Released under the GPL license, encouraging community collaboration. 42 | 43 | --- 44 | 45 | ## Prerequisites 46 | 47 | - **Linux Kernel with eBPF Support**: bpfsnitch requires a Linux kernel version that supports eBPF (version 5.8 or higher recommended). 48 | - **eBPF Libraries**: Ensure that `libbpf` and related dependencies are installed. 49 | - **Prometheus**: For metrics scraping and monitoring. 50 | - **Container Runtime**: Supports Docker and Containerd Kubernetes environments. 51 | 52 | --- 53 | 54 | ## Installation 55 | 56 | ### On Kubernetes Clusters 57 | 58 | Deploy bpfsnitch as a DaemonSet to monitor all nodes in your cluster. 59 | 60 | 1. Apply the DaemonSet Manifest 61 | 62 | ```bash 63 | curl -s https://raw.githubusercontent.com/nullswan/bpfsnitch/main/deployments/daemonset.yaml | kubectl apply -f - 64 | ``` 65 | 66 | ## Metrics 67 | 68 | bpfsnitch exposes a variety of Prometheus metrics, providing insights into syscalls and network activities. 69 | 70 | ### Key Metrics 71 | 72 | - Syscall Counters: Counts of specific syscalls made by processes or pods. 73 | - Network Bytes Counters: Total bytes sent and received, labeled by pod and remote subnets. 74 | - Network Packets Counters: Total packets sent and received. 75 | - DNS Query Counters: Number of DNS queries made by pods. 76 | 77 | ### Example Metrics Output 78 | 79 | ```perl 80 | # HELP bpfsnitch_dns_query_counter Number of DNS queries 81 | # TYPE bpfsnitch_dns_query_counter counter 82 | bpfsnitch_dns_query_counter{container="kube-proxy-cwn8r"} 23 83 | 84 | # HELP bpfsnitch_network_received_bytes_counter Number of bytes received 85 | # TYPE bpfsnitch_network_received_bytes_counter counter 86 | bpfsnitch_network_received_bytes_counter{pod="nginx-7b9f54988c-2tpbd",remote_subnet="0.0.0.0/24"} 1334512 87 | 88 | # HELP bpfsnitch_network_received_packets_counter Number of packets received 89 | # TYPE bpfsnitch_network_received_packets_counter counter 90 | bpfsnitch_network_received_packets_counter{pod="nginx-7b9f54988c-2tpbd",remote_subnet="0.0.0.0/24"} 623 91 | 92 | # HELP bpfsnitch_network_sent_bytes_counter Number of bytes sent 93 | # TYPE bpfsnitch_network_sent_bytes_counter counter 94 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.3.0/24"} 1293500 95 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.97.0/24"} 80 96 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.111.0/24"} 310 97 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.108.0/24"} 65 98 | 99 | # HELP bpfsnitch_network_sent_packets_counter Number of packets sent 100 | # TYPE bpfsnitch_network_sent_packets_counter counter 101 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.3.0/24"} 1529 102 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.97.0/24"} 1 103 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.111.0/24"} 3 104 | bpfsnitch_network_sent_packets_counter{pod="kube-proxy-cwn8r",remote_subnet="1.2.108.0/24"} 1 105 | 106 | # HELP bpfsnitch_syscall_counter Number of syscalls 107 | # TYPE bpfsnitch_syscall_counter counter 108 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="arch_prctl"} 520 109 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="bind"} 2713 110 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="clone"} 818 111 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="connect"} 264 112 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="getrandom"} 578 113 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="getsockname"} 2845 114 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="read"} 16424 115 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="recvmsg"} 56939 116 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="sendmsg"} 443 117 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="sendto"} 32007 118 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="setsockopt"} 819 119 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="socket"} 2845 120 | bpfsnitch_syscall_counter{pod="kube-proxy-cwn8r",syscall="wait4"} 818 121 | ``` 122 | 123 | ## Performance 124 | 125 | Starting from v0.1.0, bpfsnitch is built to be lightweight and efficient using eBPF technology. It monitors syscalls and network events at the kernel level, providing real-time insights with minimal system impact. 126 | 127 | In production, bpfsnitch typically uses an average of 5ms of CPU per 60-second scrape and maintains a memory footprint of up to `250MB`. It is statically bound to a maximum of `100ms` CPU usage, ensuring consistent performance regardless of system configuration or workload. See the [DaemonSet resources](https://github.com/search?q=repo%3Anullswan/bpfsnitch%20resources&type=code) 128 | 129 | To monitor bpfsnitch's performance in real-time, start it with the -pprof flag to expose a pprof server. Access live profiling data at the /debug/pprof route to analyze CPU and memory usage and optimize performance as needed. 130 | 131 | We are committed to providing detailed performance benchmarks and optimization tips in future releases to help you maximize bpfsnitch's benefits. 132 | 133 | ## Configuration (soon) 134 | 135 | ### Customizing Syscall Monitoring 136 | 137 | bpfsnitch comes with a predefined list of syscalls to monitor, focusing on critical operations that could affect system security or stability. We plan to provide a configurable syscall whitelist in future releases, allowing you to tailor monitoring to your specific needs. 138 | 139 | #### Predefined Syscalls 140 | 141 | ```go 142 | var WhitelistedSyscalls = []int{ 143 | SyscallToId["clone"], 144 | SyscallToId["execve"], 145 | SyscallToId["mknodat"], 146 | SyscallToId["chroot"], 147 | SyscallToId["mount"], 148 | SyscallToId["umount2"], 149 | SyscallToId["pivot_root"], 150 | SyscallToId["setuid"], 151 | SyscallToId["setgid"], 152 | ... 153 | ``` 154 | 155 | ## Educational Value 156 | 157 | bpfsnitch is not only a powerful monitoring tool but also an excellent educational resource. It provides insights into: 158 | - eBPF Programming: Learn how eBPF programs are written and attached to kernel functions. 159 | - System Call Mechanics: Understand how syscalls work and how they impact system behavior. 160 | - Kernel-Level Monitoring: Gain knowledge about low-level monitoring techniques in Linux. 161 | - Observability Practices: Explore how to collect and expose metrics for modern monitoring systems like Prometheus. 162 | 163 | ## License 164 | 165 | bpfsnitch is released under the GNU General Public License (GPL). 166 | 167 | ## Future Plans 168 | 169 | - Configurable Syscall Whitelist: Allow users to define which syscalls to monitor. 170 | - User Interface: Develop a web-based UI for easier visualization and management. 171 | - Performance Optimizations: Enhance the efficiency of data collection and processing. 172 | - Additional Metrics: Include more granular metrics, such as latency measurements and error counts. 173 | - Extended Container Support: Improve compatibility with various container runtimes and orchestration platforms. 174 | 175 | ## Contact 176 | 177 | - Contributor: [@nullswan](https://github.com/nullswan) 178 | - Reviewers: [@gmarcha](https://github.com/gmarcha), [@naofel1](https://github.com/naofel1) 179 | - GitHub Issues: [https://github.com/nullswan/bpfsnitch/issues](https://github.com/nullswan/bpfsnitch/issues) 180 | 181 | ## Acknowledgments 182 | 183 | - eBPF Community: For providing extensive resources and support for eBPF development. 184 | - Prometheus: For their powerful monitoring and alerting toolkit. 185 | - Open Source Community: Thanks to all who have contributed to the open-source ecosystem, making projects like bpfsnitch possible. 186 | 187 | ## Join the Community 188 | 189 | If you find bpfsnitch valuable, please give us a ⭐ star on GitHub and share it with others who might be interested. Your support helps us improve and grow the project! 190 | 191 | Feel free to reach out if you have any questions or need assistance getting started with bpfsnitch. We look forward to your feedback! 192 | -------------------------------------------------------------------------------- /internal/bpf/arch/arm64.go: -------------------------------------------------------------------------------- 1 | // AUTOGENERATED FILE 2 | 3 | //go:build arm64 4 | // +build arm64 5 | 6 | package bpfarch 7 | 8 | const BpfProgramElf = bpfProgramName + "_arm64.o" 9 | 10 | var SyscallToId = map[string]int{ 11 | "io_setup": 0, 12 | "io_destroy": 1, 13 | "io_submit": 2, 14 | "io_cancel": 3, 15 | "io_getevents": 4, 16 | "setxattr": 5, 17 | "lsetxattr": 6, 18 | "fsetxattr": 7, 19 | "getxattr": 8, 20 | "lgetxattr": 9, 21 | "fgetxattr": 10, 22 | "listxattr": 11, 23 | "llistxattr": 12, 24 | "flistxattr": 13, 25 | "removexattr": 14, 26 | "lremovexattr": 15, 27 | "fremovexattr": 16, 28 | "getcwd": 17, 29 | "lookup_dcookie": 18, 30 | "eventfd2": 19, 31 | "epoll_create1": 20, 32 | "epoll_ctl": 21, 33 | "epoll_pwait": 22, 34 | "dup": 23, 35 | "dup3": 24, 36 | "fcntl": 25, 37 | "inotify_init1": 26, 38 | "inotify_add_watch": 27, 39 | "inotify_rm_watch": 28, 40 | "ioctl": 29, 41 | "ioprio_set": 30, 42 | "ioprio_get": 31, 43 | "flock": 32, 44 | "mknodat": 33, 45 | "mkdirat": 34, 46 | "unlinkat": 35, 47 | "symlinkat": 36, 48 | "linkat": 37, 49 | "renameat": 38, 50 | "umount2": 39, 51 | "mount": 40, 52 | "pivot_root": 41, 53 | "nfsservctl": 42, 54 | "statfs": 43, 55 | "fstatfs": 44, 56 | "truncate": 45, 57 | "ftruncate": 46, 58 | "fallocate": 47, 59 | "faccessat": 48, 60 | "chdir": 49, 61 | "fchdir": 50, 62 | "chroot": 51, 63 | "fchmod": 52, 64 | "fchmodat": 53, 65 | "fchownat": 54, 66 | "fchown": 55, 67 | "openat": 56, 68 | "close": 57, 69 | "vhangup": 58, 70 | "pipe2": 59, 71 | "quotactl": 60, 72 | "getdents64": 61, 73 | "lseek": 62, 74 | "read": 63, 75 | "write": 64, 76 | "readv": 65, 77 | "writev": 66, 78 | "pread64": 67, 79 | "pwrite64": 68, 80 | "preadv": 69, 81 | "pwritev": 70, 82 | "sendfile": 71, 83 | "pselect6": 72, 84 | "ppoll": 73, 85 | "signalfd4": 74, 86 | "vmsplice": 75, 87 | "splice": 76, 88 | "tee": 77, 89 | "readlinkat": 78, 90 | "newfstatat": 79, 91 | "fstat": 80, 92 | "sync": 81, 93 | "fsync": 82, 94 | "fdatasync": 83, 95 | "sync_file_range": 84, 96 | "timerfd_create": 85, 97 | "timerfd_settime": 86, 98 | "timerfd_gettime": 87, 99 | "utimensat": 88, 100 | "acct": 89, 101 | "capget": 90, 102 | "capset": 91, 103 | "personality": 92, 104 | "exit": 93, 105 | "exit_group": 94, 106 | "waitid": 95, 107 | "set_tid_address": 96, 108 | "unshare": 97, 109 | "futex": 98, 110 | "set_robust_list": 99, 111 | "get_robust_list": 100, 112 | "nanosleep": 101, 113 | "getitimer": 102, 114 | "setitimer": 103, 115 | "kexec_load": 104, 116 | "init_module": 105, 117 | "delete_module": 106, 118 | "timer_create": 107, 119 | "timer_gettime": 108, 120 | "timer_getoverrun": 109, 121 | "timer_settime": 110, 122 | "timer_delete": 111, 123 | "clock_settime": 112, 124 | "clock_gettime": 113, 125 | "clock_getres": 114, 126 | "clock_nanosleep": 115, 127 | "syslog": 116, 128 | "ptrace": 117, 129 | "sched_setparam": 118, 130 | "sched_setscheduler": 119, 131 | "sched_getscheduler": 120, 132 | "sched_getparam": 121, 133 | "sched_setaffinity": 122, 134 | "sched_getaffinity": 123, 135 | "sched_yield": 124, 136 | "sched_get_priority_max": 125, 137 | "sched_get_priority_min": 126, 138 | "sched_rr_get_interval": 127, 139 | "restart_syscall": 128, 140 | "kill": 129, 141 | "tkill": 130, 142 | "tgkill": 131, 143 | "sigaltstack": 132, 144 | "rt_sigsuspend": 133, 145 | "rt_sigaction": 134, 146 | "rt_sigprocmask": 135, 147 | "rt_sigpending": 136, 148 | "rt_sigtimedwait": 137, 149 | "rt_sigqueueinfo": 138, 150 | "rt_sigreturn": 139, 151 | "setpriority": 140, 152 | "getpriority": 141, 153 | "reboot": 142, 154 | "setregid": 143, 155 | "setgid": 144, 156 | "setreuid": 145, 157 | "setuid": 146, 158 | "setresuid": 147, 159 | "getresuid": 148, 160 | "setresgid": 149, 161 | "getresgid": 150, 162 | "setfsuid": 151, 163 | "setfsgid": 152, 164 | "times": 153, 165 | "setpgid": 154, 166 | "getpgid": 155, 167 | "getsid": 156, 168 | "setsid": 157, 169 | "getgroups": 158, 170 | "setgroups": 159, 171 | "uname": 160, 172 | "sethostname": 161, 173 | "setdomainname": 162, 174 | "getrlimit": 163, 175 | "setrlimit": 164, 176 | "getrusage": 165, 177 | "umask": 166, 178 | "prctl": 167, 179 | "getcpu": 168, 180 | "gettimeofday": 169, 181 | "settimeofday": 170, 182 | "adjtimex": 171, 183 | "getpid": 172, 184 | "getppid": 173, 185 | "getuid": 174, 186 | "geteuid": 175, 187 | "getgid": 176, 188 | "getegid": 177, 189 | "gettid": 178, 190 | "sysinfo": 179, 191 | "mq_open": 180, 192 | "mq_unlink": 181, 193 | "mq_timedsend": 182, 194 | "mq_timedreceive": 183, 195 | "mq_notify": 184, 196 | "mq_getsetattr": 185, 197 | "msgget": 186, 198 | "msgctl": 187, 199 | "msgrcv": 188, 200 | "msgsnd": 189, 201 | "semget": 190, 202 | "semctl": 191, 203 | "semtimedop": 192, 204 | "semop": 193, 205 | "shmget": 194, 206 | "shmctl": 195, 207 | "shmat": 196, 208 | "shmdt": 197, 209 | "socket": 198, 210 | "socketpair": 199, 211 | "bind": 200, 212 | "listen": 201, 213 | "accept": 202, 214 | "connect": 203, 215 | "getsockname": 204, 216 | "getpeername": 205, 217 | "sendto": 206, 218 | "recvfrom": 207, 219 | "setsockopt": 208, 220 | "getsockopt": 209, 221 | "shutdown": 210, 222 | "sendmsg": 211, 223 | "recvmsg": 212, 224 | "readahead": 213, 225 | "brk": 214, 226 | "munmap": 215, 227 | "mremap": 216, 228 | "add_key": 217, 229 | "request_key": 218, 230 | "keyctl": 219, 231 | "clone": 220, 232 | "execve": 221, 233 | "mmap": 222, 234 | "fadvise64": 223, 235 | "swapon": 224, 236 | "swapoff": 225, 237 | "mprotect": 226, 238 | "msync": 227, 239 | "mlock": 228, 240 | "munlock": 229, 241 | "mlockall": 230, 242 | "munlockall": 231, 243 | "mincore": 232, 244 | "madvise": 233, 245 | "remap_file_pages": 234, 246 | "mbind": 235, 247 | "get_mempolicy": 236, 248 | "set_mempolicy": 237, 249 | "migrate_pages": 238, 250 | "move_pages": 239, 251 | "rt_tgsigqueueinfo": 240, 252 | "perf_event_open": 241, 253 | "accept4": 242, 254 | "recvmmsg": 243, 255 | "wait4": 260, 256 | "prlimit64": 261, 257 | "fanotify_init": 262, 258 | "fanotify_mark": 263, 259 | "name_to_handle_at": 264, 260 | "open_by_handle_at": 265, 261 | "clock_adjtime": 266, 262 | "syncfs": 267, 263 | "setns": 268, 264 | "sendmmsg": 269, 265 | "process_vm_readv": 270, 266 | "process_vm_writev": 271, 267 | "kcmp": 272, 268 | "finit_module": 273, 269 | "sched_setattr": 274, 270 | "sched_getattr": 275, 271 | "renameat2": 276, 272 | "seccomp": 277, 273 | "getrandom": 278, 274 | "memfd_create": 279, 275 | "bpf": 280, 276 | "execveat": 281, 277 | "userfaultfd": 282, 278 | "membarrier": 283, 279 | "mlock2": 284, 280 | "copy_file_range": 285, 281 | "preadv2": 286, 282 | "pwritev2": 287, 283 | "pkey_mprotect": 288, 284 | "pkey_alloc": 289, 285 | "pkey_free": 290, 286 | "statx": 291, 287 | } 288 | 289 | var IdToSyscall = map[int]string{ 290 | 0: "io_setup", 291 | 1: "io_destroy", 292 | 2: "io_submit", 293 | 3: "io_cancel", 294 | 4: "io_getevents", 295 | 5: "setxattr", 296 | 6: "lsetxattr", 297 | 7: "fsetxattr", 298 | 8: "getxattr", 299 | 9: "lgetxattr", 300 | 10: "fgetxattr", 301 | 11: "listxattr", 302 | 12: "llistxattr", 303 | 13: "flistxattr", 304 | 14: "removexattr", 305 | 15: "lremovexattr", 306 | 16: "fremovexattr", 307 | 17: "getcwd", 308 | 18: "lookup_dcookie", 309 | 19: "eventfd2", 310 | 20: "epoll_create1", 311 | 21: "epoll_ctl", 312 | 22: "epoll_pwait", 313 | 23: "dup", 314 | 24: "dup3", 315 | 25: "fcntl", 316 | 26: "inotify_init1", 317 | 27: "inotify_add_watch", 318 | 28: "inotify_rm_watch", 319 | 29: "ioctl", 320 | 30: "ioprio_set", 321 | 31: "ioprio_get", 322 | 32: "flock", 323 | 33: "mknodat", 324 | 34: "mkdirat", 325 | 35: "unlinkat", 326 | 36: "symlinkat", 327 | 37: "linkat", 328 | 38: "renameat", 329 | 39: "umount2", 330 | 40: "mount", 331 | 41: "pivot_root", 332 | 42: "nfsservctl", 333 | 43: "statfs", 334 | 44: "fstatfs", 335 | 45: "truncate", 336 | 46: "ftruncate", 337 | 47: "fallocate", 338 | 48: "faccessat", 339 | 49: "chdir", 340 | 50: "fchdir", 341 | 51: "chroot", 342 | 52: "fchmod", 343 | 53: "fchmodat", 344 | 54: "fchownat", 345 | 55: "fchown", 346 | 56: "openat", 347 | 57: "close", 348 | 58: "vhangup", 349 | 59: "pipe2", 350 | 60: "quotactl", 351 | 61: "getdents64", 352 | 62: "lseek", 353 | 63: "read", 354 | 64: "write", 355 | 65: "readv", 356 | 66: "writev", 357 | 67: "pread64", 358 | 68: "pwrite64", 359 | 69: "preadv", 360 | 70: "pwritev", 361 | 71: "sendfile", 362 | 72: "pselect6", 363 | 73: "ppoll", 364 | 74: "signalfd4", 365 | 75: "vmsplice", 366 | 76: "splice", 367 | 77: "tee", 368 | 78: "readlinkat", 369 | 79: "newfstatat", 370 | 80: "fstat", 371 | 81: "sync", 372 | 82: "fsync", 373 | 83: "fdatasync", 374 | 84: "sync_file_range", 375 | 85: "timerfd_create", 376 | 86: "timerfd_settime", 377 | 87: "timerfd_gettime", 378 | 88: "utimensat", 379 | 89: "acct", 380 | 90: "capget", 381 | 91: "capset", 382 | 92: "personality", 383 | 93: "exit", 384 | 94: "exit_group", 385 | 95: "waitid", 386 | 96: "set_tid_address", 387 | 97: "unshare", 388 | 98: "futex", 389 | 99: "set_robust_list", 390 | 100: "get_robust_list", 391 | 101: "nanosleep", 392 | 102: "getitimer", 393 | 103: "setitimer", 394 | 104: "kexec_load", 395 | 105: "init_module", 396 | 106: "delete_module", 397 | 107: "timer_create", 398 | 108: "timer_gettime", 399 | 109: "timer_getoverrun", 400 | 110: "timer_settime", 401 | 111: "timer_delete", 402 | 112: "clock_settime", 403 | 113: "clock_gettime", 404 | 114: "clock_getres", 405 | 115: "clock_nanosleep", 406 | 116: "syslog", 407 | 117: "ptrace", 408 | 118: "sched_setparam", 409 | 119: "sched_setscheduler", 410 | 120: "sched_getscheduler", 411 | 121: "sched_getparam", 412 | 122: "sched_setaffinity", 413 | 123: "sched_getaffinity", 414 | 124: "sched_yield", 415 | 125: "sched_get_priority_max", 416 | 126: "sched_get_priority_min", 417 | 127: "sched_rr_get_interval", 418 | 128: "restart_syscall", 419 | 129: "kill", 420 | 130: "tkill", 421 | 131: "tgkill", 422 | 132: "sigaltstack", 423 | 133: "rt_sigsuspend", 424 | 134: "rt_sigaction", 425 | 135: "rt_sigprocmask", 426 | 136: "rt_sigpending", 427 | 137: "rt_sigtimedwait", 428 | 138: "rt_sigqueueinfo", 429 | 139: "rt_sigreturn", 430 | 140: "setpriority", 431 | 141: "getpriority", 432 | 142: "reboot", 433 | 143: "setregid", 434 | 144: "setgid", 435 | 145: "setreuid", 436 | 146: "setuid", 437 | 147: "setresuid", 438 | 148: "getresuid", 439 | 149: "setresgid", 440 | 150: "getresgid", 441 | 151: "setfsuid", 442 | 152: "setfsgid", 443 | 153: "times", 444 | 154: "setpgid", 445 | 155: "getpgid", 446 | 156: "getsid", 447 | 157: "setsid", 448 | 158: "getgroups", 449 | 159: "setgroups", 450 | 160: "uname", 451 | 161: "sethostname", 452 | 162: "setdomainname", 453 | 163: "getrlimit", 454 | 164: "setrlimit", 455 | 165: "getrusage", 456 | 166: "umask", 457 | 167: "prctl", 458 | 168: "getcpu", 459 | 169: "gettimeofday", 460 | 170: "settimeofday", 461 | 171: "adjtimex", 462 | 172: "getpid", 463 | 173: "getppid", 464 | 174: "getuid", 465 | 175: "geteuid", 466 | 176: "getgid", 467 | 177: "getegid", 468 | 178: "gettid", 469 | 179: "sysinfo", 470 | 180: "mq_open", 471 | 181: "mq_unlink", 472 | 182: "mq_timedsend", 473 | 183: "mq_timedreceive", 474 | 184: "mq_notify", 475 | 185: "mq_getsetattr", 476 | 186: "msgget", 477 | 187: "msgctl", 478 | 188: "msgrcv", 479 | 189: "msgsnd", 480 | 190: "semget", 481 | 191: "semctl", 482 | 192: "semtimedop", 483 | 193: "semop", 484 | 194: "shmget", 485 | 195: "shmctl", 486 | 196: "shmat", 487 | 197: "shmdt", 488 | 198: "socket", 489 | 199: "socketpair", 490 | 200: "bind", 491 | 201: "listen", 492 | 202: "accept", 493 | 203: "connect", 494 | 204: "getsockname", 495 | 205: "getpeername", 496 | 206: "sendto", 497 | 207: "recvfrom", 498 | 208: "setsockopt", 499 | 209: "getsockopt", 500 | 210: "shutdown", 501 | 211: "sendmsg", 502 | 212: "recvmsg", 503 | 213: "readahead", 504 | 214: "brk", 505 | 215: "munmap", 506 | 216: "mremap", 507 | 217: "add_key", 508 | 218: "request_key", 509 | 219: "keyctl", 510 | 220: "clone", 511 | 221: "execve", 512 | 222: "mmap", 513 | 223: "fadvise64", 514 | 224: "swapon", 515 | 225: "swapoff", 516 | 226: "mprotect", 517 | 227: "msync", 518 | 228: "mlock", 519 | 229: "munlock", 520 | 230: "mlockall", 521 | 231: "munlockall", 522 | 232: "mincore", 523 | 233: "madvise", 524 | 234: "remap_file_pages", 525 | 235: "mbind", 526 | 236: "get_mempolicy", 527 | 237: "set_mempolicy", 528 | 238: "migrate_pages", 529 | 239: "move_pages", 530 | 240: "rt_tgsigqueueinfo", 531 | 241: "perf_event_open", 532 | 242: "accept4", 533 | 243: "recvmmsg", 534 | 260: "wait4", 535 | 261: "prlimit64", 536 | 262: "fanotify_init", 537 | 263: "fanotify_mark", 538 | 264: "name_to_handle_at", 539 | 265: "open_by_handle_at", 540 | 266: "clock_adjtime", 541 | 267: "syncfs", 542 | 268: "setns", 543 | 269: "sendmmsg", 544 | 270: "process_vm_readv", 545 | 271: "process_vm_writev", 546 | 272: "kcmp", 547 | 273: "finit_module", 548 | 274: "sched_setattr", 549 | 275: "sched_getattr", 550 | 276: "renameat2", 551 | 277: "seccomp", 552 | 278: "getrandom", 553 | 279: "memfd_create", 554 | 280: "bpf", 555 | 281: "execveat", 556 | 282: "userfaultfd", 557 | 283: "membarrier", 558 | 284: "mlock2", 559 | 285: "copy_file_range", 560 | 286: "preadv2", 561 | 287: "pwritev2", 562 | 288: "pkey_mprotect", 563 | 289: "pkey_alloc", 564 | 290: "pkey_free", 565 | 291: "statx", 566 | } 567 | 568 | var WhitelistedSyscalls = []int{ 569 | SyscallToId["clone"], 570 | SyscallToId["execve"], 571 | SyscallToId["mknodat"], 572 | SyscallToId["chroot"], 573 | SyscallToId["mount"], 574 | SyscallToId["umount2"], 575 | SyscallToId["pivot_root"], 576 | SyscallToId["setuid"], 577 | SyscallToId["setgid"], 578 | SyscallToId["setreuid"], 579 | SyscallToId["setregid"], 580 | SyscallToId["setresuid"], 581 | SyscallToId["setresgid"], 582 | SyscallToId["capget"], 583 | SyscallToId["capset"], 584 | SyscallToId["prctl"], 585 | SyscallToId["seccomp"], 586 | SyscallToId["setns"], 587 | SyscallToId["unshare"], 588 | SyscallToId["kill"], 589 | SyscallToId["tkill"], 590 | SyscallToId["tgkill"], 591 | SyscallToId["socket"], 592 | SyscallToId["bind"], 593 | SyscallToId["connect"], 594 | SyscallToId["listen"], 595 | SyscallToId["accept"], 596 | SyscallToId["accept4"], 597 | SyscallToId["shutdown"], 598 | SyscallToId["sendmsg"], 599 | SyscallToId["recvmsg"], 600 | SyscallToId["sendto"], 601 | SyscallToId["recvfrom"], 602 | SyscallToId["getsockopt"], 603 | SyscallToId["setsockopt"], 604 | SyscallToId["sendmmsg"], 605 | SyscallToId["sethostname"], 606 | SyscallToId["setdomainname"], 607 | SyscallToId["wait4"], 608 | SyscallToId["finit_module"], 609 | SyscallToId["kexec_load"], 610 | SyscallToId["capget"], 611 | SyscallToId["capset"], 612 | SyscallToId["syslog"], 613 | SyscallToId["ptrace"], 614 | SyscallToId["prctl"], 615 | } 616 | -------------------------------------------------------------------------------- /internal/bpf/arch/amd64.go: -------------------------------------------------------------------------------- 1 | // AUTOGENERATED FILE 2 | 3 | //go:build amd64 4 | // +build amd64 5 | 6 | package bpfarch 7 | 8 | const BpfProgramElf = bpfProgramName + "_amd64.o" 9 | 10 | var SyscallToId = map[string]int{ 11 | "read": 0, 12 | "write": 1, 13 | "open": 2, 14 | "close": 3, 15 | "stat": 4, 16 | "fstat": 5, 17 | "lstat": 6, 18 | "poll": 7, 19 | "lseek": 8, 20 | "mmap": 9, 21 | "mprotect": 10, 22 | "munmap": 11, 23 | "brk": 12, 24 | "rt_sigaction": 13, 25 | "rt_sigprocmask": 14, 26 | "rt_sigreturn": 15, 27 | "ioctl": 16, 28 | "pread64": 17, 29 | "pwrite64": 18, 30 | "readv": 19, 31 | "writev": 20, 32 | "access": 21, 33 | "pipe": 22, 34 | "select": 23, 35 | "sched_yield": 24, 36 | "mremap": 25, 37 | "msync": 26, 38 | "mincore": 27, 39 | "madvise": 28, 40 | "shmget": 29, 41 | "shmat": 30, 42 | "shmctl": 31, 43 | "dup": 32, 44 | "dup2": 33, 45 | "pause": 34, 46 | "nanosleep": 35, 47 | "getitimer": 36, 48 | "alarm": 37, 49 | "setitimer": 38, 50 | "getpid": 39, 51 | "sendfile": 40, 52 | "socket": 41, 53 | "connect": 42, 54 | "accept": 43, 55 | "sendto": 44, 56 | "recvfrom": 45, 57 | "sendmsg": 46, 58 | "recvmsg": 47, 59 | "shutdown": 48, 60 | "bind": 49, 61 | "listen": 50, 62 | "getsockname": 51, 63 | "getpeername": 52, 64 | "socketpair": 53, 65 | "setsockopt": 54, 66 | "getsockopt": 55, 67 | "clone": 56, 68 | "fork": 57, 69 | "vfork": 58, 70 | "execve": 59, 71 | "exit": 60, 72 | "wait4": 61, 73 | "kill": 62, 74 | "uname": 63, 75 | "semget": 64, 76 | "semop": 65, 77 | "semctl": 66, 78 | "shmdt": 67, 79 | "msgget": 68, 80 | "msgsnd": 69, 81 | "msgrcv": 70, 82 | "msgctl": 71, 83 | "fcntl": 72, 84 | "flock": 73, 85 | "fsync": 74, 86 | "fdatasync": 75, 87 | "truncate": 76, 88 | "ftruncate": 77, 89 | "getdents": 78, 90 | "getcwd": 79, 91 | "chdir": 80, 92 | "fchdir": 81, 93 | "rename": 82, 94 | "mkdir": 83, 95 | "rmdir": 84, 96 | "creat": 85, 97 | "link": 86, 98 | "unlink": 87, 99 | "symlink": 88, 100 | "readlink": 89, 101 | "chmod": 90, 102 | "fchmod": 91, 103 | "chown": 92, 104 | "fchown": 93, 105 | "lchown": 94, 106 | "umask": 95, 107 | "gettimeofday": 96, 108 | "getrlimit": 97, 109 | "getrusage": 98, 110 | "sysinfo": 99, 111 | "times": 100, 112 | "ptrace": 101, 113 | "getuid": 102, 114 | "syslog": 103, 115 | "getgid": 104, 116 | "setuid": 105, 117 | "setgid": 106, 118 | "geteuid": 107, 119 | "getegid": 108, 120 | "setpgid": 109, 121 | "getppid": 110, 122 | "getpgrp": 111, 123 | "setsid": 112, 124 | "setreuid": 113, 125 | "setregid": 114, 126 | "getgroups": 115, 127 | "setgroups": 116, 128 | "setresuid": 117, 129 | "getresuid": 118, 130 | "setresgid": 119, 131 | "getresgid": 120, 132 | "getpgid": 121, 133 | "setfsuid": 122, 134 | "setfsgid": 123, 135 | "getsid": 124, 136 | "capget": 125, 137 | "capset": 126, 138 | "rt_sigpending": 127, 139 | "rt_sigtimedwait": 128, 140 | "rt_sigqueueinfo": 129, 141 | "rt_sigsuspend": 130, 142 | "sigaltstack": 131, 143 | "utime": 132, 144 | "mknod": 133, 145 | "uselib": 134, 146 | "personality": 135, 147 | "ustat": 136, 148 | "statfs": 137, 149 | "fstatfs": 138, 150 | "sysfs": 139, 151 | "getpriority": 140, 152 | "setpriority": 141, 153 | "sched_setparam": 142, 154 | "sched_getparam": 143, 155 | "sched_setscheduler": 144, 156 | "sched_getscheduler": 145, 157 | "sched_get_priority_max": 146, 158 | "sched_get_priority_min": 147, 159 | "sched_rr_get_interval": 148, 160 | "mlock": 149, 161 | "munlock": 150, 162 | "mlockall": 151, 163 | "munlockall": 152, 164 | "vhangup": 153, 165 | "modify_ldt": 154, 166 | "pivot_root": 155, 167 | "_sysctl": 156, 168 | "prctl": 157, 169 | "arch_prctl": 158, 170 | "adjtimex": 159, 171 | "setrlimit": 160, 172 | "chroot": 161, 173 | "sync": 162, 174 | "acct": 163, 175 | "settimeofday": 164, 176 | "mount": 165, 177 | "umount2": 166, 178 | "swapon": 167, 179 | "swapoff": 168, 180 | "reboot": 169, 181 | "sethostname": 170, 182 | "setdomainname": 171, 183 | "iopl": 172, 184 | "ioperm": 173, 185 | "create_module": 174, 186 | "init_module": 175, 187 | "delete_module": 176, 188 | "get_kernel_syms": 177, 189 | "query_module": 178, 190 | "quotactl": 179, 191 | "nfsservctl": 180, 192 | "getpmsg": 181, 193 | "putpmsg": 182, 194 | "afs_syscall": 183, 195 | "tuxcall": 184, 196 | "security": 185, 197 | "gettid": 186, 198 | "readahead": 187, 199 | "setxattr": 188, 200 | "lsetxattr": 189, 201 | "fsetxattr": 190, 202 | "getxattr": 191, 203 | "lgetxattr": 192, 204 | "fgetxattr": 193, 205 | "listxattr": 194, 206 | "llistxattr": 195, 207 | "flistxattr": 196, 208 | "removexattr": 197, 209 | "lremovexattr": 198, 210 | "fremovexattr": 199, 211 | "tkill": 200, 212 | "time": 201, 213 | "futex": 202, 214 | "sched_setaffinity": 203, 215 | "sched_getaffinity": 204, 216 | "set_thread_area": 205, 217 | "io_setup": 206, 218 | "io_destroy": 207, 219 | "io_getevents": 208, 220 | "io_submit": 209, 221 | "io_cancel": 210, 222 | "get_thread_area": 211, 223 | "lookup_dcookie": 212, 224 | "epoll_create": 213, 225 | "epoll_ctl_old": 214, 226 | "epoll_wait_old": 215, 227 | "remap_file_pages": 216, 228 | "getdents64": 217, 229 | "set_tid_address": 218, 230 | "restart_syscall": 219, 231 | "semtimedop": 220, 232 | "fadvise64": 221, 233 | "timer_create": 222, 234 | "timer_settime": 223, 235 | "timer_gettime": 224, 236 | "timer_getoverrun": 225, 237 | "timer_delete": 226, 238 | "clock_settime": 227, 239 | "clock_gettime": 228, 240 | "clock_getres": 229, 241 | "clock_nanosleep": 230, 242 | "exit_group": 231, 243 | "epoll_wait": 232, 244 | "epoll_ctl": 233, 245 | "tgkill": 234, 246 | "utimes": 235, 247 | "vserver": 236, 248 | "mbind": 237, 249 | "set_mempolicy": 238, 250 | "get_mempolicy": 239, 251 | "mq_open": 240, 252 | "mq_unlink": 241, 253 | "mq_timedsend": 242, 254 | "mq_timedreceive": 243, 255 | "mq_notify": 244, 256 | "mq_getsetattr": 245, 257 | "kexec_load": 246, 258 | "waitid": 247, 259 | "add_key": 248, 260 | "request_key": 249, 261 | "keyctl": 250, 262 | "ioprio_set": 251, 263 | "ioprio_get": 252, 264 | "inotify_init": 253, 265 | "inotify_add_watch": 254, 266 | "inotify_rm_watch": 255, 267 | "migrate_pages": 256, 268 | "openat": 257, 269 | "mkdirat": 258, 270 | "mknodat": 259, 271 | "fchownat": 260, 272 | "futimesat": 261, 273 | "newfstatat": 262, 274 | "unlinkat": 263, 275 | "renameat": 264, 276 | "linkat": 265, 277 | "symlinkat": 266, 278 | "readlinkat": 267, 279 | "fchmodat": 268, 280 | "faccessat": 269, 281 | "pselect6": 270, 282 | "ppoll": 271, 283 | "unshare": 272, 284 | "set_robust_list": 273, 285 | "get_robust_list": 274, 286 | "splice": 275, 287 | "tee": 276, 288 | "sync_file_range": 277, 289 | "vmsplice": 278, 290 | "move_pages": 279, 291 | "utimensat": 280, 292 | "epoll_pwait": 281, 293 | "signalfd": 282, 294 | "timerfd_create": 283, 295 | "eventfd": 284, 296 | "fallocate": 285, 297 | "timerfd_settime": 286, 298 | "timerfd_gettime": 287, 299 | "accept4": 288, 300 | "signalfd4": 289, 301 | "eventfd2": 290, 302 | "epoll_create1": 291, 303 | "dup3": 292, 304 | "pipe2": 293, 305 | "inotify_init1": 294, 306 | "preadv": 295, 307 | "pwritev": 296, 308 | "rt_tgsigqueueinfo": 297, 309 | "perf_event_open": 298, 310 | "recvmmsg": 299, 311 | "fanotify_init": 300, 312 | "fanotify_mark": 301, 313 | "prlimit64": 302, 314 | "name_to_handle_at": 303, 315 | "open_by_handle_at": 304, 316 | "clock_adjtime": 305, 317 | "syncfs": 306, 318 | "sendmmsg": 307, 319 | "setns": 308, 320 | "getcpu": 309, 321 | "process_vm_readv": 310, 322 | "process_vm_writev": 311, 323 | "kcmp": 312, 324 | "finit_module": 313, 325 | "sched_setattr": 314, 326 | "sched_getattr": 315, 327 | "renameat2": 316, 328 | "seccomp": 317, 329 | "getrandom": 318, 330 | "memfd_create": 319, 331 | "kexec_file_load": 320, 332 | "bpf": 321, 333 | "execveat": 322, 334 | "userfaultfd": 323, 335 | "membarrier": 324, 336 | "mlock2": 325, 337 | "copy_file_range": 326, 338 | "preadv2": 327, 339 | "pwritev2": 328, 340 | "pkey_mprotect": 329, 341 | "pkey_alloc": 330, 342 | "pkey_free": 331, 343 | "statx": 332, 344 | } 345 | 346 | var IdToSyscall = map[int]string{ 347 | 0: "read", 348 | 1: "write", 349 | 2: "open", 350 | 3: "close", 351 | 4: "stat", 352 | 5: "fstat", 353 | 6: "lstat", 354 | 7: "poll", 355 | 8: "lseek", 356 | 9: "mmap", 357 | 10: "mprotect", 358 | 11: "munmap", 359 | 12: "brk", 360 | 13: "rt_sigaction", 361 | 14: "rt_sigprocmask", 362 | 15: "rt_sigreturn", 363 | 16: "ioctl", 364 | 17: "pread64", 365 | 18: "pwrite64", 366 | 19: "readv", 367 | 20: "writev", 368 | 21: "access", 369 | 22: "pipe", 370 | 23: "select", 371 | 24: "sched_yield", 372 | 25: "mremap", 373 | 26: "msync", 374 | 27: "mincore", 375 | 28: "madvise", 376 | 29: "shmget", 377 | 30: "shmat", 378 | 31: "shmctl", 379 | 32: "dup", 380 | 33: "dup2", 381 | 34: "pause", 382 | 35: "nanosleep", 383 | 36: "getitimer", 384 | 37: "alarm", 385 | 38: "setitimer", 386 | 39: "getpid", 387 | 40: "sendfile", 388 | 41: "socket", 389 | 42: "connect", 390 | 43: "accept", 391 | 44: "sendto", 392 | 45: "recvfrom", 393 | 46: "sendmsg", 394 | 47: "recvmsg", 395 | 48: "shutdown", 396 | 49: "bind", 397 | 50: "listen", 398 | 51: "getsockname", 399 | 52: "getpeername", 400 | 53: "socketpair", 401 | 54: "setsockopt", 402 | 55: "getsockopt", 403 | 56: "clone", 404 | 57: "fork", 405 | 58: "vfork", 406 | 59: "execve", 407 | 60: "exit", 408 | 61: "wait4", 409 | 62: "kill", 410 | 63: "uname", 411 | 64: "semget", 412 | 65: "semop", 413 | 66: "semctl", 414 | 67: "shmdt", 415 | 68: "msgget", 416 | 69: "msgsnd", 417 | 70: "msgrcv", 418 | 71: "msgctl", 419 | 72: "fcntl", 420 | 73: "flock", 421 | 74: "fsync", 422 | 75: "fdatasync", 423 | 76: "truncate", 424 | 77: "ftruncate", 425 | 78: "getdents", 426 | 79: "getcwd", 427 | 80: "chdir", 428 | 81: "fchdir", 429 | 82: "rename", 430 | 83: "mkdir", 431 | 84: "rmdir", 432 | 85: "creat", 433 | 86: "link", 434 | 87: "unlink", 435 | 88: "symlink", 436 | 89: "readlink", 437 | 90: "chmod", 438 | 91: "fchmod", 439 | 92: "chown", 440 | 93: "fchown", 441 | 94: "lchown", 442 | 95: "umask", 443 | 96: "gettimeofday", 444 | 97: "getrlimit", 445 | 98: "getrusage", 446 | 99: "sysinfo", 447 | 100: "times", 448 | 101: "ptrace", 449 | 102: "getuid", 450 | 103: "syslog", 451 | 104: "getgid", 452 | 105: "setuid", 453 | 106: "setgid", 454 | 107: "geteuid", 455 | 108: "getegid", 456 | 109: "setpgid", 457 | 110: "getppid", 458 | 111: "getpgrp", 459 | 112: "setsid", 460 | 113: "setreuid", 461 | 114: "setregid", 462 | 115: "getgroups", 463 | 116: "setgroups", 464 | 117: "setresuid", 465 | 118: "getresuid", 466 | 119: "setresgid", 467 | 120: "getresgid", 468 | 121: "getpgid", 469 | 122: "setfsuid", 470 | 123: "setfsgid", 471 | 124: "getsid", 472 | 125: "capget", 473 | 126: "capset", 474 | 127: "rt_sigpending", 475 | 128: "rt_sigtimedwait", 476 | 129: "rt_sigqueueinfo", 477 | 130: "rt_sigsuspend", 478 | 131: "sigaltstack", 479 | 132: "utime", 480 | 133: "mknod", 481 | 134: "uselib", 482 | 135: "personality", 483 | 136: "ustat", 484 | 137: "statfs", 485 | 138: "fstatfs", 486 | 139: "sysfs", 487 | 140: "getpriority", 488 | 141: "setpriority", 489 | 142: "sched_setparam", 490 | 143: "sched_getparam", 491 | 144: "sched_setscheduler", 492 | 145: "sched_getscheduler", 493 | 146: "sched_get_priority_max", 494 | 147: "sched_get_priority_min", 495 | 148: "sched_rr_get_interval", 496 | 149: "mlock", 497 | 150: "munlock", 498 | 151: "mlockall", 499 | 152: "munlockall", 500 | 153: "vhangup", 501 | 154: "modify_ldt", 502 | 155: "pivot_root", 503 | 156: "_sysctl", 504 | 157: "prctl", 505 | 158: "arch_prctl", 506 | 159: "adjtimex", 507 | 160: "setrlimit", 508 | 161: "chroot", 509 | 162: "sync", 510 | 163: "acct", 511 | 164: "settimeofday", 512 | 165: "mount", 513 | 166: "umount2", 514 | 167: "swapon", 515 | 168: "swapoff", 516 | 169: "reboot", 517 | 170: "sethostname", 518 | 171: "setdomainname", 519 | 172: "iopl", 520 | 173: "ioperm", 521 | 174: "create_module", 522 | 175: "init_module", 523 | 176: "delete_module", 524 | 177: "get_kernel_syms", 525 | 178: "query_module", 526 | 179: "quotactl", 527 | 180: "nfsservctl", 528 | 181: "getpmsg", 529 | 182: "putpmsg", 530 | 183: "afs_syscall", 531 | 184: "tuxcall", 532 | 185: "security", 533 | 186: "gettid", 534 | 187: "readahead", 535 | 188: "setxattr", 536 | 189: "lsetxattr", 537 | 190: "fsetxattr", 538 | 191: "getxattr", 539 | 192: "lgetxattr", 540 | 193: "fgetxattr", 541 | 194: "listxattr", 542 | 195: "llistxattr", 543 | 196: "flistxattr", 544 | 197: "removexattr", 545 | 198: "lremovexattr", 546 | 199: "fremovexattr", 547 | 200: "tkill", 548 | 201: "time", 549 | 202: "futex", 550 | 203: "sched_setaffinity", 551 | 204: "sched_getaffinity", 552 | 205: "set_thread_area", 553 | 206: "io_setup", 554 | 207: "io_destroy", 555 | 208: "io_getevents", 556 | 209: "io_submit", 557 | 210: "io_cancel", 558 | 211: "get_thread_area", 559 | 212: "lookup_dcookie", 560 | 213: "epoll_create", 561 | 214: "epoll_ctl_old", 562 | 215: "epoll_wait_old", 563 | 216: "remap_file_pages", 564 | 217: "getdents64", 565 | 218: "set_tid_address", 566 | 219: "restart_syscall", 567 | 220: "semtimedop", 568 | 221: "fadvise64", 569 | 222: "timer_create", 570 | 223: "timer_settime", 571 | 224: "timer_gettime", 572 | 225: "timer_getoverrun", 573 | 226: "timer_delete", 574 | 227: "clock_settime", 575 | 228: "clock_gettime", 576 | 229: "clock_getres", 577 | 230: "clock_nanosleep", 578 | 231: "exit_group", 579 | 232: "epoll_wait", 580 | 233: "epoll_ctl", 581 | 234: "tgkill", 582 | 235: "utimes", 583 | 236: "vserver", 584 | 237: "mbind", 585 | 238: "set_mempolicy", 586 | 239: "get_mempolicy", 587 | 240: "mq_open", 588 | 241: "mq_unlink", 589 | 242: "mq_timedsend", 590 | 243: "mq_timedreceive", 591 | 244: "mq_notify", 592 | 245: "mq_getsetattr", 593 | 246: "kexec_load", 594 | 247: "waitid", 595 | 248: "add_key", 596 | 249: "request_key", 597 | 250: "keyctl", 598 | 251: "ioprio_set", 599 | 252: "ioprio_get", 600 | 253: "inotify_init", 601 | 254: "inotify_add_watch", 602 | 255: "inotify_rm_watch", 603 | 256: "migrate_pages", 604 | 257: "openat", 605 | 258: "mkdirat", 606 | 259: "mknodat", 607 | 260: "fchownat", 608 | 261: "futimesat", 609 | 262: "newfstatat", 610 | 263: "unlinkat", 611 | 264: "renameat", 612 | 265: "linkat", 613 | 266: "symlinkat", 614 | 267: "readlinkat", 615 | 268: "fchmodat", 616 | 269: "faccessat", 617 | 270: "pselect6", 618 | 271: "ppoll", 619 | 272: "unshare", 620 | 273: "set_robust_list", 621 | 274: "get_robust_list", 622 | 275: "splice", 623 | 276: "tee", 624 | 277: "sync_file_range", 625 | 278: "vmsplice", 626 | 279: "move_pages", 627 | 280: "utimensat", 628 | 281: "epoll_pwait", 629 | 282: "signalfd", 630 | 283: "timerfd_create", 631 | 284: "eventfd", 632 | 285: "fallocate", 633 | 286: "timerfd_settime", 634 | 287: "timerfd_gettime", 635 | 288: "accept4", 636 | 289: "signalfd4", 637 | 290: "eventfd2", 638 | 291: "epoll_create1", 639 | 292: "dup3", 640 | 293: "pipe2", 641 | 294: "inotify_init1", 642 | 295: "preadv", 643 | 296: "pwritev", 644 | 297: "rt_tgsigqueueinfo", 645 | 298: "perf_event_open", 646 | 299: "recvmmsg", 647 | 300: "fanotify_init", 648 | 301: "fanotify_mark", 649 | 302: "prlimit64", 650 | 303: "name_to_handle_at", 651 | 304: "open_by_handle_at", 652 | 305: "clock_adjtime", 653 | 306: "syncfs", 654 | 307: "sendmmsg", 655 | 308: "setns", 656 | 309: "getcpu", 657 | 310: "process_vm_readv", 658 | 311: "process_vm_writev", 659 | 312: "kcmp", 660 | 313: "finit_module", 661 | 314: "sched_setattr", 662 | 315: "sched_getattr", 663 | 316: "renameat2", 664 | 317: "seccomp", 665 | 318: "getrandom", 666 | 319: "memfd_create", 667 | 320: "kexec_file_load", 668 | 321: "bpf", 669 | 322: "execveat", 670 | 323: "userfaultfd", 671 | 324: "membarrier", 672 | 325: "mlock2", 673 | 326: "copy_file_range", 674 | 327: "preadv2", 675 | 328: "pwritev2", 676 | 329: "pkey_mprotect", 677 | 330: "pkey_alloc", 678 | 331: "pkey_free", 679 | 332: "statx", 680 | } 681 | 682 | var WhitelistedSyscalls = []int{ 683 | SyscallToId["clone"], 684 | SyscallToId["fork"], 685 | SyscallToId["vfork"], 686 | SyscallToId["execve"], 687 | SyscallToId["exit"], 688 | SyscallToId["wait4"], 689 | SyscallToId["kill"], 690 | SyscallToId["ptrace"], 691 | SyscallToId["setuid"], 692 | SyscallToId["setgid"], 693 | SyscallToId["seteuid"], 694 | SyscallToId["setegid"], 695 | SyscallToId["setpgid"], 696 | SyscallToId["setresuid"], 697 | SyscallToId["getresuid"], 698 | SyscallToId["setresgid"], 699 | SyscallToId["getresgid"], 700 | SyscallToId["prctl"], 701 | SyscallToId["arch_prctl"], 702 | SyscallToId["capget"], 703 | SyscallToId["capset"], 704 | SyscallToId["seccomp"], 705 | SyscallToId["setns"], 706 | SyscallToId["unshare"], 707 | SyscallToId["chroot"], 708 | SyscallToId["pivot_root"], 709 | SyscallToId["mknod"], 710 | SyscallToId["mount"], 711 | SyscallToId["umount2"], 712 | SyscallToId["socket"], 713 | SyscallToId["connect"], 714 | SyscallToId["accept"], 715 | SyscallToId["sendto"], 716 | SyscallToId["recvfrom"], 717 | SyscallToId["sendmsg"], 718 | SyscallToId["recvmsg"], 719 | SyscallToId["shutdown"], 720 | SyscallToId["bind"], 721 | SyscallToId["listen"], 722 | SyscallToId["getsockname"], 723 | SyscallToId["getpeername"], 724 | SyscallToId["socketpair"], 725 | SyscallToId["setsockopt"], 726 | SyscallToId["getsockopt"], 727 | SyscallToId["accept4"], 728 | SyscallToId["sendmmsg"], 729 | SyscallToId["getrandom"], 730 | SyscallToId["mknodat"], 731 | SyscallToId["fchownat"], 732 | } 733 | -------------------------------------------------------------------------------- /internal/bpf/arch/386.go: -------------------------------------------------------------------------------- 1 | // AUTOGENERATED FILE 2 | 3 | //go:build 386 4 | // +build 386 5 | 6 | package bpfarch 7 | 8 | const BpfProgramElf = bpfProgramName + "_x86.o" 9 | 10 | var SyscallToId = map[string]int{ 11 | "restart_syscall": 0, 12 | "exit": 1, 13 | "fork": 2, 14 | "read": 3, 15 | "write": 4, 16 | "open": 5, 17 | "close": 6, 18 | "waitpid": 7, 19 | "creat": 8, 20 | "link": 9, 21 | "unlink": 10, 22 | "execve": 11, 23 | "chdir": 12, 24 | "time": 13, 25 | "mknod": 14, 26 | "chmod": 15, 27 | "lchown": 16, 28 | "break": 17, 29 | "oldstat": 18, 30 | "lseek": 19, 31 | "getpid": 20, 32 | "mount": 21, 33 | "umount": 22, 34 | "setuid": 23, 35 | "getuid": 24, 36 | "stime": 25, 37 | "ptrace": 26, 38 | "alarm": 27, 39 | "oldfstat": 28, 40 | "pause": 29, 41 | "utime": 30, 42 | "stty": 31, 43 | "gtty": 32, 44 | "access": 33, 45 | "nice": 34, 46 | "ftime": 35, 47 | "sync": 36, 48 | "kill": 37, 49 | "rename": 38, 50 | "mkdir": 39, 51 | "rmdir": 40, 52 | "dup": 41, 53 | "pipe": 42, 54 | "times": 43, 55 | "prof": 44, 56 | "brk": 45, 57 | "setgid": 46, 58 | "getgid": 47, 59 | "signal": 48, 60 | "geteuid": 49, 61 | "getegid": 50, 62 | "acct": 51, 63 | "umount2": 52, 64 | "lock": 53, 65 | "ioctl": 54, 66 | "fcntl": 55, 67 | "mpx": 56, 68 | "setpgid": 57, 69 | "ulimit": 58, 70 | "oldolduname": 59, 71 | "umask": 60, 72 | "chroot": 61, 73 | "ustat": 62, 74 | "dup2": 63, 75 | "getppid": 64, 76 | "getpgrp": 65, 77 | "setsid": 66, 78 | "sigaction": 67, 79 | "sgetmask": 68, 80 | "ssetmask": 69, 81 | "setreuid": 70, 82 | "setregid": 71, 83 | "sigsuspend": 72, 84 | "sigpending": 73, 85 | "sethostname": 74, 86 | "setrlimit": 75, 87 | "getrlimit": 76, 88 | "getrusage": 77, 89 | "gettimeofday": 78, 90 | "settimeofday": 79, 91 | "getgroups": 80, 92 | "setgroups": 81, 93 | "select": 82, 94 | "symlink": 83, 95 | "oldlstat": 84, 96 | "readlink": 85, 97 | "uselib": 86, 98 | "swapon": 87, 99 | "reboot": 88, 100 | "readdir": 89, 101 | "mmap": 90, 102 | "munmap": 91, 103 | "truncate": 92, 104 | "ftruncate": 93, 105 | "fchmod": 94, 106 | "fchown": 95, 107 | "getpriority": 96, 108 | "setpriority": 97, 109 | "profil": 98, 110 | "statfs": 99, 111 | "fstatfs": 100, 112 | "ioperm": 101, 113 | "socketcall": 102, 114 | "syslog": 103, 115 | "setitimer": 104, 116 | "getitimer": 105, 117 | "stat": 106, 118 | "lstat": 107, 119 | "fstat": 108, 120 | "olduname": 109, 121 | "iopl": 110, 122 | "vhangup": 111, 123 | "idle": 112, 124 | "vm86old": 113, 125 | "wait4": 114, 126 | "swapoff": 115, 127 | "sysinfo": 116, 128 | "ipc": 117, 129 | "fsync": 118, 130 | "sigreturn": 119, 131 | "clone": 120, 132 | "setdomainname": 121, 133 | "uname": 122, 134 | "modify_ldt": 123, 135 | "adjtimex": 124, 136 | "mprotect": 125, 137 | "sigprocmask": 126, 138 | "create_module": 127, 139 | "init_module": 128, 140 | "delete_module": 129, 141 | "get_kernel_syms": 130, 142 | "quotactl": 131, 143 | "getpgid": 132, 144 | "fchdir": 133, 145 | "bdflush": 134, 146 | "sysfs": 135, 147 | "personality": 136, 148 | "afs_syscall": 137, 149 | "setfsuid": 138, 150 | "setfsgid": 139, 151 | "_llseek": 140, 152 | "getdents": 141, 153 | "_newselect": 142, 154 | "flock": 143, 155 | "msync": 144, 156 | "readv": 145, 157 | "writev": 146, 158 | "getsid": 147, 159 | "fdatasync": 148, 160 | "_sysctl": 149, 161 | "mlock": 150, 162 | "munlock": 151, 163 | "mlockall": 152, 164 | "munlockall": 153, 165 | "sched_setparam": 154, 166 | "sched_getparam": 155, 167 | "sched_setscheduler": 156, 168 | "sched_getscheduler": 157, 169 | "sched_yield": 158, 170 | "sched_get_priority_max": 159, 171 | "sched_get_priority_min": 160, 172 | "sched_rr_get_interval": 161, 173 | "nanosleep": 162, 174 | "mremap": 163, 175 | "setresuid": 164, 176 | "getresuid": 165, 177 | "vm86": 166, 178 | "query_module": 167, 179 | "poll": 168, 180 | "nfsservctl": 169, 181 | "setresgid": 170, 182 | "getresgid": 171, 183 | "prctl": 172, 184 | "rt_sigreturn": 173, 185 | "rt_sigaction": 174, 186 | "rt_sigprocmask": 175, 187 | "rt_sigpending": 176, 188 | "rt_sigtimedwait": 177, 189 | "rt_sigqueueinfo": 178, 190 | "rt_sigsuspend": 179, 191 | "pread64": 180, 192 | "pwrite64": 181, 193 | "chown": 182, 194 | "getcwd": 183, 195 | "capget": 184, 196 | "capset": 185, 197 | "sigaltstack": 186, 198 | "sendfile": 187, 199 | "getpmsg": 188, 200 | "putpmsg": 189, 201 | "vfork": 190, 202 | "ugetrlimit": 191, 203 | "mmap2": 192, 204 | "truncate64": 193, 205 | "ftruncate64": 194, 206 | "stat64": 195, 207 | "lstat64": 196, 208 | "fstat64": 197, 209 | "lchown32": 198, 210 | "getuid32": 199, 211 | "getgid32": 200, 212 | "geteuid32": 201, 213 | "getegid32": 202, 214 | "setreuid32": 203, 215 | "setregid32": 204, 216 | "getgroups32": 205, 217 | "setgroups32": 206, 218 | "fchown32": 207, 219 | "setresuid32": 208, 220 | "getresuid32": 209, 221 | "setresgid32": 210, 222 | "getresgid32": 211, 223 | "chown32": 212, 224 | "setuid32": 213, 225 | "setgid32": 214, 226 | "setfsuid32": 215, 227 | "setfsgid32": 216, 228 | "pivot_root": 217, 229 | "mincore": 218, 230 | "madvise": 219, 231 | "getdents64": 220, 232 | "fcntl64": 221, 233 | "gettid": 224, 234 | "readahead": 225, 235 | "setxattr": 226, 236 | "lsetxattr": 227, 237 | "fsetxattr": 228, 238 | "getxattr": 229, 239 | "lgetxattr": 230, 240 | "fgetxattr": 231, 241 | "listxattr": 232, 242 | "llistxattr": 233, 243 | "flistxattr": 234, 244 | "removexattr": 235, 245 | "lremovexattr": 236, 246 | "fremovexattr": 237, 247 | "tkill": 238, 248 | "sendfile64": 239, 249 | "futex": 240, 250 | "sched_setaffinity": 241, 251 | "sched_getaffinity": 242, 252 | "set_thread_area": 243, 253 | "get_thread_area": 244, 254 | "io_setup": 245, 255 | "io_destroy": 246, 256 | "io_getevents": 247, 257 | "io_submit": 248, 258 | "io_cancel": 249, 259 | "fadvise64": 250, 260 | "exit_group": 252, 261 | "lookup_dcookie": 253, 262 | "epoll_create": 254, 263 | "epoll_ctl": 255, 264 | "epoll_wait": 256, 265 | "remap_file_pages": 257, 266 | "set_tid_address": 258, 267 | "timer_create": 259, 268 | "timer_settime": 260, 269 | "timer_gettime": 261, 270 | "timer_getoverrun": 262, 271 | "timer_delete": 263, 272 | "clock_settime": 264, 273 | "clock_gettime": 265, 274 | "clock_getres": 266, 275 | "clock_nanosleep": 267, 276 | "statfs64": 268, 277 | "fstatfs64": 269, 278 | "tgkill": 270, 279 | "utimes": 271, 280 | "fadvise64_64": 272, 281 | "vserver": 273, 282 | "mbind": 274, 283 | "get_mempolicy": 275, 284 | "set_mempolicy": 276, 285 | "mq_open": 277, 286 | "mq_unlink": 278, 287 | "mq_timedsend": 279, 288 | "mq_timedreceive": 280, 289 | "mq_notify": 281, 290 | "mq_getsetattr": 282, 291 | "kexec_load": 283, 292 | "waitid": 284, 293 | "add_key": 286, 294 | "request_key": 287, 295 | "keyctl": 288, 296 | "ioprio_set": 289, 297 | "ioprio_get": 290, 298 | "inotify_init": 291, 299 | "inotify_add_watch": 292, 300 | "inotify_rm_watch": 293, 301 | "migrate_pages": 294, 302 | "openat": 295, 303 | "mkdirat": 296, 304 | "mknodat": 297, 305 | "fchownat": 298, 306 | "futimesat": 299, 307 | "fstatat64": 300, 308 | "unlinkat": 301, 309 | "renameat": 302, 310 | "linkat": 303, 311 | "symlinkat": 304, 312 | "readlinkat": 305, 313 | "fchmodat": 306, 314 | "faccessat": 307, 315 | "pselect6": 308, 316 | "ppoll": 309, 317 | "unshare": 310, 318 | "set_robust_list": 311, 319 | "get_robust_list": 312, 320 | "splice": 313, 321 | "sync_file_range": 314, 322 | "tee": 315, 323 | "vmsplice": 316, 324 | "move_pages": 317, 325 | "getcpu": 318, 326 | "epoll_pwait": 319, 327 | "utimensat": 320, 328 | "signalfd": 321, 329 | "timerfd_create": 322, 330 | "eventfd": 323, 331 | "fallocate": 324, 332 | "timerfd_settime": 325, 333 | "timerfd_gettime": 326, 334 | "signalfd4": 327, 335 | "eventfd2": 328, 336 | "epoll_create1": 329, 337 | "dup3": 330, 338 | "pipe2": 331, 339 | "inotify_init1": 332, 340 | "preadv": 333, 341 | "pwritev": 334, 342 | "rt_tgsigqueueinfo": 335, 343 | "perf_event_open": 336, 344 | "recvmmsg": 337, 345 | "fanotify_init": 338, 346 | "fanotify_mark": 339, 347 | "prlimit64": 340, 348 | "name_to_handle_at": 341, 349 | "open_by_handle_at": 342, 350 | "clock_adjtime": 343, 351 | "syncfs": 344, 352 | "sendmmsg": 345, 353 | "setns": 346, 354 | "process_vm_readv": 347, 355 | "process_vm_writev": 348, 356 | "kcmp": 349, 357 | "finit_module": 350, 358 | "sched_setattr": 351, 359 | "sched_getattr": 352, 360 | "renameat2": 353, 361 | "seccomp": 354, 362 | "getrandom": 355, 363 | "memfd_create": 356, 364 | "bpf": 357, 365 | "execveat": 358, 366 | "socket": 359, 367 | "socketpair": 360, 368 | "bind": 361, 369 | "connect": 362, 370 | "listen": 363, 371 | "accept4": 364, 372 | "getsockopt": 365, 373 | "setsockopt": 366, 374 | "getsockname": 367, 375 | "getpeername": 368, 376 | "sendto": 369, 377 | "sendmsg": 370, 378 | "recvfrom": 371, 379 | "recvmsg": 372, 380 | "shutdown": 373, 381 | "userfaultfd": 374, 382 | "membarrier": 375, 383 | "mlock2": 376, 384 | "copy_file_range": 377, 385 | "preadv2": 378, 386 | "pwritev2": 379, 387 | "pkey_mprotect": 380, 388 | "pkey_alloc": 381, 389 | "pkey_free": 382, 390 | "statx": 383, 391 | "arch_prctl": 384, 392 | } 393 | 394 | var IdToSyscall = map[int]string{ 395 | 0: "restart_syscall", 396 | 1: "exit", 397 | 2: "fork", 398 | 3: "read", 399 | 4: "write", 400 | 5: "open", 401 | 6: "close", 402 | 7: "waitpid", 403 | 8: "creat", 404 | 9: "link", 405 | 10: "unlink", 406 | 11: "execve", 407 | 12: "chdir", 408 | 13: "time", 409 | 14: "mknod", 410 | 15: "chmod", 411 | 16: "lchown", 412 | 17: "break", 413 | 18: "oldstat", 414 | 19: "lseek", 415 | 20: "getpid", 416 | 21: "mount", 417 | 22: "umount", 418 | 23: "setuid", 419 | 24: "getuid", 420 | 25: "stime", 421 | 26: "ptrace", 422 | 27: "alarm", 423 | 28: "oldfstat", 424 | 29: "pause", 425 | 30: "utime", 426 | 31: "stty", 427 | 32: "gtty", 428 | 33: "access", 429 | 34: "nice", 430 | 35: "ftime", 431 | 36: "sync", 432 | 37: "kill", 433 | 38: "rename", 434 | 39: "mkdir", 435 | 40: "rmdir", 436 | 41: "dup", 437 | 42: "pipe", 438 | 43: "times", 439 | 44: "prof", 440 | 45: "brk", 441 | 46: "setgid", 442 | 47: "getgid", 443 | 48: "signal", 444 | 49: "geteuid", 445 | 50: "getegid", 446 | 51: "acct", 447 | 52: "umount2", 448 | 53: "lock", 449 | 54: "ioctl", 450 | 55: "fcntl", 451 | 56: "mpx", 452 | 57: "setpgid", 453 | 58: "ulimit", 454 | 59: "oldolduname", 455 | 60: "umask", 456 | 61: "chroot", 457 | 62: "ustat", 458 | 63: "dup2", 459 | 64: "getppid", 460 | 65: "getpgrp", 461 | 66: "setsid", 462 | 67: "sigaction", 463 | 68: "sgetmask", 464 | 69: "ssetmask", 465 | 70: "setreuid", 466 | 71: "setregid", 467 | 72: "sigsuspend", 468 | 73: "sigpending", 469 | 74: "sethostname", 470 | 75: "setrlimit", 471 | 76: "getrlimit", 472 | 77: "getrusage", 473 | 78: "gettimeofday", 474 | 79: "settimeofday", 475 | 80: "getgroups", 476 | 81: "setgroups", 477 | 82: "select", 478 | 83: "symlink", 479 | 84: "oldlstat", 480 | 85: "readlink", 481 | 86: "uselib", 482 | 87: "swapon", 483 | 88: "reboot", 484 | 89: "readdir", 485 | 90: "mmap", 486 | 91: "munmap", 487 | 92: "truncate", 488 | 93: "ftruncate", 489 | 94: "fchmod", 490 | 95: "fchown", 491 | 96: "getpriority", 492 | 97: "setpriority", 493 | 98: "profil", 494 | 99: "statfs", 495 | 100: "fstatfs", 496 | 101: "ioperm", 497 | 102: "socketcall", 498 | 103: "syslog", 499 | 104: "setitimer", 500 | 105: "getitimer", 501 | 106: "stat", 502 | 107: "lstat", 503 | 108: "fstat", 504 | 109: "olduname", 505 | 110: "iopl", 506 | 111: "vhangup", 507 | 112: "idle", 508 | 113: "vm86old", 509 | 114: "wait4", 510 | 115: "swapoff", 511 | 116: "sysinfo", 512 | 117: "ipc", 513 | 118: "fsync", 514 | 119: "sigreturn", 515 | 120: "clone", 516 | 121: "setdomainname", 517 | 122: "uname", 518 | 123: "modify_ldt", 519 | 124: "adjtimex", 520 | 125: "mprotect", 521 | 126: "sigprocmask", 522 | 127: "create_module", 523 | 128: "init_module", 524 | 129: "delete_module", 525 | 130: "get_kernel_syms", 526 | 131: "quotactl", 527 | 132: "getpgid", 528 | 133: "fchdir", 529 | 134: "bdflush", 530 | 135: "sysfs", 531 | 136: "personality", 532 | 137: "afs_syscall", 533 | 138: "setfsuid", 534 | 139: "setfsgid", 535 | 140: "_llseek", 536 | 141: "getdents", 537 | 142: "_newselect", 538 | 143: "flock", 539 | 144: "msync", 540 | 145: "readv", 541 | 146: "writev", 542 | 147: "getsid", 543 | 148: "fdatasync", 544 | 149: "_sysctl", 545 | 150: "mlock", 546 | 151: "munlock", 547 | 152: "mlockall", 548 | 153: "munlockall", 549 | 154: "sched_setparam", 550 | 155: "sched_getparam", 551 | 156: "sched_setscheduler", 552 | 157: "sched_getscheduler", 553 | 158: "sched_yield", 554 | 159: "sched_get_priority_max", 555 | 160: "sched_get_priority_min", 556 | 161: "sched_rr_get_interval", 557 | 162: "nanosleep", 558 | 163: "mremap", 559 | 164: "setresuid", 560 | 165: "getresuid", 561 | 166: "vm86", 562 | 167: "query_module", 563 | 168: "poll", 564 | 169: "nfsservctl", 565 | 170: "setresgid", 566 | 171: "getresgid", 567 | 172: "prctl", 568 | 173: "rt_sigreturn", 569 | 174: "rt_sigaction", 570 | 175: "rt_sigprocmask", 571 | 176: "rt_sigpending", 572 | 177: "rt_sigtimedwait", 573 | 178: "rt_sigqueueinfo", 574 | 179: "rt_sigsuspend", 575 | 180: "pread64", 576 | 181: "pwrite64", 577 | 182: "chown", 578 | 183: "getcwd", 579 | 184: "capget", 580 | 185: "capset", 581 | 186: "sigaltstack", 582 | 187: "sendfile", 583 | 188: "getpmsg", 584 | 189: "putpmsg", 585 | 190: "vfork", 586 | 191: "ugetrlimit", 587 | 192: "mmap2", 588 | 193: "truncate64", 589 | 194: "ftruncate64", 590 | 195: "stat64", 591 | 196: "lstat64", 592 | 197: "fstat64", 593 | 198: "lchown32", 594 | 199: "getuid32", 595 | 200: "getgid32", 596 | 201: "geteuid32", 597 | 202: "getegid32", 598 | 203: "setreuid32", 599 | 204: "setregid32", 600 | 205: "getgroups32", 601 | 206: "setgroups32", 602 | 207: "fchown32", 603 | 208: "setresuid32", 604 | 209: "getresuid32", 605 | 210: "setresgid32", 606 | 211: "getresgid32", 607 | 212: "chown32", 608 | 213: "setuid32", 609 | 214: "setgid32", 610 | 215: "setfsuid32", 611 | 216: "setfsgid32", 612 | 217: "pivot_root", 613 | 218: "mincore", 614 | 219: "madvise", 615 | 220: "getdents64", 616 | 221: "fcntl64", 617 | 224: "gettid", 618 | 225: "readahead", 619 | 226: "setxattr", 620 | 227: "lsetxattr", 621 | 228: "fsetxattr", 622 | 229: "getxattr", 623 | 230: "lgetxattr", 624 | 231: "fgetxattr", 625 | 232: "listxattr", 626 | 233: "llistxattr", 627 | 234: "flistxattr", 628 | 235: "removexattr", 629 | 236: "lremovexattr", 630 | 237: "fremovexattr", 631 | 238: "tkill", 632 | 239: "sendfile64", 633 | 240: "futex", 634 | 241: "sched_setaffinity", 635 | 242: "sched_getaffinity", 636 | 243: "set_thread_area", 637 | 244: "get_thread_area", 638 | 245: "io_setup", 639 | 246: "io_destroy", 640 | 247: "io_getevents", 641 | 248: "io_submit", 642 | 249: "io_cancel", 643 | 250: "fadvise64", 644 | 252: "exit_group", 645 | 253: "lookup_dcookie", 646 | 254: "epoll_create", 647 | 255: "epoll_ctl", 648 | 256: "epoll_wait", 649 | 257: "remap_file_pages", 650 | 258: "set_tid_address", 651 | 259: "timer_create", 652 | 260: "timer_settime", 653 | 261: "timer_gettime", 654 | 262: "timer_getoverrun", 655 | 263: "timer_delete", 656 | 264: "clock_settime", 657 | 265: "clock_gettime", 658 | 266: "clock_getres", 659 | 267: "clock_nanosleep", 660 | 268: "statfs64", 661 | 269: "fstatfs64", 662 | 270: "tgkill", 663 | 271: "utimes", 664 | 272: "fadvise64_64", 665 | 273: "vserver", 666 | 274: "mbind", 667 | 275: "get_mempolicy", 668 | 276: "set_mempolicy", 669 | 277: "mq_open", 670 | 278: "mq_unlink", 671 | 279: "mq_timedsend", 672 | 280: "mq_timedreceive", 673 | 281: "mq_notify", 674 | 282: "mq_getsetattr", 675 | 283: "kexec_load", 676 | 284: "waitid", 677 | 286: "add_key", 678 | 287: "request_key", 679 | 288: "keyctl", 680 | 289: "ioprio_set", 681 | 290: "ioprio_get", 682 | 291: "inotify_init", 683 | 292: "inotify_add_watch", 684 | 293: "inotify_rm_watch", 685 | 294: "migrate_pages", 686 | 295: "openat", 687 | 296: "mkdirat", 688 | 297: "mknodat", 689 | 298: "fchownat", 690 | 299: "futimesat", 691 | 300: "fstatat64", 692 | 301: "unlinkat", 693 | 302: "renameat", 694 | 303: "linkat", 695 | 304: "symlinkat", 696 | 305: "readlinkat", 697 | 306: "fchmodat", 698 | 307: "faccessat", 699 | 308: "pselect6", 700 | 309: "ppoll", 701 | 310: "unshare", 702 | 311: "set_robust_list", 703 | 312: "get_robust_list", 704 | 313: "splice", 705 | 314: "sync_file_range", 706 | 315: "tee", 707 | 316: "vmsplice", 708 | 317: "move_pages", 709 | 318: "getcpu", 710 | 319: "epoll_pwait", 711 | 320: "utimensat", 712 | 321: "signalfd", 713 | 322: "timerfd_create", 714 | 323: "eventfd", 715 | 324: "fallocate", 716 | 325: "timerfd_settime", 717 | 326: "timerfd_gettime", 718 | 327: "signalfd4", 719 | 328: "eventfd2", 720 | 329: "epoll_create1", 721 | 330: "dup3", 722 | 331: "pipe2", 723 | 332: "inotify_init1", 724 | 333: "preadv", 725 | 334: "pwritev", 726 | 335: "rt_tgsigqueueinfo", 727 | 336: "perf_event_open", 728 | 337: "recvmmsg", 729 | 338: "fanotify_init", 730 | 339: "fanotify_mark", 731 | 340: "prlimit64", 732 | 341: "name_to_handle_at", 733 | 342: "open_by_handle_at", 734 | 343: "clock_adjtime", 735 | 344: "syncfs", 736 | 345: "sendmmsg", 737 | 346: "setns", 738 | 347: "process_vm_readv", 739 | 348: "process_vm_writev", 740 | 349: "kcmp", 741 | 350: "finit_module", 742 | 351: "sched_setattr", 743 | 352: "sched_getattr", 744 | 353: "renameat2", 745 | 354: "seccomp", 746 | 355: "getrandom", 747 | 356: "memfd_create", 748 | 357: "bpf", 749 | 358: "execveat", 750 | 359: "socket", 751 | 360: "socketpair", 752 | 361: "bind", 753 | 362: "connect", 754 | 363: "listen", 755 | 364: "accept4", 756 | 365: "getsockopt", 757 | 366: "setsockopt", 758 | 367: "getsockname", 759 | 368: "getpeername", 760 | 369: "sendto", 761 | 370: "sendmsg", 762 | 371: "recvfrom", 763 | 372: "recvmsg", 764 | 373: "shutdown", 765 | 374: "userfaultfd", 766 | 375: "membarrier", 767 | 376: "mlock2", 768 | 377: "copy_file_range", 769 | 378: "preadv2", 770 | 379: "pwritev2", 771 | 380: "pkey_mprotect", 772 | 381: "pkey_alloc", 773 | 382: "pkey_free", 774 | 383: "statx", 775 | 384: "arch_prctl", 776 | } 777 | 778 | var WhitelistedSyscalls = []int{ 779 | SyscallToId["execve"], 780 | SyscallToId["ptrace"], 781 | SyscallToId["fork"], 782 | SyscallToId["vfork"], 783 | SyscallToId["clone"], 784 | SyscallToId["mknod"], 785 | SyscallToId["chroot"], 786 | SyscallToId["mount"], 787 | SyscallToId["umount"], 788 | SyscallToId["umount2"], 789 | SyscallToId["setuid"], 790 | SyscallToId["setgid"], 791 | SyscallToId["setresuid"], 792 | SyscallToId["setresgid"], 793 | SyscallToId["getuid"], 794 | SyscallToId["getgid"], 795 | SyscallToId["geteuid"], 796 | SyscallToId["getegid"], 797 | SyscallToId["kill"], 798 | SyscallToId["tkill"], 799 | SyscallToId["prctl"], 800 | SyscallToId["seccomp"], 801 | SyscallToId["unshare"], 802 | SyscallToId["setns"], 803 | SyscallToId["capset"], 804 | SyscallToId["capget"], 805 | SyscallToId["socket"], 806 | SyscallToId["bind"], 807 | SyscallToId["connect"], 808 | SyscallToId["listen"], 809 | SyscallToId["accept"], 810 | SyscallToId["shutdown"], 811 | SyscallToId["setsockopt"], 812 | SyscallToId["getsockopt"], 813 | SyscallToId["recvmsg"], 814 | SyscallToId["sendmsg"], 815 | SyscallToId["recvfrom"], 816 | SyscallToId["sendto"], 817 | SyscallToId["getrandom"], 818 | SyscallToId["mknodat"], 819 | SyscallToId["fchownat"], 820 | } 821 | -------------------------------------------------------------------------------- /internal/bpf/arch/arm.go: -------------------------------------------------------------------------------- 1 | // AUTOGENERATED FILE 2 | 3 | //go:build arm 4 | // +build arm 5 | 6 | package bpfarch 7 | 8 | const BpfProgramElf = bpfProgramName + "_arm.o" 9 | 10 | var SyscallToId = map[string]int{ 11 | "restart_syscall": 0, 12 | "exit": 1, 13 | "fork": 2, 14 | "read": 3, 15 | "write": 4, 16 | "open": 5, 17 | "close": 6, 18 | "creat": 8, 19 | "link": 9, 20 | "unlink": 10, 21 | "execve": 11, 22 | "chdir": 12, 23 | "mknod": 14, 24 | "chmod": 15, 25 | "lchown": 16, 26 | "lseek": 19, 27 | "getpid": 20, 28 | "mount": 21, 29 | "setuid": 23, 30 | "getuid": 24, 31 | "ptrace": 26, 32 | "pause": 29, 33 | "access": 33, 34 | "nice": 34, 35 | "sync": 36, 36 | "kill": 37, 37 | "rename": 38, 38 | "mkdir": 39, 39 | "rmdir": 40, 40 | "dup": 41, 41 | "pipe": 42, 42 | "times": 43, 43 | "brk": 45, 44 | "setgid": 46, 45 | "getgid": 47, 46 | "geteuid": 49, 47 | "getegid": 50, 48 | "acct": 51, 49 | "umount2": 52, 50 | "ioctl": 54, 51 | "fcntl": 55, 52 | "setpgid": 57, 53 | "umask": 60, 54 | "chroot": 61, 55 | "ustat": 62, 56 | "dup2": 63, 57 | "getppid": 64, 58 | "getpgrp": 65, 59 | "setsid": 66, 60 | "sigaction": 67, 61 | "setreuid": 70, 62 | "setregid": 71, 63 | "sigsuspend": 72, 64 | "sigpending": 73, 65 | "sethostname": 74, 66 | "setrlimit": 75, 67 | "getrusage": 77, 68 | "gettimeofday": 78, 69 | "settimeofday": 79, 70 | "getgroups": 80, 71 | "setgroups": 81, 72 | "symlink": 83, 73 | "readlink": 85, 74 | "uselib": 86, 75 | "swapon": 87, 76 | "reboot": 88, 77 | "munmap": 91, 78 | "truncate": 92, 79 | "ftruncate": 93, 80 | "fchmod": 94, 81 | "fchown": 95, 82 | "getpriority": 96, 83 | "setpriority": 97, 84 | "statfs": 99, 85 | "fstatfs": 100, 86 | "syslog": 103, 87 | "setitimer": 104, 88 | "getitimer": 105, 89 | "stat": 106, 90 | "lstat": 107, 91 | "fstat": 108, 92 | "vhangup": 111, 93 | "wait4": 114, 94 | "swapoff": 115, 95 | "sysinfo": 116, 96 | "fsync": 118, 97 | "sigreturn": 119, 98 | "clone": 120, 99 | "setdomainname": 121, 100 | "uname": 122, 101 | "adjtimex": 124, 102 | "mprotect": 125, 103 | "sigprocmask": 126, 104 | "init_module": 128, 105 | "delete_module": 129, 106 | "quotactl": 131, 107 | "getpgid": 132, 108 | "fchdir": 133, 109 | "bdflush": 134, 110 | "sysfs": 135, 111 | "personality": 136, 112 | "setfsuid": 138, 113 | "setfsgid": 139, 114 | "_llseek": 140, 115 | "getdents": 141, 116 | "flock": 143, 117 | "msync": 144, 118 | "readv": 145, 119 | "writev": 146, 120 | "getsid": 147, 121 | "fdatasync": 148, 122 | "mlock": 150, 123 | "munlock": 151, 124 | "mlockall": 152, 125 | "munlockall": 153, 126 | "sched_setparam": 154, 127 | "sched_getparam": 155, 128 | "sched_setscheduler": 156, 129 | "sched_getscheduler": 157, 130 | "sched_yield": 158, 131 | "sched_get_priority_max": 159, 132 | "sched_get_priority_min": 160, 133 | "sched_rr_get_interval": 161, 134 | "nanosleep": 162, 135 | "mremap": 163, 136 | "setresuid": 164, 137 | "getresuid": 165, 138 | "poll": 168, 139 | "nfsservctl": 169, 140 | "setresgid": 170, 141 | "getresgid": 171, 142 | "prctl": 172, 143 | "rt_sigreturn": 173, 144 | "rt_sigaction": 174, 145 | "rt_sigprocmask": 175, 146 | "rt_sigpending": 176, 147 | "rt_sigtimedwait": 177, 148 | "rt_sigqueueinfo": 178, 149 | "rt_sigsuspend": 179, 150 | "pread64": 180, 151 | "pwrite64": 181, 152 | "chown": 182, 153 | "getcwd": 183, 154 | "capget": 184, 155 | "capset": 185, 156 | "sigaltstack": 186, 157 | "sendfile": 187, 158 | "vfork": 190, 159 | "ugetrlimit": 191, 160 | "mmap2": 192, 161 | "truncate64": 193, 162 | "ftruncate64": 194, 163 | "stat64": 195, 164 | "lstat64": 196, 165 | "fstat64": 197, 166 | "lchown32": 198, 167 | "getuid32": 199, 168 | "getgid32": 200, 169 | "geteuid32": 201, 170 | "getegid32": 202, 171 | "setreuid32": 203, 172 | "setregid32": 204, 173 | "getgroups32": 205, 174 | "setgroups32": 206, 175 | "fchown32": 207, 176 | "setresuid32": 208, 177 | "getresuid32": 209, 178 | "setresgid32": 210, 179 | "getresgid32": 211, 180 | "chown32": 212, 181 | "setuid32": 213, 182 | "setgid32": 214, 183 | "setfsuid32": 215, 184 | "setfsgid32": 216, 185 | "getdents64": 217, 186 | "pivot_root": 218, 187 | "mincore": 219, 188 | "madvise": 220, 189 | "fcntl64": 221, 190 | "gettid": 224, 191 | "readahead": 225, 192 | "setxattr": 226, 193 | "lsetxattr": 227, 194 | "fsetxattr": 228, 195 | "getxattr": 229, 196 | "lgetxattr": 230, 197 | "fgetxattr": 231, 198 | "listxattr": 232, 199 | "llistxattr": 233, 200 | "flistxattr": 234, 201 | "removexattr": 235, 202 | "lremovexattr": 236, 203 | "fremovexattr": 237, 204 | "tkill": 238, 205 | "sendfile64": 239, 206 | "futex": 240, 207 | "sched_setaffinity": 241, 208 | "sched_getaffinity": 242, 209 | "io_setup": 243, 210 | "io_destroy": 244, 211 | "io_getevents": 245, 212 | "io_submit": 246, 213 | "io_cancel": 247, 214 | "exit_group": 248, 215 | "lookup_dcookie": 249, 216 | "epoll_create": 250, 217 | "epoll_ctl": 251, 218 | "epoll_wait": 252, 219 | "remap_file_pages": 253, 220 | "set_tid_address": 256, 221 | "timer_create": 257, 222 | "timer_settime": 258, 223 | "timer_gettime": 259, 224 | "timer_getoverrun": 260, 225 | "timer_delete": 261, 226 | "clock_settime": 262, 227 | "clock_gettime": 263, 228 | "clock_getres": 264, 229 | "clock_nanosleep": 265, 230 | "statfs64": 266, 231 | "fstatfs64": 267, 232 | "tgkill": 268, 233 | "utimes": 269, 234 | "arm_fadvise64_64": 270, 235 | "pciconfig_iobase": 271, 236 | "pciconfig_read": 272, 237 | "pciconfig_write": 273, 238 | "mq_open": 274, 239 | "mq_unlink": 275, 240 | "mq_timedsend": 276, 241 | "mq_timedreceive": 277, 242 | "mq_notify": 278, 243 | "mq_getsetattr": 279, 244 | "waitid": 280, 245 | "socket": 281, 246 | "bind": 282, 247 | "connect": 283, 248 | "listen": 284, 249 | "accept": 285, 250 | "getsockname": 286, 251 | "getpeername": 287, 252 | "socketpair": 288, 253 | "send": 289, 254 | "sendto": 290, 255 | "recv": 291, 256 | "recvfrom": 292, 257 | "shutdown": 293, 258 | "setsockopt": 294, 259 | "getsockopt": 295, 260 | "sendmsg": 296, 261 | "recvmsg": 297, 262 | "semop": 298, 263 | "semget": 299, 264 | "semctl": 300, 265 | "msgsnd": 301, 266 | "msgrcv": 302, 267 | "msgget": 303, 268 | "msgctl": 304, 269 | "shmat": 305, 270 | "shmdt": 306, 271 | "shmget": 307, 272 | "shmctl": 308, 273 | "add_key": 309, 274 | "request_key": 310, 275 | "keyctl": 311, 276 | "semtimedop": 312, 277 | "vserver": 313, 278 | "ioprio_set": 314, 279 | "ioprio_get": 315, 280 | "inotify_init": 316, 281 | "inotify_add_watch": 317, 282 | "inotify_rm_watch": 318, 283 | "mbind": 319, 284 | "get_mempolicy": 320, 285 | "set_mempolicy": 321, 286 | "openat": 322, 287 | "mkdirat": 323, 288 | "mknodat": 324, 289 | "fchownat": 325, 290 | "futimesat": 326, 291 | "fstatat64": 327, 292 | "unlinkat": 328, 293 | "renameat": 329, 294 | "linkat": 330, 295 | "symlinkat": 331, 296 | "readlinkat": 332, 297 | "fchmodat": 333, 298 | "faccessat": 334, 299 | "pselect6": 335, 300 | "ppoll": 336, 301 | "unshare": 337, 302 | "set_robust_list": 338, 303 | "get_robust_list": 339, 304 | "splice": 340, 305 | "sync_file_range2": 341, 306 | "tee": 342, 307 | "vmsplice": 343, 308 | "move_pages": 344, 309 | "getcpu": 345, 310 | "epoll_pwait": 346, 311 | "kexec_load": 347, 312 | "utimensat": 348, 313 | "signalfd": 349, 314 | "timerfd_create": 350, 315 | "eventfd": 351, 316 | "fallocate": 352, 317 | "timerfd_settime": 353, 318 | "timerfd_gettime": 354, 319 | "signalfd4": 355, 320 | "eventfd2": 356, 321 | "epoll_create1": 357, 322 | "dup3": 358, 323 | "pipe2": 359, 324 | "inotify_init1": 360, 325 | "preadv": 361, 326 | "pwritev": 362, 327 | "rt_tgsigqueueinfo": 363, 328 | "perf_event_open": 364, 329 | "recvmmsg": 365, 330 | "accept4": 366, 331 | "fanotify_init": 367, 332 | "fanotify_mark": 368, 333 | "prlimit64": 369, 334 | "name_to_handle_at": 370, 335 | "open_by_handle_at": 371, 336 | "clock_adjtime": 372, 337 | "syncfs": 373, 338 | "sendmmsg": 374, 339 | "setns": 375, 340 | "process_vm_readv": 376, 341 | "process_vm_writev": 377, 342 | "kcmp": 378, 343 | "finit_module": 379, 344 | "sched_setattr": 380, 345 | "sched_getattr": 381, 346 | "renameat2": 382, 347 | "seccomp": 383, 348 | "getrandom": 384, 349 | "memfd_create": 385, 350 | "bpf": 386, 351 | "execveat": 387, 352 | "userfaultfd": 388, 353 | "membarrier": 389, 354 | "mlock2": 390, 355 | "copy_file_range": 391, 356 | "preadv2": 392, 357 | "pwritev2": 393, 358 | "pkey_mprotect": 394, 359 | "pkey_alloc": 395, 360 | "pkey_free": 396, 361 | "statx": 397, 362 | "ARM_breakpoint": 983041, 363 | "ARM_cacheflush": 983042, 364 | "ARM_usr26": 983043, 365 | "ARM_usr32": 983044, 366 | "ARM_set_tls": 983045, 367 | } 368 | 369 | var IdToSyscall = map[int]string{ 370 | 0: "restart_syscall", 371 | 1: "exit", 372 | 2: "fork", 373 | 3: "read", 374 | 4: "write", 375 | 5: "open", 376 | 6: "close", 377 | 8: "creat", 378 | 9: "link", 379 | 10: "unlink", 380 | 11: "execve", 381 | 12: "chdir", 382 | 14: "mknod", 383 | 15: "chmod", 384 | 16: "lchown", 385 | 19: "lseek", 386 | 20: "getpid", 387 | 21: "mount", 388 | 23: "setuid", 389 | 24: "getuid", 390 | 26: "ptrace", 391 | 29: "pause", 392 | 33: "access", 393 | 34: "nice", 394 | 36: "sync", 395 | 37: "kill", 396 | 38: "rename", 397 | 39: "mkdir", 398 | 40: "rmdir", 399 | 41: "dup", 400 | 42: "pipe", 401 | 43: "times", 402 | 45: "brk", 403 | 46: "setgid", 404 | 47: "getgid", 405 | 49: "geteuid", 406 | 50: "getegid", 407 | 51: "acct", 408 | 52: "umount2", 409 | 54: "ioctl", 410 | 55: "fcntl", 411 | 57: "setpgid", 412 | 60: "umask", 413 | 61: "chroot", 414 | 62: "ustat", 415 | 63: "dup2", 416 | 64: "getppid", 417 | 65: "getpgrp", 418 | 66: "setsid", 419 | 67: "sigaction", 420 | 70: "setreuid", 421 | 71: "setregid", 422 | 72: "sigsuspend", 423 | 73: "sigpending", 424 | 74: "sethostname", 425 | 75: "setrlimit", 426 | 77: "getrusage", 427 | 78: "gettimeofday", 428 | 79: "settimeofday", 429 | 80: "getgroups", 430 | 81: "setgroups", 431 | 83: "symlink", 432 | 85: "readlink", 433 | 86: "uselib", 434 | 87: "swapon", 435 | 88: "reboot", 436 | 91: "munmap", 437 | 92: "truncate", 438 | 93: "ftruncate", 439 | 94: "fchmod", 440 | 95: "fchown", 441 | 96: "getpriority", 442 | 97: "setpriority", 443 | 99: "statfs", 444 | 100: "fstatfs", 445 | 103: "syslog", 446 | 104: "setitimer", 447 | 105: "getitimer", 448 | 106: "stat", 449 | 107: "lstat", 450 | 108: "fstat", 451 | 111: "vhangup", 452 | 114: "wait4", 453 | 115: "swapoff", 454 | 116: "sysinfo", 455 | 118: "fsync", 456 | 119: "sigreturn", 457 | 120: "clone", 458 | 121: "setdomainname", 459 | 122: "uname", 460 | 124: "adjtimex", 461 | 125: "mprotect", 462 | 126: "sigprocmask", 463 | 128: "init_module", 464 | 129: "delete_module", 465 | 131: "quotactl", 466 | 132: "getpgid", 467 | 133: "fchdir", 468 | 134: "bdflush", 469 | 135: "sysfs", 470 | 136: "personality", 471 | 138: "setfsuid", 472 | 139: "setfsgid", 473 | 140: "_llseek", 474 | 141: "getdents", 475 | 143: "flock", 476 | 144: "msync", 477 | 145: "readv", 478 | 146: "writev", 479 | 147: "getsid", 480 | 148: "fdatasync", 481 | 150: "mlock", 482 | 151: "munlock", 483 | 152: "mlockall", 484 | 153: "munlockall", 485 | 154: "sched_setparam", 486 | 155: "sched_getparam", 487 | 156: "sched_setscheduler", 488 | 157: "sched_getscheduler", 489 | 158: "sched_yield", 490 | 159: "sched_get_priority_max", 491 | 160: "sched_get_priority_min", 492 | 161: "sched_rr_get_interval", 493 | 162: "nanosleep", 494 | 163: "mremap", 495 | 164: "setresuid", 496 | 165: "getresuid", 497 | 168: "poll", 498 | 169: "nfsservctl", 499 | 170: "setresgid", 500 | 171: "getresgid", 501 | 172: "prctl", 502 | 173: "rt_sigreturn", 503 | 174: "rt_sigaction", 504 | 175: "rt_sigprocmask", 505 | 176: "rt_sigpending", 506 | 177: "rt_sigtimedwait", 507 | 178: "rt_sigqueueinfo", 508 | 179: "rt_sigsuspend", 509 | 180: "pread64", 510 | 181: "pwrite64", 511 | 182: "chown", 512 | 183: "getcwd", 513 | 184: "capget", 514 | 185: "capset", 515 | 186: "sigaltstack", 516 | 187: "sendfile", 517 | 190: "vfork", 518 | 191: "ugetrlimit", 519 | 192: "mmap2", 520 | 193: "truncate64", 521 | 194: "ftruncate64", 522 | 195: "stat64", 523 | 196: "lstat64", 524 | 197: "fstat64", 525 | 198: "lchown32", 526 | 199: "getuid32", 527 | 200: "getgid32", 528 | 201: "geteuid32", 529 | 202: "getegid32", 530 | 203: "setreuid32", 531 | 204: "setregid32", 532 | 205: "getgroups32", 533 | 206: "setgroups32", 534 | 207: "fchown32", 535 | 208: "setresuid32", 536 | 209: "getresuid32", 537 | 210: "setresgid32", 538 | 211: "getresgid32", 539 | 212: "chown32", 540 | 213: "setuid32", 541 | 214: "setgid32", 542 | 215: "setfsuid32", 543 | 216: "setfsgid32", 544 | 217: "getdents64", 545 | 218: "pivot_root", 546 | 219: "mincore", 547 | 220: "madvise", 548 | 221: "fcntl64", 549 | 224: "gettid", 550 | 225: "readahead", 551 | 226: "setxattr", 552 | 227: "lsetxattr", 553 | 228: "fsetxattr", 554 | 229: "getxattr", 555 | 230: "lgetxattr", 556 | 231: "fgetxattr", 557 | 232: "listxattr", 558 | 233: "llistxattr", 559 | 234: "flistxattr", 560 | 235: "removexattr", 561 | 236: "lremovexattr", 562 | 237: "fremovexattr", 563 | 238: "tkill", 564 | 239: "sendfile64", 565 | 240: "futex", 566 | 241: "sched_setaffinity", 567 | 242: "sched_getaffinity", 568 | 243: "io_setup", 569 | 244: "io_destroy", 570 | 245: "io_getevents", 571 | 246: "io_submit", 572 | 247: "io_cancel", 573 | 248: "exit_group", 574 | 249: "lookup_dcookie", 575 | 250: "epoll_create", 576 | 251: "epoll_ctl", 577 | 252: "epoll_wait", 578 | 253: "remap_file_pages", 579 | 256: "set_tid_address", 580 | 257: "timer_create", 581 | 258: "timer_settime", 582 | 259: "timer_gettime", 583 | 260: "timer_getoverrun", 584 | 261: "timer_delete", 585 | 262: "clock_settime", 586 | 263: "clock_gettime", 587 | 264: "clock_getres", 588 | 265: "clock_nanosleep", 589 | 266: "statfs64", 590 | 267: "fstatfs64", 591 | 268: "tgkill", 592 | 269: "utimes", 593 | 270: "arm_fadvise64_64", 594 | 271: "pciconfig_iobase", 595 | 272: "pciconfig_read", 596 | 273: "pciconfig_write", 597 | 274: "mq_open", 598 | 275: "mq_unlink", 599 | 276: "mq_timedsend", 600 | 277: "mq_timedreceive", 601 | 278: "mq_notify", 602 | 279: "mq_getsetattr", 603 | 280: "waitid", 604 | 281: "socket", 605 | 282: "bind", 606 | 283: "connect", 607 | 284: "listen", 608 | 285: "accept", 609 | 286: "getsockname", 610 | 287: "getpeername", 611 | 288: "socketpair", 612 | 289: "send", 613 | 290: "sendto", 614 | 291: "recv", 615 | 292: "recvfrom", 616 | 293: "shutdown", 617 | 294: "setsockopt", 618 | 295: "getsockopt", 619 | 296: "sendmsg", 620 | 297: "recvmsg", 621 | 298: "semop", 622 | 299: "semget", 623 | 300: "semctl", 624 | 301: "msgsnd", 625 | 302: "msgrcv", 626 | 303: "msgget", 627 | 304: "msgctl", 628 | 305: "shmat", 629 | 306: "shmdt", 630 | 307: "shmget", 631 | 308: "shmctl", 632 | 309: "add_key", 633 | 310: "request_key", 634 | 311: "keyctl", 635 | 312: "semtimedop", 636 | 313: "vserver", 637 | 314: "ioprio_set", 638 | 315: "ioprio_get", 639 | 316: "inotify_init", 640 | 317: "inotify_add_watch", 641 | 318: "inotify_rm_watch", 642 | 319: "mbind", 643 | 320: "get_mempolicy", 644 | 321: "set_mempolicy", 645 | 322: "openat", 646 | 323: "mkdirat", 647 | 324: "mknodat", 648 | 325: "fchownat", 649 | 326: "futimesat", 650 | 327: "fstatat64", 651 | 328: "unlinkat", 652 | 329: "renameat", 653 | 330: "linkat", 654 | 331: "symlinkat", 655 | 332: "readlinkat", 656 | 333: "fchmodat", 657 | 334: "faccessat", 658 | 335: "pselect6", 659 | 336: "ppoll", 660 | 337: "unshare", 661 | 338: "set_robust_list", 662 | 339: "get_robust_list", 663 | 340: "splice", 664 | 341: "sync_file_range2", 665 | 342: "tee", 666 | 343: "vmsplice", 667 | 344: "move_pages", 668 | 345: "getcpu", 669 | 346: "epoll_pwait", 670 | 347: "kexec_load", 671 | 348: "utimensat", 672 | 349: "signalfd", 673 | 350: "timerfd_create", 674 | 351: "eventfd", 675 | 352: "fallocate", 676 | 353: "timerfd_settime", 677 | 354: "timerfd_gettime", 678 | 355: "signalfd4", 679 | 356: "eventfd2", 680 | 357: "epoll_create1", 681 | 358: "dup3", 682 | 359: "pipe2", 683 | 360: "inotify_init1", 684 | 361: "preadv", 685 | 362: "pwritev", 686 | 363: "rt_tgsigqueueinfo", 687 | 364: "perf_event_open", 688 | 365: "recvmmsg", 689 | 366: "accept4", 690 | 367: "fanotify_init", 691 | 368: "fanotify_mark", 692 | 369: "prlimit64", 693 | 370: "name_to_handle_at", 694 | 371: "open_by_handle_at", 695 | 372: "clock_adjtime", 696 | 373: "syncfs", 697 | 374: "sendmmsg", 698 | 375: "setns", 699 | 376: "process_vm_readv", 700 | 377: "process_vm_writev", 701 | 378: "kcmp", 702 | 379: "finit_module", 703 | 380: "sched_setattr", 704 | 381: "sched_getattr", 705 | 382: "renameat2", 706 | 383: "seccomp", 707 | 384: "getrandom", 708 | 385: "memfd_create", 709 | 386: "bpf", 710 | 387: "execveat", 711 | 388: "userfaultfd", 712 | 389: "membarrier", 713 | 390: "mlock2", 714 | 391: "copy_file_range", 715 | 392: "preadv2", 716 | 393: "pwritev2", 717 | 394: "pkey_mprotect", 718 | 395: "pkey_alloc", 719 | 396: "pkey_free", 720 | 397: "statx", 721 | 983041: "ARM_breakpoint", 722 | 983042: "ARM_cacheflush", 723 | 983043: "ARM_usr26", 724 | 983044: "ARM_usr32", 725 | 983045: "ARM_set_tls", 726 | } 727 | 728 | var WhitelistedSyscalls = []int{ 729 | SyscallToId["restart_syscall"], 730 | SyscallToId["exit"], 731 | SyscallToId["fork"], 732 | SyscallToId["creat"], 733 | SyscallToId["link"], 734 | SyscallToId["unlink"], 735 | SyscallToId["execve"], 736 | SyscallToId["mknod"], 737 | SyscallToId["ptrace"], 738 | SyscallToId["setuid"], 739 | SyscallToId["getuid"], 740 | SyscallToId["setgid"], 741 | SyscallToId["getgid"], 742 | SyscallToId["seteuid"], 743 | SyscallToId["getegid"], 744 | SyscallToId["setpgid"], 745 | SyscallToId["setreuid"], 746 | SyscallToId["setregid"], 747 | SyscallToId["setresuid"], 748 | SyscallToId["getresuid"], 749 | SyscallToId["setresgid"], 750 | SyscallToId["getresgid"], 751 | SyscallToId["prctl"], 752 | SyscallToId["capget"], 753 | SyscallToId["capset"], 754 | SyscallToId["seccomp"], 755 | SyscallToId["setns"], 756 | SyscallToId["unshare"], 757 | SyscallToId["chroot"], 758 | SyscallToId["mount"], 759 | SyscallToId["umount2"], 760 | SyscallToId["pivot_root"], 761 | SyscallToId["clone"], 762 | SyscallToId["wait4"], 763 | SyscallToId["kill"], 764 | SyscallToId["nice"], 765 | SyscallToId["kill"], 766 | SyscallToId["tkill"], 767 | SyscallToId["tgkill"], 768 | SyscallToId["socket"], 769 | SyscallToId["bind"], 770 | SyscallToId["connect"], 771 | SyscallToId["listen"], 772 | SyscallToId["accept"], 773 | SyscallToId["accept4"], 774 | SyscallToId["getsockname"], 775 | SyscallToId["getpeername"], 776 | SyscallToId["socketpair"], 777 | SyscallToId["sendto"], 778 | SyscallToId["recvfrom"], 779 | SyscallToId["sendmsg"], 780 | SyscallToId["recvmsg"], 781 | SyscallToId["getsockopt"], 782 | SyscallToId["setsockopt"], 783 | SyscallToId["shutdown"], 784 | SyscallToId["sendmmsg"], 785 | SyscallToId["sethostname"], 786 | SyscallToId["setdomainname"], 787 | } 788 | --------------------------------------------------------------------------------