From 2d43b0bb53625cf8e3a3a15a4b3cf1465b1f6d40 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Thu, 22 Jun 2023 23:18:07 +0800 Subject: [PATCH 1/7] feat: support process info for skb events. --- kern/tc.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/kern/tc.h b/kern/tc.h index f7984782f..ce1e2a04c 100644 --- a/kern/tc.h +++ b/kern/tc.h @@ -13,7 +13,7 @@ // limitations under the License. #define TC_PACKET_MIN_SIZE 36 - +#define SOCKET_ALLOW 1 struct skb_data_event_t { uint64_t ts; u32 pid; @@ -23,13 +23,17 @@ struct skb_data_event_t { }; typedef struct net_id { - struct in6_addr address; - u16 port; u16 protocol; + u32 src_port; + u32 src_ip4; + u32 dst_port; + u32 dst_ip4; +// u32 src_ip6[4]; +// u32 dst_ip6[4]; } net_id_t; typedef struct net_ctx { - u32 host_tid; + u32 pid; char comm[TASK_COMM_LEN]; } net_ctx_t; @@ -46,13 +50,21 @@ struct { __uint(max_entries, 1); } skb_data_buffer_heap SEC(".maps"); -/* + struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __type(key, struct net_id_t); __type(value, struct net_ctx_t); __uint(max_entries, 10240); } network_map SEC(".maps"); + +/* +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __type(key, u16); // key即为TCP连接的 本地port + __type(value, u32); // pid + __uint(max_entries, 10240); +} pid_port SEC(".maps"); */ ////////////////////// General helper functions ////////////////////// @@ -130,12 +142,32 @@ int capture_packets(struct __sk_buff *skb, bool is_ingress) { return TC_ACT_OK; } #endif - // debug_bpf_printk("capture_packets port : %d, dest port :%d\n", - // bpf_ntohs(tcp->source), bpf_ntohs(tcp->dest)); + debug_bpf_printk("capture_packets port : %d, dest port :%d\n", + bpf_ntohs(tcp->source), bpf_ntohs(tcp->dest)); + // get the skb data event - net_id_t connect_id = {0}; + net_id_t conn_id = {0}; + conn_id.protocol = iph->protocol; + conn_id.src_ip4 = iph->saddr; + conn_id.dst_ip4 = iph->daddr; + conn_id.src_port = tcp->source; + conn_id.dst_port = tcp->dest; + + net_ctx_t *net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); + if (net_ctx == NULL) { + conn_id.src_ip4 = iph->daddr; + conn_id.dst_ip4 = iph->saddr; + conn_id.src_port = tcp->dest; + conn_id.dst_port = tcp->source; + net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); + } + // new packet event struct skb_data_event_t event = {0}; + if (net_ctx != NULL) { + event.pid = net_ctx->pid; + bpf_probe_read(&event.comm, sizeof(event.comm), net_ctx->comm); + } event.ts = bpf_ktime_get_ns(); event.len = skb->len; event.ifindex = skb->ifindex; @@ -168,4 +200,55 @@ int egress_cls_func(struct __sk_buff *skb) { SEC("classifier/ingress") int ingress_cls_func(struct __sk_buff *skb) { return capture_packets(skb, true); -}; \ No newline at end of file +}; + +static __always_inline int dected_port(struct bpf_sock_addr *ctx) { + u32 pid = bpf_get_current_pid_tgid() >> 32; +// 仅对指定PID的进程发起的connect事件进行捕获 +#ifndef KERNEL_LESS_5_2 + if (target_pid != 0 && target_pid != pid) { + return SOCKET_ALLOW; + } +#endif + u32 port = ctx->user_port; + if (port == 0) { + return SOCKET_ALLOW; + } + if (ctx->family != AF_INET ) { + debug_bpf_printk("[eCapture] unsupported family %d\n", ctx->family); + return SOCKET_ALLOW; + } + + // 从 ctx->sk中获取五元组 + net_id_t conn_id = {0}; + conn_id.dst_ip4 = ctx->sk->dst_ip4; + conn_id.src_ip4 = ctx->sk->src_ip4; + conn_id.protocol = ctx->sk->protocol; + conn_id.src_port = ctx->sk->src_port; + conn_id.dst_port = ctx->sk->dst_port; + + net_ctx_t net_ctx; + net_ctx.pid = pid; + bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); + debug_bpf_printk("[eCapture] wrote network_map map: user_port %d ==> pid:%d\n", port, pid); + bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); + return SOCKET_ALLOW; +} + + +// tracee used kprobe/security_socket_bind. +SEC("cgroup/connect4") +int cg_connect4(struct bpf_sock_addr *ctx) { + if (ctx->user_family != AF_INET || ctx->family != AF_INET) { + return SOCKET_ALLOW; + } + return dected_port(ctx); +} + +SEC("cgroup/connect6") +int cg_connect6(struct bpf_sock_addr *ctx) { + if (ctx->user_family != AF_INET6 || ctx->family != AF_INET6) { + return SOCKET_ALLOW; + } + return dected_port(ctx); +} \ No newline at end of file From 01ec5f38bbb1d624b34d7289b76caaf8c60a5b09 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Thu, 22 Jun 2023 23:42:49 +0800 Subject: [PATCH 2/7] feat: add process info for pcapng model. --- cli/cmd/tls.go | 1 + user/config/config_openssl.go | 57 +++++++++++++++++++++++++++++ user/config/config_openssl_linux.go | 5 +++ user/module/probe_openssl.go | 4 ++ user/module/probe_openssl_tc.go | 7 ++++ user/module/probe_tc.go | 2 +- 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/cli/cmd/tls.go b/cli/cmd/tls.go index 91f4b45ea..be8bfc20a 100644 --- a/cli/cmd/tls.go +++ b/cli/cmd/tls.go @@ -51,6 +51,7 @@ ecapture tls -w save_android.pcapng -i wlan0 --libssl=/apex/com.android.conscryp func init() { opensslCmd.PersistentFlags().StringVar(&oc.Curlpath, "curl", "", "curl or wget file path, use to dectet openssl.so path, default:/usr/bin/curl. (Deprecated)") opensslCmd.PersistentFlags().StringVar(&oc.Openssl, "libssl", "", "libssl.so file path, will automatically find it from curl default.") + opensslCmd.PersistentFlags().StringVar(&oc.CGroupPath, "cgroup_path", "/sys/fs/cgroup", "cgroup path, default: /sys/fs/cgroup.") opensslCmd.PersistentFlags().StringVar(&gc.Gnutls, "gnutls", "", "libgnutls.so file path, will automatically find it from curl default.") opensslCmd.PersistentFlags().StringVar(&gc.Curlpath, "wget", "", "wget file path, default: /usr/bin/wget. (Deprecated)") opensslCmd.PersistentFlags().StringVar(&nc.Firefoxpath, "firefox", "", "firefox file path, default: /usr/lib/firefox/firefox. (Deprecated)") diff --git a/user/config/config_openssl.go b/user/config/config_openssl.go index 1ea55af97..6bff6d5af 100644 --- a/user/config/config_openssl.go +++ b/user/config/config_openssl.go @@ -14,6 +14,23 @@ package config +import ( + "golang.org/x/sys/unix" + "os" + "path/filepath" + "syscall" +) + +/* +关于CGroup路径问题,可以自己创建,也可以使用系统的。不限制CGroup版本, v1、v2都可以。 +ubuntu系统上,默认在/sys/fs/cgroup ,CentOS上,可以自己创建。 代码中已经实现。 +或使用如下命令: +创建命令:mkdir /mnt/ecapture_cgroupv2 +mount -t cgroup2 none /mnt/ecapture_cgroupv2 +*/ +const cgroupPath = "/sys/fs/cgroup" // ubuntu +const cgroupPathCentos = "/mnt/ecapture_cgroupv2" // centos + // 最终使用openssl参数 type OpensslConfig struct { eConfig @@ -24,6 +41,7 @@ type OpensslConfig struct { Ifname string `json:"ifName"` // (TC Classifier) Interface name on which the probe will be attached. Port uint16 `json:"port"` // capture port SslVersion string `json:"sslVersion"` // openssl version like 1.1.1a/1.1.1f/boringssl_1.1.1 + CGroupPath string `json:"CGroupPath"` // cgroup path, used for filter process ElfType uint8 // IsAndroid bool // is Android OS ? } @@ -32,3 +50,42 @@ func NewOpensslConfig() *OpensslConfig { config := &OpensslConfig{} return config } + +func checkCgroupPath(cp string) (string, error) { + var st syscall.Statfs_t + err := syscall.Statfs(cp, &st) + if err != nil { + return "", err + } + newPath := cp + isCgroupV2Enabled := st.Type == unix.CGROUP2_SUPER_MAGIC + if !isCgroupV2Enabled { + newPath = filepath.Join(cgroupPath, "unified") + } + + // 判断老路径是否存在,正常的返回 + err = syscall.Statfs(newPath, &st) + if err == nil { + return newPath, nil + } + + // 若老路径不存在,则改用新路径 + // for CentOS + newPath = cgroupPathCentos + err = syscall.Statfs(newPath, &st) + if err == nil { + //TODO 判断是否已经mount + return newPath, nil + } + + // 若新路径不存在,重新创建 + err = os.Mkdir(newPath, os.FileMode(0755)) + if err != nil { + return "", err + } + err = syscall.Mount("none", newPath, "cgroup2", 0, "") + if err != nil { + return "", err + } + return newPath, nil +} diff --git a/user/config/config_openssl_linux.go b/user/config/config_openssl_linux.go index 7f8a16031..9bf17dfd2 100644 --- a/user/config/config_openssl_linux.go +++ b/user/config/config_openssl_linux.go @@ -95,5 +95,10 @@ func (oc *OpensslConfig) Check() error { } } + s, e := checkCgroupPath(oc.CGroupPath) + if e != nil { + return e + } + oc.CGroupPath = s return nil } diff --git a/user/module/probe_openssl.go b/user/module/probe_openssl.go index 8b1507c14..3cc8499d6 100644 --- a/user/module/probe_openssl.go +++ b/user/module/probe_openssl.go @@ -75,6 +75,7 @@ type MOpenSSLProbe struct { sslBpfFile string // ssl bpf file isBoringSSL bool // masterHookFunc string // SSL_in_init on boringSSL, SSL_write on openssl + cgroupPath string } // 对象初始化 @@ -126,6 +127,8 @@ func (m *MOpenSSLProbe) Init(ctx context.Context, logger *log.Logger, conf confi m.masterKeyBuffer = bytes.NewBuffer([]byte{}) m.initOpensslOffset() + m.cgroupPath = m.conf.(*config.OpensslConfig).CGroupPath + return nil } @@ -632,6 +635,7 @@ func (m *MOpenSSLProbe) Dispatcher(eventStruct event.IEventStruct) { case *event.MasterSecretBSSLEvent: m.saveMasterSecretBSSL(eventStruct.(*event.MasterSecretBSSLEvent)) case *event.TcSkbEvent: + m.logger.Printf("pid:%d, comm:%s\n", eventStruct.(*event.TcSkbEvent).Pid, eventStruct.(*event.TcSkbEvent).Comm) err := m.dumpTcSkb(eventStruct.(*event.TcSkbEvent)) if err != nil { m.logger.Printf("%s\t save packet error %s .\n", m.Name(), err.Error()) diff --git a/user/module/probe_openssl_tc.go b/user/module/probe_openssl_tc.go index f34db5a9a..1952ddbda 100644 --- a/user/module/probe_openssl_tc.go +++ b/user/module/probe_openssl_tc.go @@ -119,6 +119,13 @@ func (m *MOpenSSLProbe) setupManagersTC() error { BinaryPath: binaryPath, UID: "uprobe_ssl_master_key", }, + + // + { + EbpfFuncName: "cg_connect4", + Section: "cgroup/connect4", + CGroupPath: m.cgroupPath, + }, }, Maps: []*manager.Map{ diff --git a/user/module/probe_tc.go b/user/module/probe_tc.go index bd8c16678..fb764af97 100644 --- a/user/module/probe_tc.go +++ b/user/module/probe_tc.go @@ -110,7 +110,7 @@ func (t *MTCProbe) createPcapng(netIfs []net.Interface) error { SnapLength: uint32(math.MaxUint16), } - _, err := pcapWriter.AddInterface(ngIface) + _, err = pcapWriter.AddInterface(ngIface) if err != nil { return err } From 6a9ba073d43fff463e93aa8f1b53d780509c5613 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Fri, 23 Jun 2023 23:39:17 +0800 Subject: [PATCH 3/7] debug: incorret local_port. update ebpfmanager to v0.4.3 --- cli/cmd/tls.go | 3 +- go.mod | 2 +- go.sum | 2 + kern/tc.h | 104 +++++++++++++++++++++++++------- user/module/probe_openssl_tc.go | 5 ++ 5 files changed, 91 insertions(+), 25 deletions(-) diff --git a/cli/cmd/tls.go b/cli/cmd/tls.go index be8bfc20a..a772c2083 100644 --- a/cli/cmd/tls.go +++ b/cli/cmd/tls.go @@ -90,9 +90,8 @@ func openSSLCommandFunc(command *cobra.Command, args []string) { var version kernel.Version version, err = kernel.HostVersion() logger.Printf("ECAPTURE :: Kernel Info : %s", version.String()) - modNames := []string{} - if config.ElfArchIsandroid { + if config.ElfArchIsandroid || oc.Write != "" { modNames = []string{module.ModuleNameOpenssl} } else { modNames = []string{module.ModuleNameOpenssl, module.ModuleNameGnutls, module.ModuleNameNspr} diff --git a/go.mod b/go.mod index 6764beea9..c816c318c 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/cilium/ebpf v0.10.0 - github.com/gojue/ebpfmanager v0.4.2 + github.com/gojue/ebpfmanager v0.4.3 github.com/google/gopacket v1.1.19 github.com/shuLhan/go-bindata v4.0.0+incompatible github.com/spf13/cobra v1.4.0 diff --git a/go.sum b/go.sum index 35f968901..8eb8acdf1 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/gojue/ebpfmanager v0.4.1 h1:6Civdj0n8veUyuqZrsJxp6mRTQPQP50GrZgBu3XX4 github.com/gojue/ebpfmanager v0.4.1/go.mod h1:IbOQcGaeEvSPY6NtTtkG6xRQ93tNpGcbivMS0hODdA0= github.com/gojue/ebpfmanager v0.4.2 h1:t1xYfocc0fn5d2j5UYhoSp94NaBhsZyuaiK40InecDw= github.com/gojue/ebpfmanager v0.4.2/go.mod h1:IbOQcGaeEvSPY6NtTtkG6xRQ93tNpGcbivMS0hODdA0= +github.com/gojue/ebpfmanager v0.4.3 h1:uiGLdmf77j2T4PAoVj4rQSbKhBpTCPwHj4tV0HDS+uA= +github.com/gojue/ebpfmanager v0.4.3/go.mod h1:IbOQcGaeEvSPY6NtTtkG6xRQ93tNpGcbivMS0hODdA0= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= diff --git a/kern/tc.h b/kern/tc.h index ce1e2a04c..2fa780c29 100644 --- a/kern/tc.h +++ b/kern/tc.h @@ -22,20 +22,20 @@ struct skb_data_event_t { u32 ifindex; }; -typedef struct net_id { - u16 protocol; +struct net_id_t { + u32 protocol; u32 src_port; u32 src_ip4; u32 dst_port; u32 dst_ip4; // u32 src_ip6[4]; // u32 dst_ip6[4]; -} net_id_t; +}; -typedef struct net_ctx { +struct net_ctx_t { u32 pid; char comm[TASK_COMM_LEN]; -} net_ctx_t; +}; ////////////////////// ebpf maps ////////////////////// struct { @@ -142,32 +142,32 @@ int capture_packets(struct __sk_buff *skb, bool is_ingress) { return TC_ACT_OK; } #endif - debug_bpf_printk("capture_packets port : %d, dest port :%d\n", - bpf_ntohs(tcp->source), bpf_ntohs(tcp->dest)); - + debug_bpf_printk("capture_packets port : %d, dest port :%d\n", bpf_ntohs(tcp->source), bpf_ntohs(tcp->dest)); +/* // get the skb data event - net_id_t conn_id = {0}; + struct net_id_t conn_id = {0}; conn_id.protocol = iph->protocol; conn_id.src_ip4 = iph->saddr; conn_id.dst_ip4 = iph->daddr; conn_id.src_port = tcp->source; conn_id.dst_port = tcp->dest; - net_ctx_t *net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); + struct net_ctx_t *net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); if (net_ctx == NULL) { + // exchange src and dst conn_id.src_ip4 = iph->daddr; conn_id.dst_ip4 = iph->saddr; conn_id.src_port = tcp->dest; conn_id.dst_port = tcp->source; net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); } - +*/ // new packet event struct skb_data_event_t event = {0}; - if (net_ctx != NULL) { - event.pid = net_ctx->pid; - bpf_probe_read(&event.comm, sizeof(event.comm), net_ctx->comm); - } +// if (net_ctx != NULL) { +// event.pid = net_ctx->pid; +// bpf_probe_read(&event.comm, sizeof(event.comm), net_ctx->comm); +// } event.ts = bpf_ktime_get_ns(); event.len = skb->len; event.ifindex = skb->ifindex; @@ -202,7 +202,7 @@ int ingress_cls_func(struct __sk_buff *skb) { return capture_packets(skb, true); }; -static __always_inline int dected_port(struct bpf_sock_addr *ctx) { +static __always_inline int get_process(struct bpf_sock_addr *ctx) { u32 pid = bpf_get_current_pid_tgid() >> 32; // 仅对指定PID的进程发起的connect事件进行捕获 #ifndef KERNEL_LESS_5_2 @@ -210,7 +210,10 @@ static __always_inline int dected_port(struct bpf_sock_addr *ctx) { return SOCKET_ALLOW; } #endif - u32 port = ctx->user_port; + if (ctx->protocol != IPPROTO_TCP) { + return SOCKET_ALLOW; + } + u32 port = bpf_ntohs(ctx->user_port); if (port == 0) { return SOCKET_ALLOW; } @@ -220,17 +223,18 @@ static __always_inline int dected_port(struct bpf_sock_addr *ctx) { } // 从 ctx->sk中获取五元组 - net_id_t conn_id = {0}; + struct net_id_t conn_id = {0}; conn_id.dst_ip4 = ctx->sk->dst_ip4; conn_id.src_ip4 = ctx->sk->src_ip4; conn_id.protocol = ctx->sk->protocol; conn_id.src_port = ctx->sk->src_port; conn_id.dst_port = ctx->sk->dst_port; - net_ctx_t net_ctx; + struct net_ctx_t net_ctx; net_ctx.pid = pid; bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); - debug_bpf_printk("[eCapture] wrote network_map map: user_port %d ==> pid:%d\n", port, pid); + debug_bpf_printk("[eCapture] conn_id src_port:%d , dst_port::%d, protocol:%d\n", conn_id.src_port, conn_id.dst_port, conn_id.protocol); + debug_bpf_printk("[eCapture] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); return SOCKET_ALLOW; } @@ -242,13 +246,69 @@ int cg_connect4(struct bpf_sock_addr *ctx) { if (ctx->user_family != AF_INET || ctx->family != AF_INET) { return SOCKET_ALLOW; } - return dected_port(ctx); + return get_process(ctx); } +/* SEC("cgroup/connect6") int cg_connect6(struct bpf_sock_addr *ctx) { if (ctx->user_family != AF_INET6 || ctx->family != AF_INET6) { return SOCKET_ALLOW; } - return dected_port(ctx); + return get_process(ctx); +} +*/ + + +/* +struct bpf_sock { + __u32 bound_dev_if; + __u32 family; + __u32 type; + __u32 protocol; + __u32 mark; + __u32 priority; + __u32 src_ip4; + __u32 src_ip6[4]; + __u32 src_port; + __u32 dst_port; + __u32 dst_ip4; + __u32 dst_ip6[4]; + __u32 state; + __s32 rx_queue_mapping; +}; +*/ + +SEC("cgroup/sock_create") +int ecapture_cgroup_sock(struct bpf_sock *sk) +{ + u32 pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("cgroup sock pid:%d\n", pid); + u32 port = bpf_ntohs(sk->dst_port); + if (port == 0) { + return SOCKET_ALLOW; + } + if (sk->family != AF_INET ) { + debug_bpf_printk("[eCapture] unsupported family %d\n", sk->family); + return SOCKET_ALLOW; + } +/* + // 从 skops中获取五元组 + struct net_id_t conn_id = {0}; + conn_id.dst_ip4 = sk->dst_ip4; + conn_id.src_ip4 = sk->src_ip4; + conn_id.protocol = sk->protocol; + conn_id.src_port = sk->src_port; + conn_id.dst_port = sk->dst_port; + + struct net_ctx_t net_ctx; + net_ctx.pid = pid; + bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); + */ + +// debug_bpf_printk("[cgroup sock] conn_id src_port:%d , dst_port::%d, protocol:%d\n", conn_id.src_port, conn_id.dst_port, conn_id.protocol); +// debug_bpf_printk("[cgroup sock] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); +// bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); + debug_bpf_printk("[cgroup sock] PID:%d, sk dst_port->src_port : %d -> %d\n", pid, sk->dst_port, sk->src_port); + return SOCKET_ALLOW; } \ No newline at end of file diff --git a/user/module/probe_openssl_tc.go b/user/module/probe_openssl_tc.go index 1952ddbda..4552a99bd 100644 --- a/user/module/probe_openssl_tc.go +++ b/user/module/probe_openssl_tc.go @@ -121,6 +121,11 @@ func (m *MOpenSSLProbe) setupManagersTC() error { }, // + { + EbpfFuncName: "ecapture_cgroup_sock", + Section: "cgroup/sock_create", + CGroupPath: m.cgroupPath, + }, { EbpfFuncName: "cg_connect4", Section: "cgroup/connect4", From cacd01ad39c45bd2f255ea55d068359b8cd068b3 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Sat, 24 Jun 2023 23:27:25 +0800 Subject: [PATCH 4/7] debug cgroup/connect4 eBPF program type. --- kern/tc.h | 89 ++++++++------------------------- user/module/probe_openssl_tc.go | 6 --- 2 files changed, 21 insertions(+), 74 deletions(-) diff --git a/kern/tc.h b/kern/tc.h index 2fa780c29..8f40dfd67 100644 --- a/kern/tc.h +++ b/kern/tc.h @@ -26,8 +26,8 @@ struct net_id_t { u32 protocol; u32 src_port; u32 src_ip4; - u32 dst_port; - u32 dst_ip4; +// u32 dst_port; +// u32 dst_ip4; // u32 src_ip6[4]; // u32 dst_ip6[4]; }; @@ -148,17 +148,13 @@ int capture_packets(struct __sk_buff *skb, bool is_ingress) { struct net_id_t conn_id = {0}; conn_id.protocol = iph->protocol; conn_id.src_ip4 = iph->saddr; - conn_id.dst_ip4 = iph->daddr; conn_id.src_port = tcp->source; - conn_id.dst_port = tcp->dest; struct net_ctx_t *net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); if (net_ctx == NULL) { // exchange src and dst conn_id.src_ip4 = iph->daddr; - conn_id.dst_ip4 = iph->saddr; conn_id.src_port = tcp->dest; - conn_id.dst_port = tcp->source; net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); } */ @@ -202,6 +198,18 @@ int ingress_cls_func(struct __sk_buff *skb) { return capture_packets(skb, true); }; +/* +struct bpf_sock_addr { + __u32 user_family; + __u32 user_ip4; + __u32 user_ip6[4]; + __u32 user_port; + __u32 family; + __u32 type; + __u32 protocol; + __u32 msg_src_ip4; + __u32 msg_src_ip6[4]; + */ static __always_inline int get_process(struct bpf_sock_addr *ctx) { u32 pid = bpf_get_current_pid_tgid() >> 32; // 仅对指定PID的进程发起的connect事件进行捕获 @@ -224,17 +232,16 @@ static __always_inline int get_process(struct bpf_sock_addr *ctx) { // 从 ctx->sk中获取五元组 struct net_id_t conn_id = {0}; - conn_id.dst_ip4 = ctx->sk->dst_ip4; - conn_id.src_ip4 = ctx->sk->src_ip4; +// conn_id.src_ip4 = bpf_ntohs(ctx->msg_src_ip4); + bpf_probe_read(&conn_id.src_ip4, sizeof(conn_id.src_ip4), &ctx->msg_src_ip4); conn_id.protocol = ctx->sk->protocol; - conn_id.src_port = ctx->sk->src_port; - conn_id.dst_port = ctx->sk->dst_port; + conn_id.src_port = bpf_ntohs(ctx->sk->src_port); struct net_ctx_t net_ctx; net_ctx.pid = pid; bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); - debug_bpf_printk("[eCapture] conn_id src_port:%d , dst_port::%d, protocol:%d\n", conn_id.src_port, conn_id.dst_port, conn_id.protocol); - debug_bpf_printk("[eCapture] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); + debug_bpf_printk("[!!!!!] conn_id user_ip4:%d, msg_src_ip4:%d, protocol:%d\n", bpf_ntohl(ctx->user_ip4), bpf_ntohl(conn_id.src_ip4), conn_id.protocol); + debug_bpf_printk("[!!!!!] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); return SOCKET_ALLOW; } @@ -252,63 +259,9 @@ int cg_connect4(struct bpf_sock_addr *ctx) { /* SEC("cgroup/connect6") int cg_connect6(struct bpf_sock_addr *ctx) { - if (ctx->user_family != AF_INET6 || ctx->family != AF_INET6) { + if (ctx->user_family != AF_INET || ctx->family != AF_INET) { return SOCKET_ALLOW; } return get_process(ctx); } -*/ - - -/* -struct bpf_sock { - __u32 bound_dev_if; - __u32 family; - __u32 type; - __u32 protocol; - __u32 mark; - __u32 priority; - __u32 src_ip4; - __u32 src_ip6[4]; - __u32 src_port; - __u32 dst_port; - __u32 dst_ip4; - __u32 dst_ip6[4]; - __u32 state; - __s32 rx_queue_mapping; -}; -*/ - -SEC("cgroup/sock_create") -int ecapture_cgroup_sock(struct bpf_sock *sk) -{ - u32 pid = bpf_get_current_pid_tgid() >> 32; - bpf_printk("cgroup sock pid:%d\n", pid); - u32 port = bpf_ntohs(sk->dst_port); - if (port == 0) { - return SOCKET_ALLOW; - } - if (sk->family != AF_INET ) { - debug_bpf_printk("[eCapture] unsupported family %d\n", sk->family); - return SOCKET_ALLOW; - } -/* - // 从 skops中获取五元组 - struct net_id_t conn_id = {0}; - conn_id.dst_ip4 = sk->dst_ip4; - conn_id.src_ip4 = sk->src_ip4; - conn_id.protocol = sk->protocol; - conn_id.src_port = sk->src_port; - conn_id.dst_port = sk->dst_port; - - struct net_ctx_t net_ctx; - net_ctx.pid = pid; - bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); - */ - -// debug_bpf_printk("[cgroup sock] conn_id src_port:%d , dst_port::%d, protocol:%d\n", conn_id.src_port, conn_id.dst_port, conn_id.protocol); -// debug_bpf_printk("[cgroup sock] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); -// bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); - debug_bpf_printk("[cgroup sock] PID:%d, sk dst_port->src_port : %d -> %d\n", pid, sk->dst_port, sk->src_port); - return SOCKET_ALLOW; -} \ No newline at end of file +*/ \ No newline at end of file diff --git a/user/module/probe_openssl_tc.go b/user/module/probe_openssl_tc.go index 4552a99bd..5d539ed07 100644 --- a/user/module/probe_openssl_tc.go +++ b/user/module/probe_openssl_tc.go @@ -119,13 +119,7 @@ func (m *MOpenSSLProbe) setupManagersTC() error { BinaryPath: binaryPath, UID: "uprobe_ssl_master_key", }, - // - { - EbpfFuncName: "ecapture_cgroup_sock", - Section: "cgroup/sock_create", - CGroupPath: m.cgroupPath, - }, { EbpfFuncName: "cg_connect4", Section: "cgroup/connect4", From e23fe3c0f952bced8c78474f19057e132140d9f6 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Sun, 25 Jun 2023 21:42:53 +0800 Subject: [PATCH 5/7] remove unused code. --- kern/openssl_masterkey.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/kern/openssl_masterkey.h b/kern/openssl_masterkey.h index 8f8a5b18b..97fc626f8 100644 --- a/kern/openssl_masterkey.h +++ b/kern/openssl_masterkey.h @@ -119,7 +119,6 @@ int probe_ssl_master_key(struct pt_regs *ctx) { // Get SSL->version pointer int version; u64 address; - u64 s3_address; int ret = bpf_probe_read_user(&version, sizeof(version), (void *)ssl_version_ptr); if (ret) { @@ -136,7 +135,6 @@ int probe_ssl_master_key(struct pt_regs *ctx) { "bpf_probe_read ssl_s3_st_ptr pointer failed, ret :%d\n", ret); return 0; } - s3_address = address; struct ssl3_state_st ssl3_stat; ret = bpf_probe_read_user(&ssl3_stat, sizeof(ssl3_stat), (void *)address); if (ret) { From e0ca2db9271268a0406d7858a004e6340623309a Mon Sep 17 00:00:00 2001 From: cfc4n Date: Sat, 1 Jul 2023 18:49:44 +0800 Subject: [PATCH 6/7] feat: associate corresponding process information with each network packet. --- kern/common.h | 1 + kern/ecapture.h | 1 + kern/tc.h | 175 +++++++++++++++++--------------- user/event/event_openssl_tc.go | 7 ++ user/module/probe_openssl.go | 1 - user/module/probe_openssl_tc.go | 6 +- user/module/probe_tc.go | 97 +++++++++++++++++- utils/ecapture.lua | 16 ++- 8 files changed, 211 insertions(+), 93 deletions(-) diff --git a/kern/common.h b/kern/common.h index 55b170612..fd40a22ab 100644 --- a/kern/common.h +++ b/kern/common.h @@ -26,6 +26,7 @@ #endif #define TASK_COMM_LEN 16 +#define PATH_MAX_LEN 256 #define MAX_DATA_SIZE_OPENSSL 1024 * 4 #define MAX_DATA_SIZE_MYSQL 256 #define MAX_DATA_SIZE_POSTGRES 256 diff --git a/kern/ecapture.h b/kern/ecapture.h index 72574830d..797fb31b2 100644 --- a/kern/ecapture.h +++ b/kern/ecapture.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/kern/tc.h b/kern/tc.h index 8f40dfd67..685d00ae7 100644 --- a/kern/tc.h +++ b/kern/tc.h @@ -14,10 +14,19 @@ #define TC_PACKET_MIN_SIZE 36 #define SOCKET_ALLOW 1 +#define READ_KERN(ptr) \ + ({ \ + typeof(ptr) _val; \ + __builtin_memset((void *)&_val, 0, sizeof(_val)); \ + bpf_core_read((void *)&_val, sizeof(_val), &ptr); \ + _val; \ + }) + struct skb_data_event_t { uint64_t ts; u32 pid; char comm[TASK_COMM_LEN]; +// u8 cmdline[PATH_MAX_LEN]; u32 len; u32 ifindex; }; @@ -26,8 +35,8 @@ struct net_id_t { u32 protocol; u32 src_port; u32 src_ip4; -// u32 dst_port; -// u32 dst_ip4; + u32 dst_port; + u32 dst_ip4; // u32 src_ip6[4]; // u32 dst_ip6[4]; }; @@ -35,6 +44,7 @@ struct net_id_t { struct net_ctx_t { u32 pid; char comm[TASK_COMM_LEN]; +// u8 cmdline[PATH_MAX_LEN]; }; ////////////////////// ebpf maps ////////////////////// @@ -58,17 +68,20 @@ struct { __uint(max_entries, 10240); } network_map SEC(".maps"); -/* -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __type(key, u16); // key即为TCP连接的 本地port - __type(value, u32); // pid - __uint(max_entries, 10240); -} pid_port SEC(".maps"); -*/ - ////////////////////// General helper functions ////////////////////// -static __inline struct skb_data_event_t *make_skb_data_event() { + +static __always_inline void get_proc_cmdline(struct task_struct *task, char *cmdline, int size) +{ + struct mm_struct *mm = READ_KERN(task->mm); + long unsigned int args_start = READ_KERN(mm->arg_start); + long unsigned int args_end = READ_KERN(mm->arg_end); + int len = (args_end - args_start); + if (len >= size) + len = size - 1; + bpf_probe_read(cmdline, len & (size - 1), (const void *)args_start); +} + +static __always_inline struct skb_data_event_t *make_skb_data_event() { u32 kZero = 0; struct skb_data_event_t *event = bpf_map_lookup_elem(&skb_data_buffer_heap, &kZero); @@ -98,17 +111,20 @@ static __always_inline bool skb_revalidate_data(struct __sk_buff *skb, } ///////////////////// ebpf functions ////////////////////// -int capture_packets(struct __sk_buff *skb, bool is_ingress) { +static __always_inline int capture_packets(struct __sk_buff *skb, bool is_ingress) { // packet data unsigned char *data_start = (void *)(long)skb->data; unsigned char *data_end = (void *)(long)skb->data_end; + if (data_start + sizeof(struct ethhdr) > data_end) { + return TC_ACT_OK; + } + u32 data_len = (u32)skb->len; uint32_t l4_hdr_off; // Ethernet headers struct ethhdr *eth = (struct ethhdr *)data_start; - // IP headers - struct iphdr *iph = (struct iphdr *)(data_start + sizeof(struct ethhdr)); + // Simple length check if ((data_start + sizeof(struct ethhdr) + sizeof(struct iphdr)) > @@ -126,14 +142,22 @@ int capture_packets(struct __sk_buff *skb, bool is_ingress) { return TC_ACT_OK; } + // IP headers + struct iphdr *iph = (struct iphdr *)(data_start + sizeof(struct ethhdr)); // filter out non-TCP packets if (iph->protocol != IPPROTO_TCP) { return TC_ACT_OK; } + struct net_id_t conn_id = {0}; + conn_id.protocol = iph->protocol; + conn_id.src_ip4 = iph->saddr; + conn_id.dst_ip4 = iph->daddr; + if (!skb_revalidate_data(skb, &data_start, &data_end, l4_hdr_off + sizeof(struct tcphdr))) { return TC_ACT_OK; } +// debug_bpf_printk("!!!capture_packets src_ip4 : %d, dst_ip4 port :%d\n", conn_id.src_ip4, conn_id.dst_ip4); struct tcphdr *tcp = (struct tcphdr *)(data_start + l4_hdr_off); #ifndef KERNEL_LESS_5_2 @@ -142,28 +166,38 @@ int capture_packets(struct __sk_buff *skb, bool is_ingress) { return TC_ACT_OK; } #endif - debug_bpf_printk("capture_packets port : %d, dest port :%d\n", bpf_ntohs(tcp->source), bpf_ntohs(tcp->dest)); -/* - // get the skb data event - struct net_id_t conn_id = {0}; - conn_id.protocol = iph->protocol; - conn_id.src_ip4 = iph->saddr; - conn_id.src_port = tcp->source; + + + conn_id.src_port = bpf_ntohs(tcp->source); + conn_id.dst_port = bpf_ntohs(tcp->dest); +// debug_bpf_printk("!!!capture_packets port : %d, dest port :%d\n", conn_id.src_port, conn_id.dst_port); struct net_ctx_t *net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); if (net_ctx == NULL) { // exchange src and dst - conn_id.src_ip4 = iph->daddr; - conn_id.src_port = tcp->dest; + u32 tmp_ip = conn_id.src_ip4; + conn_id.src_ip4 = conn_id.dst_ip4; + conn_id.dst_ip4 = tmp_ip; + u32 tmp_port = conn_id.src_port; + conn_id.src_port = conn_id.dst_port; + conn_id.dst_port = tmp_port; net_ctx = bpf_map_lookup_elem(&network_map, &conn_id); } -*/ + // new packet event struct skb_data_event_t event = {0}; -// if (net_ctx != NULL) { -// event.pid = net_ctx->pid; -// bpf_probe_read(&event.comm, sizeof(event.comm), net_ctx->comm); +// struct skb_data_event_t *event = make_skb_data_event(); +// if (event == NULL) { +// return TC_ACT_OK; // } + if (net_ctx != NULL) { + event.pid = net_ctx->pid; + __builtin_memcpy(event.comm, net_ctx->comm, TASK_COMM_LEN); +// __builtin_memcpy(event.cmdline, net_ctx->cmdline, PATH_MAX_LEN); + debug_bpf_printk("capture packet process found, pid: %d, comm :%s\n", event.pid, event.comm); + } else { + debug_bpf_printk("capture packet process not found, src_port:%d, dst_port:%d\n", conn_id.src_port, conn_id.dst_port); + } event.ts = bpf_ktime_get_ns(); event.len = skb->len; event.ifindex = skb->ifindex; @@ -198,70 +232,47 @@ int ingress_cls_func(struct __sk_buff *skb) { return capture_packets(skb, true); }; -/* -struct bpf_sock_addr { - __u32 user_family; - __u32 user_ip4; - __u32 user_ip6[4]; - __u32 user_port; - __u32 family; - __u32 type; - __u32 protocol; - __u32 msg_src_ip4; - __u32 msg_src_ip6[4]; - */ -static __always_inline int get_process(struct bpf_sock_addr *ctx) { +SEC("kprobe/tcp_sendmsg") +int tcp_sendmsg(struct pt_regs *ctx){ u32 pid = bpf_get_current_pid_tgid() >> 32; // 仅对指定PID的进程发起的connect事件进行捕获 #ifndef KERNEL_LESS_5_2 - if (target_pid != 0 && target_pid != pid) { - return SOCKET_ALLOW; - } + if (target_pid != 0 && target_pid != pid) { + return 0; + } #endif - if (ctx->protocol != IPPROTO_TCP) { - return SOCKET_ALLOW; + struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx); + if (sk == NULL) { + return 0; } - u32 port = bpf_ntohs(ctx->user_port); - if (port == 0) { - return SOCKET_ALLOW; - } - if (ctx->family != AF_INET ) { - debug_bpf_printk("[eCapture] unsupported family %d\n", ctx->family); - return SOCKET_ALLOW; + + u16 family, lport, dport; + u32 src_ip4, dst_ip4; + bpf_probe_read(&family, sizeof(family), &sk->__sk_common.skc_family); + + if (family != AF_INET) { + return 0; } + bpf_probe_read(&lport, sizeof(lport), &sk->__sk_common.skc_num); + bpf_probe_read(&dport, sizeof(dport), &sk->__sk_common.skc_dport); + bpf_probe_read(&src_ip4, sizeof(src_ip4), &sk->__sk_common.skc_rcv_saddr); + bpf_probe_read(&dst_ip4, sizeof(dst_ip4), &sk->__sk_common.skc_daddr); - // 从 ctx->sk中获取五元组 struct net_id_t conn_id = {0}; -// conn_id.src_ip4 = bpf_ntohs(ctx->msg_src_ip4); - bpf_probe_read(&conn_id.src_ip4, sizeof(conn_id.src_ip4), &ctx->msg_src_ip4); - conn_id.protocol = ctx->sk->protocol; - conn_id.src_port = bpf_ntohs(ctx->sk->src_port); + conn_id.protocol = IPPROTO_TCP; + conn_id.src_port = lport; + conn_id.src_ip4 = src_ip4; + conn_id.dst_port = bpf_ntohs(dport); + conn_id.dst_ip4 = dst_ip4; struct net_ctx_t net_ctx; net_ctx.pid = pid; bpf_get_current_comm(&net_ctx.comm, sizeof(net_ctx.comm)); - debug_bpf_printk("[!!!!!] conn_id user_ip4:%d, msg_src_ip4:%d, protocol:%d\n", bpf_ntohl(ctx->user_ip4), bpf_ntohl(conn_id.src_ip4), conn_id.protocol); - debug_bpf_printk("[!!!!!] wrote network_map map: user_port %d ==> pid:%d, comm:%s\n", port, pid, net_ctx.comm); + // +// struct task_struct *task = (struct task_struct *)bpf_get_current_task(); +// get_proc_cmdline(task, net_ctx.cmdline, sizeof(net_ctx.cmdline)); +// + debug_bpf_printk("tcp_sendmsg pid : %d, comm :%s\n", net_ctx.pid, net_ctx.comm); bpf_map_update_elem(&network_map, &conn_id, &net_ctx, BPF_ANY); - return SOCKET_ALLOW; -} - - -// tracee used kprobe/security_socket_bind. -SEC("cgroup/connect4") -int cg_connect4(struct bpf_sock_addr *ctx) { - if (ctx->user_family != AF_INET || ctx->family != AF_INET) { - return SOCKET_ALLOW; - } - return get_process(ctx); -} - -/* -SEC("cgroup/connect6") -int cg_connect6(struct bpf_sock_addr *ctx) { - if (ctx->user_family != AF_INET || ctx->family != AF_INET) { - return SOCKET_ALLOW; - } - return get_process(ctx); -} -*/ \ No newline at end of file + return 0; +} \ No newline at end of file diff --git a/user/event/event_openssl_tc.go b/user/event/event_openssl_tc.go index f077a7c3d..9b698de35 100644 --- a/user/event/event_openssl_tc.go +++ b/user/event/event_openssl_tc.go @@ -22,6 +22,7 @@ import ( const ( TaskCommLen = 16 + CmdlineLen = 256 ) type TcSkbEvent struct { @@ -29,6 +30,7 @@ type TcSkbEvent struct { Ts uint64 `json:"ts"` Pid uint32 `json:"pid"` Comm [TaskCommLen]byte `json:"Comm"` + Cmdline [CmdlineLen]byte `json:"Cmdline"` Len uint32 `json:"len"` Ifindex uint32 `json:"ifindex"` payload []byte @@ -45,6 +47,11 @@ func (te *TcSkbEvent) Decode(payload []byte) (err error) { if err = binary.Read(buf, binary.LittleEndian, &te.Comm); err != nil { return } + //if err = binary.Read(buf, binary.LittleEndian, &te.Cmdline); err != nil { + // return + //} + //TODO + te.Cmdline[0] = 91 //ascii 91 if err = binary.Read(buf, binary.LittleEndian, &te.Len); err != nil { return } diff --git a/user/module/probe_openssl.go b/user/module/probe_openssl.go index 3cc8499d6..ce264865b 100644 --- a/user/module/probe_openssl.go +++ b/user/module/probe_openssl.go @@ -635,7 +635,6 @@ func (m *MOpenSSLProbe) Dispatcher(eventStruct event.IEventStruct) { case *event.MasterSecretBSSLEvent: m.saveMasterSecretBSSL(eventStruct.(*event.MasterSecretBSSLEvent)) case *event.TcSkbEvent: - m.logger.Printf("pid:%d, comm:%s\n", eventStruct.(*event.TcSkbEvent).Pid, eventStruct.(*event.TcSkbEvent).Comm) err := m.dumpTcSkb(eventStruct.(*event.TcSkbEvent)) if err != nil { m.logger.Printf("%s\t save packet error %s .\n", m.Name(), err.Error()) diff --git a/user/module/probe_openssl_tc.go b/user/module/probe_openssl_tc.go index 5d539ed07..a856983e9 100644 --- a/user/module/probe_openssl_tc.go +++ b/user/module/probe_openssl_tc.go @@ -121,9 +121,9 @@ func (m *MOpenSSLProbe) setupManagersTC() error { }, // { - EbpfFuncName: "cg_connect4", - Section: "cgroup/connect4", - CGroupPath: m.cgroupPath, + EbpfFuncName: "tcp_sendmsg", + Section: "kprobe/tcp_sendmsg", + AttachToFuncName: "tcp_sendmsg", }, }, diff --git a/user/module/probe_tc.go b/user/module/probe_tc.go index fb764af97..538a6d884 100644 --- a/user/module/probe_tc.go +++ b/user/module/probe_tc.go @@ -2,7 +2,9 @@ package module import ( "bytes" + "ecapture/pkg/util/ethernet" "ecapture/user/event" + "encoding/binary" "fmt" "github.com/google/gopacket" "github.com/google/gopacket/layers" @@ -10,6 +12,7 @@ import ( "math" "net" "os" + "strings" "sync" "time" ) @@ -25,6 +28,41 @@ type NetCaptureData struct { ConfigIfaceIndex uint32 `json:"ifIndex"` } +const EcaptureMagic = 0xCC0C4CFC + +type packetMetaData struct { + Magic uint32 `struc:"uint32"` + Pid uint32 `struc:"uint32"` + CmdLen uint8 `struc:"uint8,sizeof=Cmd"` + Cmd string +} + +func (p *packetMetaData) Pack() ([]byte, error) { + buf := new(bytes.Buffer) + + // 使用 binary.BigEndian 将字段按大端字节序写入缓冲区 + err := binary.Write(buf, binary.BigEndian, p.Magic) + if err != nil { + return nil, err + } + + err = binary.Write(buf, binary.BigEndian, p.Pid) + if err != nil { + return nil, err + } + + err = binary.Write(buf, binary.BigEndian, p.CmdLen) + if err != nil { + return nil, err + } + + _, err = buf.WriteString(p.Cmd) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + func (NetCaptureData) GetSizeBytes() uint32 { return 8 } @@ -45,7 +83,60 @@ type MTCProbe struct { func (t *MTCProbe) dumpTcSkb(tcEvent *event.TcSkbEvent) error { var timeStamp = t.bootTime + tcEvent.Ts - return t.writePacket(tcEvent.Len, time.Unix(0, int64(timeStamp)), tcEvent.Payload()) + var payload []byte + payload = tcEvent.Payload() + if tcEvent.Pid > 0 { + err, p := t.writePid(tcEvent) + if err == nil { + payload = p + //fmt.Printf("pid:%d, comm:%s, cmdline:%s\n", tcEvent.Pid, tcEvent.Comm, tcEvent.Cmdline) + } + } + return t.writePacket(uint32(len(payload)), time.Unix(0, int64(timeStamp)), payload) +} + +func (t *MTCProbe) writePid(tcEvent *event.TcSkbEvent) (error, []byte) { + ethPacket := gopacket.NewPacket( + tcEvent.Payload(), + layers.LayerTypeEthernet, + gopacket.Default, + ) + + oldEthLayer := ethPacket.Layers()[0].(*layers.Ethernet) + + // subtract oldethelayer from the begining of ethpacket + restOfLayers := ethPacket.Layers()[1:] + remainder := []byte{} + for _, layer := range restOfLayers { + // we can correlate metadata only in TCP or UDP for now + remainder = append(remainder, layer.LayerContents()...) + } + metadata := packetMetaData{} + metadata.Magic = EcaptureMagic + metadata.Pid = tcEvent.Pid + var cmd = strings.TrimSpace(fmt.Sprintf("%s", tcEvent.Comm)) + metadata.CmdLen = uint8(len(cmd)) + metadata.Cmd = cmd + + var pt []byte + var err error + pt, err = metadata.Pack() + if err != nil { + return err, []byte{} + } + newEtherLayer := ðernet.EthernetWithTrailer{ + SrcMAC: oldEthLayer.SrcMAC, + DstMAC: oldEthLayer.DstMAC, + EthernetType: oldEthLayer.EthernetType, + Trailer: pt, + } + + buffer := gopacket.NewSerializeBuffer() + err = gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{false, false}, newEtherLayer, gopacket.Payload(remainder)) + if err != nil { + return err, []byte{} + } + return nil, buffer.Bytes() } // save pcapng file ,merge master key into pcapng file TODO @@ -80,8 +171,8 @@ func (t *MTCProbe) createPcapng(netIfs []net.Interface) error { // TODO : write Application "ecapture.lua" to decode PID/Comm info. pcapOption := pcapgo.NgWriterOptions{ SectionInfo: pcapgo.NgSectionInfo{ - Hardware: "eCapture Hardware", - OS: "", + Hardware: "eCapture (旁观者) Hardware", + OS: "Linux/Android", Application: "ecapture.lua", Comment: "see https://ecapture.cc for more information. CFC4N ", }, diff --git a/utils/ecapture.lua b/utils/ecapture.lua index 15f984490..f31b7a999 100644 --- a/utils/ecapture.lua +++ b/utils/ecapture.lua @@ -15,7 +15,7 @@ local fields = {} fields.magic = ProtoField.uint32("ecapture.magic", "Magic", base.HEX) fields.pid = ProtoField.int32("ecapture.pid", "PID", base.DEC) fields.Comm = ProtoField.string("ecapture.Comm", "Comm", base.ASCII) -fields.Cmdline = ProtoField.string("ecapture.Cmdline", "Cmdline", base.ASCII) +-- fields.Cmdline = ProtoField.string("ecapture.Cmdline", "Cmdline", base.ASCII) ecapture.fields = fields @@ -32,13 +32,21 @@ function ecapture.dissector(buffer, pinfo, tree) local iplen = buffer(16 ,2):uint() local framelen = buffer:len() local trailerlength = framelen - ethernet_header_size - iplen + -- check padding type -- -4: skip the FCS local trailer = buffer(iplen+ethernet_header_size ,trailerlength ) + if trailerlength < 9 then + return + end + -- simple sanity check with the magic number local magic = trailer(0, 4):uint() if(magic ~= ECAPTURE_MAGIC) then +-- print("trailerlength:"..trailerlength) +-- print("magic:%x", magic) +-- print("trailer:%x", trailer) return end @@ -48,10 +56,10 @@ function ecapture.dissector(buffer, pinfo, tree) subtree:add(fields.pid, pid) local commLen = trailer(8, 1):uint() subtree:add(fields.Comm, trailer(9,commLen)) - local cmdlineLen = trailer(9+commLen, 2):uint() +-- local cmdlineLen = trailer(9+commLen, 2):uint() -- subtree:add(fields.cmdlineLen, trailer(9+commLen,cmdlineLen)) - local cmdline = trailer(11+commLen, cmdlineLen):string() - subtree:add(fields.Cmdline, cmdline) +-- local cmdline = trailer(11+commLen, cmdlineLen):string() +-- subtree:add(fields.Cmdline, cmdline) end register_postdissector(ecapture) \ No newline at end of file From c0888068a773d0fe352dd05233bcbf0cc0ffb219 Mon Sep 17 00:00:00 2001 From: cfc4n Date: Sat, 1 Jul 2023 18:52:17 +0800 Subject: [PATCH 7/7] add ethernet/trailer.go --- pkg/util/ethernet/trailer.go | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 pkg/util/ethernet/trailer.go diff --git a/pkg/util/ethernet/trailer.go b/pkg/util/ethernet/trailer.go new file mode 100644 index 000000000..947eac1c6 --- /dev/null +++ b/pkg/util/ethernet/trailer.go @@ -0,0 +1,86 @@ +package ethernet + +import ( + "encoding/binary" + "fmt" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "net" +) + +// EthernetBroadcast is the broadcast MAC address used by Ethernet. +// var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + +// EthernetWithTrailer is the layer for Ethernet frame headers. +type EthernetWithTrailer struct { + layers.BaseLayer + SrcMAC, DstMAC net.HardwareAddr + EthernetType layers.EthernetType + // Length is only set if a length field exists within this header. Ethernet + // headers follow two different standards, one that uses an EthernetType, the + // other which defines a length the follows with a LLC header (802.3). If the + // former is the case, we set EthernetType and Length stays 0. In the latter + // case, we set Length and EthernetType = EthernetTypeLLC. + Length uint16 + Trailer []byte +} + +// LayerType returns LayerTypeEthernet +func (e *EthernetWithTrailer) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet } + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (e *EthernetWithTrailer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if len(e.DstMAC) != 6 { + return fmt.Errorf("invalid dst MAC: %v", e.DstMAC) + } + if len(e.SrcMAC) != 6 { + return fmt.Errorf("invalid src MAC: %v", e.SrcMAC) + } + payload := b.Bytes() + bytes, err := b.PrependBytes(14) + if err != nil { + return err + } + copy(bytes, e.DstMAC) + copy(bytes[6:], e.SrcMAC) + if e.Length != 0 || e.EthernetType == layers.EthernetTypeLLC { + if opts.FixLengths { + e.Length = uint16(len(payload)) + } + if e.EthernetType != layers.EthernetTypeLLC { + return fmt.Errorf("ethernet type %v not compatible with length value %v", e.EthernetType, e.Length) + } else if e.Length > 0x0600 { + return fmt.Errorf("invalid ethernet length %v", e.Length) + } + binary.BigEndian.PutUint16(bytes[12:], e.Length) + } else { + binary.BigEndian.PutUint16(bytes[12:], uint16(e.EthernetType)) + } + length := len(b.Bytes()) + if length < 60 { + // Pad out to 60 bytes. + padding, err := b.AppendBytes(60 - length) + if err != nil { + return err + } + copy(padding, lotsOfZeros[:]) + } + + //todo: find a way to put the trailer here + trailer, err := b.AppendBytes(len(e.Trailer)) + if err != nil { + return err + } + copy(trailer, e.Trailer) + // todo: some of this gets gobbled up as framecheck sequence, putting a 4 byte 0 in the trailer to avoid that + checksum, err := b.AppendBytes(4) + if err != nil { + return err + } + copy(checksum, lotsOfZeros[:]) + return nil +} + +var lotsOfZeros [1024]byte