diff --git a/.gitignore b/.gitignore index 33a123a..44fcc7c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ main output/ vmlinux.h .vagrant/ +*.pcap diff --git a/chapter15/hide-incoming-traffic/go.mod b/chapter15/hide-incoming-traffic/go.mod index 1b57d34..a6af17e 100644 --- a/chapter15/hide-incoming-traffic/go.mod +++ b/chapter15/hide-incoming-traffic/go.mod @@ -1,4 +1,4 @@ -module github.com/mozillazg/cloud-native-security-with-ebpf/chapter11/hide-incoming-traffic +module github.com/mozillazg/cloud-native-security-with-ebpf/chapter15/hide-incoming-traffic go 1.18 diff --git a/chapter15/modify-incoming-traffic/go.mod b/chapter15/modify-incoming-traffic/go.mod index f2af538..3015275 100644 --- a/chapter15/modify-incoming-traffic/go.mod +++ b/chapter15/modify-incoming-traffic/go.mod @@ -1,4 +1,4 @@ -module github.com/mozillazg/cloud-native-security-with-ebpf/chapter11/modify-incoming-traffic +module github.com/mozillazg/cloud-native-security-with-ebpf/chapter15/modify-incoming-traffic go 1.18 diff --git a/chapter15/modify-outgoing-traffic/Makefile b/chapter15/modify-outgoing-traffic/Makefile new file mode 100644 index 0000000..ecf235e --- /dev/null +++ b/chapter15/modify-outgoing-traffic/Makefile @@ -0,0 +1,129 @@ +.ONESHELL: +SHELL = /bin/sh + +OUTPUT = ../output +LIBBPF = ../../libbpf + + +LIBBPF_SRC = $(abspath $(LIBBPF)/src) +LIBBPF_OBJ = $(abspath $(OUTPUT)/libbpf.a) + +CC = gcc +CLANG = clang + +ARCH := $(shell uname -m) +ARCH := $(subst x86_64,amd64,$(ARCH)) +GOARCH := $(ARCH) + +BPFTOOL = $(shell which bpftool || /bin/false) +BTFFILE = /sys/kernel/btf/vmlinux +DBGVMLINUX = /usr/lib/debug/boot/vmlinux-$(shell uname -r) +GIT = $(shell which git || /bin/false) +VMLINUXH = vmlinux.h + +# libbpf + +LIBBPF_OBJDIR = $(abspath ./$(OUTPUT)/libbpf) +LIBBPF_DESTDIR = $(abspath ./$(OUTPUT)) + +CFLAGS = -ggdb -gdwarf -O2 -Wall -fpie -Wno-unused-variable -Wno-unused-function +LDFLAGS = + +BPF_CFLAGS_STATIC = "-I$(abspath $(OUTPUT))" +BPF_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_OBJ)" + +CGO_CFLAGS_STATIC = "-I$(abspath $(OUTPUT))" +CGO_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_OBJ)" +CGO_EXTLDFLAGS_STATIC = '-w -extldflags "-static"' + +CGO_CFGLAGS_DYN = "-I. -I/usr/include/" +CGO_LDFLAGS_DYN = "-lelf -lz -lbpf" +CGO_EXTLDFLAGS_DYN = '-w' + +## program + +.PHONY: $(PROGRAM) +.PHONY: $(PROGRAM).bpf.c + +PROGRAM = main + +all: + $(MAKE) -C . $(PROGRAM) + sudo ./${PROGRAM} + +# vmlinux header file + +.PHONY: vmlinuxh +vmlinuxh: $(VMLINUXH) + +$(VMLINUXH): $(OUTPUT) +ifeq ($(wildcard $(BPFTOOL)),) + @echo "ERROR: could not find bpftool" + @exit 1 +endif + @if [ -f $(DBGVMLINUX) ]; then \ + echo "INFO: found dbg kernel, generating $(VMLINUXH) from $(DBGVMLINUX)"; \ + $(BPFTOOL) btf dump file $(DBGVMLINUX) format c > $(VMLINUXH); \ + fi + @if [ ! -f $(BTFFILE) ] && [ ! -f $(DBGVMLINUX) ]; then \ + echo "ERROR: kernel does not seem to support BTF"; \ + exit 1; \ + fi + @if [ ! -f $(VMLINUXH) ]; then \ + echo "INFO: generating $(VMLINUXH) from $(BTFFILE)"; \ + $(BPFTOOL) btf dump file $(BTFFILE) format c > $(VMLINUXH); \ + fi + +# static libbpf generation for the git submodule + +.PHONY: libbpf +libbpf: $(LIBBPF_OBJ) + +$(LIBBPF_OBJ): $(LIBBPF_SRC) $(wildcard $(LIBBPF_SRC)/*.[ch]) | $(OUTPUT)/libbpf + CC="$(CC)" CFLAGS="$(CFLAGS)" LD_FLAGS="$(LDFLAGS)" \ + $(MAKE) -C $(LIBBPF_SRC) \ + BUILD_STATIC_ONLY=1 \ + OBJDIR=$(LIBBPF_OBJDIR) \ + DESTDIR=$(LIBBPF_DESTDIR) \ + INCLUDEDIR= LIBDIR= UAPIDIR= prefix= libdir= install + +$(LIBBPF_SRC): +ifeq ($(wildcard $@), ) + echo "INFO: updating submodule 'libbpf'" + $(GIT) submodule update --init --recursive +endif + +# output dir + +$(OUTPUT): + mkdir -p $(OUTPUT) + +$(OUTPUT)/libbpf: + mkdir -p $(OUTPUT)/libbpf + +## program bpf dependency + +$(PROGRAM).bpf.o: $(PROGRAM).bpf.c $(PROGRAM).h | vmlinuxh + $(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_x86 -I. -I$(OUTPUT) -c $< -o $@ + +## GO example + +.PHONY: $(PROGRAM) + +$(PROGRAM): libbpf | $(PROGRAM).bpf.o + CC=$(CLANG) \ + CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \ + CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \ + GOARCH=$(GOARCH) \ + go build \ + -tags netgo -ldflags $(CGO_EXTLDFLAGS_STATIC) \ + -o $(PROGRAM) ./$(PROGRAM).go + +## clean + +clean: + $(MAKE) -C $(LIBBPF_SRC) clean + rm -rf $(OUTPUT) + rm -rf $(VMLINUXH) + rm -rf $(PROGRAM) + rm -rf $(PROGRAM).bpf.o $(PROGRAM).o diff --git a/chapter15/modify-outgoing-traffic/go.mod b/chapter15/modify-outgoing-traffic/go.mod new file mode 100644 index 0000000..1a1ade8 --- /dev/null +++ b/chapter15/modify-outgoing-traffic/go.mod @@ -0,0 +1,5 @@ +module github.com/mozillazg/cloud-native-security-with-ebpf/chapter15/modify-outgoing-traffic + +go 1.18 + +require github.com/aquasecurity/libbpfgo v0.4.5-libbpf-1.0.1 diff --git a/chapter15/modify-outgoing-traffic/go.sum b/chapter15/modify-outgoing-traffic/go.sum new file mode 100644 index 0000000..d46e879 --- /dev/null +++ b/chapter15/modify-outgoing-traffic/go.sum @@ -0,0 +1,2 @@ +github.com/aquasecurity/libbpfgo v0.4.5-libbpf-1.0.1 h1:Et7WT8CEpaO03v7FIVk85GMRRbwjF7sgoBgQhH5T30k= +github.com/aquasecurity/libbpfgo v0.4.5-libbpf-1.0.1/go.mod h1:v+Nk+v6BtHLfdT4kVdsp+fYt4AeUa3cIG2P0y+nBuuY= diff --git a/chapter15/modify-outgoing-traffic/main.bpf.c b/chapter15/modify-outgoing-traffic/main.bpf.c new file mode 100644 index 0000000..9b4b037 --- /dev/null +++ b/chapter15/modify-outgoing-traffic/main.bpf.c @@ -0,0 +1,300 @@ +#include "vmlinux.h" +#include +#include +#include +#include +#include "main.h" + +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(u32)); + __uint(value_size, sizeof(u32)); +} events SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} modify_map SEC(".maps"); + + +SEC("tc") +int on_egress(struct __sk_buff *skb) { + int target_port = 8080; + + // 通过指针操作解析数据包 + void *data_end = (void *)(__u64)skb->data_end; + void *data = (void *)(__u64)skb->data; + + // 从 IP 首部中过滤协议类型,只处理 TCP 协议 + struct iphdr *ip_hdr = data + ETH_HLEN; + if ((void *)ip_hdr + sizeof(struct iphdr) > data_end) { + return TC_ACT_UNSPEC; + } + if (ip_hdr->protocol != IPPROTO_TCP) { + return TC_ACT_UNSPEC; + } + + // TCP 协议数据过滤 + struct tcphdr *tcp_hdr = (void *)ip_hdr + sizeof(struct iphdr); + if ((void *)tcp_hdr + sizeof(struct tcphdr) > data_end) { + return TC_ACT_UNSPEC; + } +// if (tcp_hdr->dest != bpf_htons(target_port)) { +// return TC_ACT_UNSPEC; +// } + + char replace[] = "GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nUser-Agent: curl/7.81.0\r\n"; + int replace_size = 25; + char *payload = (void *)tcp_hdr + tcp_hdr->doff * 4; + unsigned int payload_size = bpf_htons(ip_hdr->tot_len) - (tcp_hdr->doff * 4) - sizeof(struct iphdr); +// if (payload_size < 25) { +// return TC_ACT_UNSPEC; +// } + + + int zero = 0; + if (bpf_map_lookup_elem(&modify_map, &zero)) { + bpf_printk("exist"); + return TC_ACT_UNSPEC; + } + bpf_map_update_elem(&modify_map, &zero, &zero, BPF_ANY); + bpf_printk("update"); + + char content[100]; + bpf_probe_read_kernel(&content, sizeof(content), payload); + bpf_printk("tcp: payload: %s", content); + char new_payload[64]; + __builtin_memcpy(new_payload, replace, 64); + +// int offset = ETH_HLEN + sizeof(struct iphdr) + tcp_hdr->doff * 4; +// bpf_skb_store_bytes(skb, offset, &replace, sizeof(replace), BPF_F_RECOMPUTE_CSUM); + +// bpf_skb_pull_data(skb, 0); +// bpf_printk("%x", ip_hdr->daddr); + + u32 old_dest_addr = ip_hdr->daddr; + u16 old_dest_port = tcp_hdr->dest; + u32 new_dest_addr = 0x100007f; + u32 dest_addr_offset = ETH_HLEN + offsetof(struct iphdr, daddr); + u32 ip_checksum_offset = ETH_HLEN + offsetof(struct iphdr, check); + + bpf_skb_pull_data(skb, 0); + + int ret = bpf_l3_csum_replace(skb, ip_checksum_offset, old_dest_addr, new_dest_addr, sizeof(u32)); + if (ret < 0) { + bpf_printk("bpf_l3_csum_replace failed: %d", ret); + return TC_ACT_UNSPEC; + } + ret = bpf_skb_store_bytes(skb, dest_addr_offset, &new_dest_addr, sizeof(u32), 0); + if (ret < 0) { + bpf_printk("replace dest addr failed: %d", ret); + return TC_ACT_UNSPEC; + } + + u32 increment_len = sizeof(char)*64; + u16 new_dest_port = bpf_htons(9090); + u32 dest_port_offset = ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, dest); + u32 tcp_checksum_offset = ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, check); + + ret = bpf_l4_csum_replace(skb, tcp_checksum_offset, old_dest_port, new_dest_port, sizeof(u16)); + if (ret < 0) { + bpf_printk("bpf_l4_csum_replace failed: %d", ret); + return TC_ACT_UNSPEC; + } + ret = bpf_skb_store_bytes(skb, dest_port_offset, &new_dest_port, sizeof(u16), 0); + if (ret < 0) { + bpf_printk("replace dest port failed: %d", ret); + return TC_ACT_UNSPEC; + } + + ret = bpf_skb_change_tail(skb, skb->len+increment_len, 0); + if (ret < 0) { + bpf_printk("bpf_skb_change_tail failed: %d", ret); + return TC_ACT_UNSPEC; + } + ret = bpf_skb_pull_data(skb, 0); + if (ret < 0) { + bpf_printk("bpf_skb_pull_data failed: %d", ret); + return TC_ACT_UNSPEC; + } + + data = (void *)(long)skb->data; + data_end = (void *)(long)skb->data_end; + // 从 IP 首部中过滤协议类型,只处理 TCP 协议 + ip_hdr = data + ETH_HLEN; + if ((void *)ip_hdr + sizeof(struct iphdr) > data_end) { + return TC_ACT_UNSPEC; + } + if (ip_hdr->protocol != IPPROTO_TCP) { + return TC_ACT_UNSPEC; + } + // TCP 协议数据过滤 + tcp_hdr = (void *)ip_hdr + sizeof(struct iphdr); + if ((void *)tcp_hdr + sizeof(struct tcphdr) > data_end) { + return TC_ACT_UNSPEC; + } + payload_size = bpf_htons(ip_hdr->tot_len) - (tcp_hdr->doff * 4) - sizeof(struct iphdr); + payload = data_end - payload_size; + if(payload_size>=sizeof(char)*64){ + return TC_ACT_OK; + } + + u32 offset = skb->len-payload_size-increment_len; +// if(increment_len>skb->data_end-skb->data){ +// return TC_ACT_OK; +// } + if(data + increment_len > data_end){ + return TC_ACT_OK; + } + + //Simple strlen + u32 payload_char_len = str_len(new_payload, 64); + if(payload_char_len>=increment_len|| payload_char_len<=0){ + return TC_ACT_OK; + } + + bpf_printk("New payload offset %i, writing %i bytes\n", offset, payload_char_len); + ret = bpf_skb_store_bytes(skb, offset, new_payload, payload_char_len, 0); + if (ret < 0) { + bpf_printk("Failed to overwrite payload: %d\n", ret); + return TC_ACT_OK; + } + + data = (void *)(__u64)skb->data; + data_end = (void *)(__u64)skb->data_end; + +// eth = data; +// if ((void *)eth + sizeof(struct ethhdr) > data_end){ +// bpf_printk("ETH\n"); +// return TC_ACT_OK; +// } + ip_hdr = (struct iphdr*)(data + sizeof(struct ethhdr)); + if ((void *)ip_hdr + sizeof(struct iphdr) > data_end){ + bpf_printk("IP CHECK, ip: %llx, data: %llx, datalen: %llx\n", ip_hdr, data, data_end); + return TC_ACT_OK; + } + tcp_hdr = (struct tcphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr)); + if ((void *)tcp_hdr + sizeof(struct tcphdr) > data_end){ + bpf_printk("TCP CHECK\n"); + return TC_ACT_OK; + } + + //Fixing IP checksum + //bpf_printk("Old value %x, new value %x\n", htons(ip->tot_len), htons(ntohs(ip->tot_len)+increment_len)); + u32 offset_ip_tot_len = offsetof(struct iphdr, tot_len)+ sizeof(struct ethhdr); + u16 new_tot_len = bpf_htons(bpf_ntohs(ip_hdr->tot_len)+increment_len); + ret = bpf_l3_csum_replace(skb, ip_checksum_offset, (ip_hdr->tot_len), new_tot_len, sizeof(__u16)); + if (ret < 0) { + bpf_printk("Failed to recompute l3 checksum: %d\n", ret); + return TC_ACT_OK; + } + bpf_printk("New ip tot len: %i\n", bpf_ntohs(new_tot_len)); + ret = bpf_skb_store_bytes(skb, offset_ip_tot_len, &new_tot_len, sizeof(__u16), 0); + if (ret < 0) { + bpf_printk("Failed to overwrite ip total len: %d\n", ret); + return TC_ACT_OK; + } + + bpf_printk("Finished packet hijacking routine\n"); + + return TC_ACT_OK; +} + + +SEC("xdp") +int handle_xdp(struct xdp_md *ctx) { + // GET /healthz HTTP/1.1\r\n + // Host: 127.0.0.1:8080\r\n + // User-Agent: curl/7.81.0 cmd:test\r\n + // Accept: */*\r\n + char keyword[] = "GET /healthz HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nUser-Agent: curl/7.81.0 cmd:"; + int keyword_size = 73; + char cmd_len = 20; + char replace[] = "GET /healthz HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nUser-Agent: curl/7.81.0\r\nCache-Control: no-cache"; + char replace_size = 93; +// char keyword[] = "!!!CMD:"; +// int keyword_size = 7; + int target_port = 9090; + + // 通过指针操作解析数据包 + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + + // 从 IP 首部中过滤协议类型,只处理 TCP 协议 + struct iphdr *ip_hdr = data + ETH_HLEN; + if ((void *)ip_hdr + sizeof(struct iphdr) > data_end) { + return XDP_PASS; + } + if (ip_hdr->protocol != IPPROTO_TCP) { + return XDP_PASS; + } + + // TCP 协议数据过滤 + struct tcphdr *tcp_hdr = (void *)ip_hdr + sizeof(struct iphdr); + if ((void *)tcp_hdr + sizeof(struct tcphdr) > data_end) { + return XDP_PASS; + } + if (tcp_hdr->dest != bpf_htons(target_port)) { + return XDP_PASS; + } + + // 过滤关键字 + char *payload = (void *)tcp_hdr + tcp_hdr->doff * 4; + unsigned int payload_size = bpf_htons(ip_hdr->tot_len) - (tcp_hdr->doff * 4) - sizeof(struct iphdr); +// if (payload_size < keyword_size + cmd_len) { +// return XDP_PASS; +// } +// if ((void *)payload + keyword_size + cmd_len > data_end) { +// return XDP_PASS; +// } +// if ((void *)payload + replace_size > data_end) { +// return XDP_PASS; +// } +// if (!str_eq(payload, keyword, keyword_size)) { +// return XDP_PASS; +// } +// +// int zero = 0; +// struct event_t *event; +// event = bpf_map_lookup_elem(&tmp_storage, &zero); +// if (!event) { +// return XDP_PASS; +// } +// +// event->src_addr = ip_hdr->saddr; +// event->dest_addr = ip_hdr->daddr; +// event->src_port = bpf_ntohs(tcp_hdr->source); +// event->dest_port = bpf_ntohs(tcp_hdr->dest); +// +// bpf_probe_read_kernel(&event->payload, sizeof(event->payload), payload); + +// +//// bpf_printk("tcp: %x:%d ->", event->src_addr, event->src_port); +//// bpf_printk("tcp: %x:%d ", event->dest_addr, event->dest_port); +//// bpf_printk("tcp: payload: %s", event->payload); + +// +// bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event)); +// +// // 更新数据包 +//#pragma unroll +// for (int i = 0; i < replace_size; i++) { +// payload[i] = replace[i]; +// } +// + bpf_printk("xdp xx: %d", tcp_hdr->syn); + if (tcp_hdr->syn == 1) { + char content[64]; + bpf_probe_read_kernel(&content, sizeof(content), payload); + bpf_printk("xdp: payload: %s", content); + bpf_printk("xdp seq: %d", tcp_hdr->seq); + return XDP_PASS; + } + + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/chapter15/modify-outgoing-traffic/main.go b/chapter15/modify-outgoing-traffic/main.go new file mode 100644 index 0000000..baa2576 --- /dev/null +++ b/chapter15/modify-outgoing-traffic/main.go @@ -0,0 +1,144 @@ +package main + +import ( + "bytes" + "context" + "encoding/binary" + "log" + "net" + "os" + "os/signal" + "syscall" + + bpf "github.com/aquasecurity/libbpfgo" +) + +type Event struct { + IsIngress uint32 + SrcAddr uint32 + DstAddr uint32 + Type uint8 + Code uint8 +} + +func (e Event) Source() string { + if e.IsIngress == 1 { + return "ingress" + } + return "egress" +} + +func parseEvent(data []byte) (*Event, error) { + var event Event + err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event) + if err != nil { + return nil, err + } + return &event, nil +} + +func uint32ToIpV4(n uint32) net.IP { + ip := make(net.IP, 4) + binary.LittleEndian.PutUint32(ip, n) + return ip +} + +type BPFFunc struct { + FuncName string + Type bpf.TcAttachPoint +} + +func main() { + interfaceName := "lo" + if len(os.Args) > 1 { + interfaceName = os.Args[1] + } + var err error + defer func() { + if err != nil { + log.Fatalf("%+v", err) + } + }() + + bpfModule, err := bpf.NewModuleFromFile("main.bpf.o") + if err != nil { + return + } + defer bpfModule.Close() + if err = bpfModule.BPFLoadObject(); err != nil { + return + } + + for _, f := range []BPFFunc{ +// {"on_ingress", bpf.BPFTcIngress}, + {"on_egress", bpf.BPFTcEgress}, + } { + hook := bpfModule.TcHookInit() + defer hook.Destroy() + if err = hook.SetInterfaceByName(interfaceName); err != nil { + return + } + hook.SetAttachPoint(f.Type) + if err = hook.Create(); err != nil { + if errno, ok := err.(syscall.Errno); ok && errno != syscall.EEXIST { + return + } + } + prog, e := bpfModule.GetProgram(f.FuncName) + if e != nil { + err = e + return + } + tcOpts := bpf.TcOpts{ProgFd: prog.FileDescriptor()} + if err = hook.Attach(&tcOpts); err != nil { + return + } + defer hook.Detach(&tcOpts) + } + prog, err := bpfModule.GetProgram("handle_xdp") + if err != nil { + return + } + link, err := prog.AttachXDP(interfaceName) + if err != nil { + return + } + defer link.Destroy() + + log.Println("tracing...") + eventsChannel := make(chan []byte) + lostChannel := make(chan uint64) + pb, err := bpfModule.InitPerfBuf("events", eventsChannel, lostChannel, 1024) + if err != nil { + return + } + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + + pb.Start() + defer func() { + pb.Stop() + pb.Close() + stop() + }() + +loop: + for { + select { + case data := <-eventsChannel: + event, e := parseEvent(data) + if e != nil { + err = e + return + } else { + log.Printf("[ICMP] [%s] %s -> %s type: %d code: %d", + event.Source(), uint32ToIpV4(event.SrcAddr), uint32ToIpV4(event.DstAddr), + event.Type, event.Code) + } + case n := <-lostChannel: + log.Printf("lost %d events", n) + case <-ctx.Done(): + break loop + } + } + log.Println("bye bye~") +} diff --git a/chapter15/modify-outgoing-traffic/main.h b/chapter15/modify-outgoing-traffic/main.h new file mode 100644 index 0000000..d19a774 --- /dev/null +++ b/chapter15/modify-outgoing-traffic/main.h @@ -0,0 +1,42 @@ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_HLEN 14 /* Total octets in header. */ + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_SHOT 2 +#define TC_ACT_STOLEN 4 +#define TC_ACT_REDIRECT 7 + + +struct event_t { + u32 is_ingress; + u32 src_addr; + u32 dst_addr; + u8 type; + u8 code; +}; + + +static __always_inline bool str_eq(const char *a, const char *b, int len) +{ +#pragma unroll + for (int i = 0; i < len; i++) { + if (a[i] != b[i]) + return false; + if (a[i] == '\0') + break; + } + return true; +} + +static __always_inline int str_len(const char *s, int max_len) +{ +#pragma unroll + for (int i = 0; i < max_len; i++) { + if (s[i] == '\0') + return i; + } + if (s[max_len - 1] != '\0') + return max_len; + return 0; +} \ No newline at end of file diff --git a/chapter15/read-file/go.mod b/chapter15/read-file/go.mod index 3758c35..ee42ca5 100644 --- a/chapter15/read-file/go.mod +++ b/chapter15/read-file/go.mod @@ -1,4 +1,4 @@ -module github.com/mozillazg/cloud-native-security-with-ebpf/chapter15/add-sudo +module github.com/mozillazg/cloud-native-security-with-ebpf/chapter15/read-file go 1.18