Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Associate corresponding process information with each network packet. #376

Merged
merged 7 commits into from
Jul 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/cmd/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down Expand Up @@ -89,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}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
1 change: 1 addition & 0 deletions kern/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions kern/ecapture.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <uapi/linux/ptrace.h>
#include <linux/bpf.h>
#include <linux/socket.h>
#include <net/sock.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
Expand Down
2 changes: 0 additions & 2 deletions kern/openssl_masterkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
145 changes: 126 additions & 19 deletions kern/tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,39 @@
// limitations under the License.

#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;
};

typedef struct net_id {
struct in6_addr address;
u16 port;
u16 protocol;
} net_id_t;
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];
};

typedef struct net_ctx {
u32 host_tid;
struct net_ctx_t {
u32 pid;
char comm[TASK_COMM_LEN];
} net_ctx_t;
// u8 cmdline[PATH_MAX_LEN];
};

////////////////////// ebpf maps //////////////////////
struct {
Expand All @@ -46,17 +60,28 @@ 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");
*/

////////////////////// 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);
Expand Down Expand Up @@ -86,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)) >
Expand All @@ -114,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
Expand All @@ -130,12 +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
net_id_t connect_id = {0};


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
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};
// 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;
Expand Down Expand Up @@ -168,4 +230,49 @@ int egress_cls_func(struct __sk_buff *skb) {
SEC("classifier/ingress")
int ingress_cls_func(struct __sk_buff *skb) {
return capture_packets(skb, true);
};
};

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 0;
}
#endif
struct sock *sk = (struct sock *)PT_REGS_PARM1(ctx);
if (sk == NULL) {
return 0;
}

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);

struct net_id_t conn_id = {0};
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));
//
// 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 0;
}
86 changes: 86 additions & 0 deletions pkg/util/ethernet/trailer.go
Original file line number Diff line number Diff line change
@@ -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
Loading