Browse Source

Feature #TASK_QT-18250 header2

Carl 8 months ago
parent
commit
304403947a

+ 19 - 0
ebpftracer/ebpf/l7/apm_trace.c

@@ -70,6 +70,13 @@ struct {
 	__uint(max_entries, 10240);
 } pid_of_connection_ptr_maps SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__uint(key_size, sizeof(__u16));
+	__uint(value_size, sizeof(__u8));
+	__uint(max_entries, 64);
+} l4_header_code_types SEC(".maps");
+
 #define MAX_LEN 1022
 #define L7_IOVEC_BUF_SIZE 1024
 #define MAX_L7_IOVEC_BUF_SIZE 10240
@@ -718,4 +725,16 @@ static __always_inline  char code_type_to_code(__u16 code_type) {
 		default:
 			return '0'; // unknown / fallback
 	}
+}
+
+// 假定已有:
+// struct ebpf_proc_info { __u16 code_type; /* ... */ };
+// BPF map 已声明为 proc_info_map
+
+static __always_inline int mk_header_in_sk_msg(__u16 code_type) {
+	/* 在 allowed_code_types 中查找 */
+	__u8 *p = bpf_map_lookup_elem(&l4_header_code_types, &code_type);
+	if (p && *p)
+		return 1;
+	return 0;
 }

+ 58 - 55
ebpftracer/ebpf/l7/l7.c

@@ -1432,11 +1432,11 @@ int sockops_cb(struct bpf_sock_ops *skops) {
 	// 将socket添加到sockhash map
 	__u32 cookie = bpf_get_socket_cookie(skops);
 	bpf_sock_hash_update(skops, &sockhash, &tuple, BPF_ANY);
-	
+
 	// 同时将socket添加到sockmap(用于sk_msg程序)
 	bpf_sock_map_update(skops, &sk_msg_map, &cookie, BPF_ANY);
 
-	bpf_printk("sockops: added socket to sockhash and sockmap, cookie=%u\n", cookie);
+//	bpf_printk("sockops: added socket to sockhash and sockmap, cookie=%u\n", cookie);
 
 	return 0;
 }
@@ -1445,58 +1445,58 @@ int sockops_cb(struct bpf_sock_ops *skops) {
 SEC("cgroup/skb")
 int http_request_handler(struct __sk_buff *skb) {
 	// 检查数据包长度
-	if (skb->len < 4) {
-		return 1; // 允许通过
-	}
-	
-	// 读取前几个字节来检查是否是HTTP请求
-	char buf[100] = {};
-	if (bpf_skb_load_bytes(skb, 0, buf, 100) < 0) {
-		return 1; // 允许通过
-	}
-
-
-	// 跳过IP头部(20字节)和TCP头部(20字节),直接读取应用层数据
-	// IP头部长度 = (buf[0] & 0x0F) * 4 = 5 * 4 = 20字节
-	// TCP头部长度 = (buf[32] >> 4) * 4,但通常也是20字节
-	int ip_header_len = (buf[0] & 0x0F) * 4;
-	int tcp_header_len = 20; // 通常TCP头部是20字节
-	int app_data_offset = ip_header_len + tcp_header_len;
-	
-	// 检查是否有足够的应用层数据
-	if (skb->len < app_data_offset + 4) {
-		return 1; // 允许通过
-	}
-	
-	// 读取应用层数据的前几个字节
-	char app_data[100] = {};
-	if (bpf_skb_load_bytes(skb, app_data_offset, app_data, 100) < 0) {
-		return 1; // 允许通过
-	}
-
-	// 检查是否是HTTP请求
-	if ((app_data[0] == 'G' && app_data[1] == 'E' && app_data[2] == 'T' && app_data[3] == ' ') ||
-	    (app_data[0] == 'P' && app_data[1] == 'O' && app_data[2] == 'S' && app_data[3] == 'T') ||
-	    (app_data[0] == 'P' && app_data[1] == 'U' && app_data[2] == 'T' && app_data[3] == ' ') ||
-	    (app_data[0] == 'D' && app_data[1] == 'E' && app_data[2] == 'L' && app_data[3] == 'E') ||
-	    (app_data[0] == 'H' && app_data[1] == 'E' && app_data[2] == 'A' && app_data[3] == 'D') ||
-	    (app_data[0] == 'O' && app_data[1] == 'P' && app_data[2] == 'T' && app_data[3] == 'I')) {
-		
-//		bpf_printk("=== HTTP REQUEST FOUND ===\n");
-//		bpf_printk("IP header len: %d, TCP header len: %d\n", ip_header_len, tcp_header_len);
-//		bpf_printk("App data offset: %d\n", app_data_offset);
-//		bpf_printk("Content: %s\n", app_data);
-//		bpf_printk("=== END HTTP REQUEST ===\n");
-		
-		// 标记这个socket需要修改HTTP请求
-		// 通过http_modify_flags map传递信息给stream_verdict程序
-		__u32 cookie = bpf_get_socket_cookie(skb);
-		__u32 flag = 1; // 标记需要修改
-		if (bpf_map_update_elem(&http_modify_flags, &cookie, &flag, BPF_ANY) == 0) {
-			bpf_printk("Marked socket %u for HTTP request modification\n", cookie);
-		}
-	}
-	
+//	if (skb->len < 4) {
+//		return 1; // 允许通过
+//	}
+//
+//	// 读取前几个字节来检查是否是HTTP请求
+//	char buf[100] = {};
+//	if (bpf_skb_load_bytes(skb, 0, buf, 100) < 0) {
+//		return 1; // 允许通过
+//	}
+//
+//
+//	// 跳过IP头部(20字节)和TCP头部(20字节),直接读取应用层数据
+//	// IP头部长度 = (buf[0] & 0x0F) * 4 = 5 * 4 = 20字节
+//	// TCP头部长度 = (buf[32] >> 4) * 4,但通常也是20字节
+//	int ip_header_len = (buf[0] & 0x0F) * 4;
+//	int tcp_header_len = 20; // 通常TCP头部是20字节
+//	int app_data_offset = ip_header_len + tcp_header_len;
+//
+//	// 检查是否有足够的应用层数据
+//	if (skb->len < app_data_offset + 4) {
+//		return 1; // 允许通过
+//	}
+//
+//	// 读取应用层数据的前几个字节
+//	char app_data[100] = {};
+//	if (bpf_skb_load_bytes(skb, app_data_offset, app_data, 100) < 0) {
+//		return 1; // 允许通过
+//	}
+//
+//	// 检查是否是HTTP请求
+//	if ((app_data[0] == 'G' && app_data[1] == 'E' && app_data[2] == 'T' && app_data[3] == ' ') ||
+//	    (app_data[0] == 'P' && app_data[1] == 'O' && app_data[2] == 'S' && app_data[3] == 'T') ||
+//	    (app_data[0] == 'P' && app_data[1] == 'U' && app_data[2] == 'T' && app_data[3] == ' ') ||
+//	    (app_data[0] == 'D' && app_data[1] == 'E' && app_data[2] == 'L' && app_data[3] == 'E') ||
+//	    (app_data[0] == 'H' && app_data[1] == 'E' && app_data[2] == 'A' && app_data[3] == 'D') ||
+//	    (app_data[0] == 'O' && app_data[1] == 'P' && app_data[2] == 'T' && app_data[3] == 'I')) {
+//
+////		bpf_printk("=== HTTP REQUEST FOUND ===\n");
+////		bpf_printk("IP header len: %d, TCP header len: %d\n", ip_header_len, tcp_header_len);
+////		bpf_printk("App data offset: %d\n", app_data_offset);
+////		bpf_printk("Content: %s\n", app_data);
+////		bpf_printk("=== END HTTP REQUEST ===\n");
+//
+//		// 标记这个socket需要修改HTTP请求
+//		// 通过http_modify_flags map传递信息给stream_verdict程序
+//		__u32 cookie = bpf_get_socket_cookie(skb);
+//		__u32 flag = 1; // 标记需要修改
+//		if (bpf_map_update_elem(&http_modify_flags, &cookie, &flag, BPF_ANY) == 0) {
+//			bpf_printk("Marked socket %u for HTTP request modification\n", cookie);
+//		}
+//	}
+//
 	return 1; // 允许数据包通过
 }
 
@@ -1514,13 +1514,16 @@ int sk_msg_handler(struct sk_msg_md *msg)
 		return SK_PASS;
 	}
 
-	// todo 进程过滤
 	__u32 tgid = (__u32) (bpf_get_current_pid_tgid() >> 32);
 	struct ebpf_proc_info *proc_info = bpf_map_lookup_elem(&proc_info_map, &tgid);
 	if (!proc_info) {
 		return SK_PASS;
 	}
 
+	if (!mk_header_in_sk_msg(proc_info->code_type)) {
+//		bpf_printk("not allowd");
+		return SK_PASS;
+	}
 
 	__u32 max_buf = msg->size < MAX_L7_IOVEC_BUF_SIZE ? msg->size : MAX_L7_IOVEC_BUF_SIZE;
 

+ 3 - 2
ebpftracer/ebpf/utrace/java/net/server.probe.bpf.c

@@ -85,11 +85,12 @@ static __inline u32 get_http_header_offset(const char *data, u32 offset, u32 len
 static __inline u32 has_cw_header(const char *data)
 {
 	// cw header 查询
-	long cw_header_native = 0x6361727477630a0dLL; // 小端序下的 "\r\ncwtrac" {0x0d,0x0a,0x63,0x77,0x74,0x72,0x61,0x63}
+	long cw_header_native_lo = 0x6361727477630a0dLL; // 小端序下的 "\r\ncwtrac" {0x0d,0x0a,0x63,0x77,0x74,0x72,0x61,0x63}
+	long cw_header_native_up = 0x6361727477430a0dLL; // 小端序下的 "\r\nCwtrac" {0x0d,0x0a,0x43,0x77,0x74,0x72,0x61,0x63}
 #pragma clang loop unroll(full)
 	for (u32 i = 0; i < 500 - 8; i++) {
 		long tmp_data = *(long long *) (data + i);
-		if (tmp_data == cw_header_native) {
+		if (tmp_data == cw_header_native_lo || tmp_data == cw_header_native_up) {
 			return i+11;
 		}
 	}

+ 20 - 7
ebpftracer/tracer/btf_vmlinux.go

@@ -84,15 +84,28 @@ func bpf_table_pre_set_value(collectionSpec *ebpf.CollectionSpec, opts *ebpf.Col
 }
 
 func bpf_table_set_value(collection *ebpf.Collection, mapName string, key uint32, data any) (int, error) {
-	m, ok := collection.Maps[mapName]
-	//for s, m2 := range collection.Maps {
-	//	fmt.Println(s, m2.String())
+	//m, ok := collection.Maps[mapName]
+	////for s, m2 := range collection.Maps {
+	////	fmt.Println(s, m2.String())
+	////}
+	////fmt.Println("bpf_table_set_value", m, mapName, data)
+	//if ok {
+	//	k := make([]byte, 4)                  // Assuming int k size is 4 bytes
+	//	binary.LittleEndian.PutUint32(k, key) // Assuming the key is an integer
+	//	if err := m.Update(k, data, ebpf.UpdateAny); err != nil {
+	//		return ETR_UPDATE_MAP_FAILD, err
+	//	}
+	//} else {
+	//	return ETR_UPDATE_MAP_FAILD, errors.New("cannot find map " + mapName)
 	//}
-	//fmt.Println("bpf_table_set_value", m, mapName, data)
+	//return ETR_OK, nil
+	return bpf_table_set_any_value(collection, mapName, key, data)
+}
+
+func bpf_table_set_any_value(collection *ebpf.Collection, mapName string, key, data any) (int, error) {
+	m, ok := collection.Maps[mapName]
 	if ok {
-		k := make([]byte, 4)                  // Assuming int k size is 4 bytes
-		binary.LittleEndian.PutUint32(k, key) // Assuming the key is an integer
-		if err := m.Update(k, data, ebpf.UpdateAny); err != nil {
+		if err := m.Update(key, data, ebpf.UpdateAny); err != nil {
 			return ETR_UPDATE_MAP_FAILD, err
 		}
 	} else {

+ 66 - 6
ebpftracer/tracer/socket.go

@@ -2,16 +2,19 @@ package tracer
 
 import (
 	"fmt"
-	"github.com/cilium/ebpf"
-	"github.com/cilium/ebpf/btf"
-	"github.com/coroot/coroot-node-agent/utils"
-	. "github.com/coroot/coroot-node-agent/utils/modelse"
-	klog "github.com/sirupsen/logrus"
 	"net"
 	"os"
 	"runtime"
+	"strings"
 	"syscall"
 	"time"
+
+	"github.com/cilium/ebpf"
+	"github.com/cilium/ebpf/btf"
+	"github.com/coroot/coroot-node-agent/flags"
+	"github.com/coroot/coroot-node-agent/utils"
+	. "github.com/coroot/coroot-node-agent/utils/modelse"
+	klog "github.com/sirupsen/logrus"
 )
 
 func init() {
@@ -52,6 +55,9 @@ func MapInsert(collection *ebpf.Collection) {
 
 	// Update protocol filter array
 	update_protocol_filter_array(collection)
+
+	// 从flags配置获取CodeType配置,默认支持Python和Node
+	update_skmsg_header_allowed_to_map(collection)
 }
 
 func insert_output_prog_to_map(collection *ebpf.Collection) {
@@ -109,7 +115,7 @@ func insert_adapt_kern_uid_to_map(collection *ebpf.Collection) {
 	pid := os.Getpid()
 	tid := syscall.Gettid()
 	adaptKernUID := uint64(pid)<<32 | uint64(tid)
-	code, err := bpf_table_set_value(collection, MAP_ADAPT_KERN_UID_NAME, 0, adaptKernUID)
+	code, err := bpf_table_set_value(collection, MAP_ADAPT_KERN_UID_NAME, uint32(0), adaptKernUID)
 	if err != nil || code != ETR_OK {
 		klog.Error(err, code)
 	}
@@ -362,3 +368,57 @@ func SetConstants(collectionSpec *ebpf.CollectionSpec) {
 	// 	fmt.Println("err", err, consts)
 	// }
 }
+
+// parseCodeTypesFromFlags 从flags配置解析CodeType数组
+// 配置格式: "python,nodejs" 或 "python,node" 等
+// 支持的语言标识: python, node, nodejs, java, go, php, dotnet, netcore, c, lua, ruby
+func parseCodeTypesFromFlags() []CodeType {
+	var codeTypes []CodeType
+	configValue := *flags.L4HeaderCodeTypes
+	if configValue == "" {
+		return codeTypes
+	}
+	parts := strings.Split(configValue, ",")
+	for _, part := range parts {
+		part = strings.TrimSpace(strings.ToLower(part))
+		switch part {
+		case "python":
+			codeTypes = append(codeTypes, CodeTypePython)
+		case "node", "nodejs":
+			codeTypes = append(codeTypes, CodeTypeNode)
+		case "java":
+			codeTypes = append(codeTypes, CodeTypeJava)
+		case "go":
+			codeTypes = append(codeTypes, CodeTypeGo)
+		case "php":
+			codeTypes = append(codeTypes, CodeTypePHP)
+		case "dotnet":
+			codeTypes = append(codeTypes, CodeTypeDotNet)
+		case "netcore":
+			codeTypes = append(codeTypes, CodeTypeNetCore)
+		case "c":
+			codeTypes = append(codeTypes, CodeTypeC)
+		case "lua":
+			codeTypes = append(codeTypes, CodeTypeLua)
+		case "ruby":
+			codeTypes = append(codeTypes, CodeTypeRuby)
+		case "nginx":
+			codeTypes = append(codeTypes, CodeTypeNginx)
+		default:
+			klog.Warnf("Unknown code type in L4_HEADER_CODE_TYPES: %s", part)
+		}
+	}
+
+	return codeTypes
+}
+
+func update_skmsg_header_allowed_to_map(collection *ebpf.Collection) {
+	codeTypes := parseCodeTypesFromFlags()
+	klog.Infof("[kernel] set l4 header allowed_to_map %s", codeTypes)
+	for _, codeType := range codeTypes {
+		_, err := bpf_table_set_any_value(collection, MAP_L4_HEADER_CODE_TYPES_NAME, uint16(codeType), uint8(1))
+		if err != nil {
+			klog.Errorf("[kernel] update_skmsg_header_allowed_to_map err: %v]")
+		}
+	}
+}

+ 1 - 0
flags/flags.go

@@ -66,6 +66,7 @@ var (
 
 	HostDirPathPrefix = kingpin.Flag("host-dir-path-prefix", "Set the prefix of path about the mount point of the host directory").Envar("HOST_DIR_PATH_PREFIX").Default("").String()
 	FuseTryMax        = kingpin.Flag("fuse_try_max", "The maximum number of the fuse operation try").Default("3").Envar("FUSE_TRY_MAX").Int()
+	L4HeaderCodeTypes = kingpin.Flag("l4-header", "L4 header code types (e.g., python,node,ruby)").Envar("L4_HEADER_CODE_TYPES").Default("python,node").String()
 	// debug
 	Test = kingpin.Flag("test", "Only test").Default("false").Envar("TEST").Bool()
 )

+ 6 - 1
utils/modelse/bpf_struct.go

@@ -25,7 +25,8 @@ const (
 	MAP_PROGS_JMP_TP_NAME = "__progs_jmp_tp_map"
 	MAP_PROGS_JMP_UP_NAME = "__progs_jmp_up_map"
 
-	MAP_PROC_INFO_MAP_NAME = "proc_info_map"
+	MAP_PROC_INFO_MAP_NAME        = "proc_info_map"
+	MAP_L4_HEADER_CODE_TYPES_NAME = "l4_header_code_types"
 	// This prog is designed to handle data transfer
 	PROGUP                         = "bpf_prog_up__"
 	PROGKP                         = "bpf_prog_kp__"
@@ -201,6 +202,10 @@ type EbpfProcInfo struct {
 	BucketsPtrPos  uint64
 }
 
+type allowedHeaderCodeTypes struct {
+	CodeType uint16
+}
+
 type allowPortBitmap struct {
 	Bitmap [65536 / 8]uint8
 }

+ 14 - 0
utils/modelse/code_type.go

@@ -22,6 +22,7 @@ const (
 	CodeTypeLua        CodeType = 1009
 	CodeTypeJavaC      CodeType = 1010
 	CodeTypeRuby       CodeType = 1012
+	CodeTypeNginx      CodeType = 1019
 )
 
 func (p CodeType) String() string {
@@ -52,6 +53,8 @@ func (p CodeType) String() string {
 		return "JAVA_C"
 	case CodeTypeRuby:
 		return "RUBY"
+	case CodeTypeNginx:
+		return "NGINX"
 	case CodeTypeWaitCheck:
 		return "WAIT_CHECK"
 	case CodeTypeUnknown:
@@ -130,6 +133,8 @@ func (p CodeType) ServiceTypeString() string {
 		return "JAVA_C"
 	case CodeTypeRuby:
 		return "RUBY"
+	case CodeTypeNginx:
+		return "NGINX"
 	case CodeTypeWaitCheck:
 		return "WAIT_CHECK"
 	case CodeTypeUnknown:
@@ -159,6 +164,8 @@ func (p CodeType) WhiteCodeString() string {
 		return "c"
 	case CodeTypeNetCore:
 		return "dc"
+	case CodeTypeNginx:
+		return "nginx"
 	//case CodeTypeNetCoreAot:
 	//	return "NETCORE_AOT"
 	//case CodeTypeLua:
@@ -273,3 +280,10 @@ func (p CodeType) IsJavaCCode() bool {
 	}
 	return false
 }
+
+func (p CodeType) IsNginxCode() bool {
+	if p == CodeTypeNginx {
+		return true
+	}
+	return false
+}