diff --git a/kern/boringssl_masterkey.h b/kern/boringssl_masterkey.h index 515ca0117..3c24c8852 100644 --- a/kern/boringssl_masterkey.h +++ b/kern/boringssl_masterkey.h @@ -113,7 +113,8 @@ static __always_inline struct mastersecret_bssl_t *make_event() { // in boringssl, the master secret is stored in src/ssl/handshake.cc 581 // const SSL_SESSION *ssl_handshake_session(const SSL_HANDSHAKE *hs) { -static __always_inline u64 get_session_addr(void *ssl_st_ptr, u64 s3_address, u64 ssl_hs_st_ptr) { +static __always_inline u64 get_session_addr(void *ssl_st_ptr, u64 s3_address, + u64 ssl_hs_st_ptr) { u64 tmp_address; int ret; @@ -220,7 +221,8 @@ int probe_ssl_master_key(struct pt_regs *ctx) { ret = bpf_probe_read_user(&ssl_hs_st_addr, sizeof(ssl_hs_st_addr), ssl_hs_st_ptr); if (ret || ssl_hs_st_addr == 0) { -// debug_bpf_printk("bpf_probe_read ssl_hs_st_ptr failed, ret :%d\n", ret); + // debug_bpf_printk("bpf_probe_read ssl_hs_st_ptr failed, ret + // :%d\n", ret); return 0; } @@ -241,7 +243,7 @@ int probe_ssl_master_key(struct pt_regs *ctx) { (u64 *)(ssl_hs_st_addr + BSSL__SSL_HANDSHAKE_CLIENT_VERSION); ret = bpf_probe_read_user(&client_version, sizeof(client_version), ssl_hs_cv_ptr); -// if (ret || client_version == 0) { + // if (ret || client_version == 0) { if (ret) { debug_bpf_printk( "bpf_probe_read ssl_hs_st_ptr failed, ret :%d, client_version:%d\n", @@ -261,15 +263,17 @@ int probe_ssl_master_key(struct pt_regs *ctx) { // ssl_client_hs_state_t::ssl3_hs_state=5 // tls13_server_hs_state_t::state13_read_second_client_flight -// if (ssl3_hs_state.state == 5 && ssl3_hs_state.tls13_state < 8) { -// return 0; -// } + // if (ssl3_hs_state.state == 5 && ssl3_hs_state.tls13_state < 8) { + // return 0; + // } ///////////// debug info ///////// - debug_bpf_printk("client_version:%d, state:%d, tls13_state:%d\n", client_version, ssl3_hs_state.state, + debug_bpf_printk("client_version:%d, state:%d, tls13_state:%d\n", + client_version, ssl3_hs_state.state, ssl3_hs_state.tls13_state); // debug_bpf_printk("openssl uprobe/SSL_write masterKey PID :%d\n", pid); - debug_bpf_printk("TLS version :%d, hash_len:%d, \n", mastersecret->version, hash_len); + debug_bpf_printk("TLS version :%d, hash_len:%d, \n", mastersecret->version, + hash_len); // 判断当前tls链接状态 // handshake->handshake_finalized = hs_st_addr + BSSL__SSL_HANDSHAKE_HINTS + s32 all_bool; @@ -289,15 +293,16 @@ int probe_ssl_master_key(struct pt_regs *ctx) { if (mastersecret->version != TLS1_3_VERSION) { // state12_finish_server_handshake // state12_done - if (ssl3_hs_state.state < 20) { + if (ssl3_hs_state.state < 20) { // not finished yet. return 0; } // Get ssl_session_st pointer u64 ssl_session_st_addr; - ssl_session_st_addr = get_session_addr(ssl_st_ptr, s3_address, ssl_hs_st_addr); + ssl_session_st_addr = + get_session_addr(ssl_st_ptr, s3_address, ssl_hs_st_addr); if (ssl_session_st_addr == 0) { -// debug_bpf_printk("ssl_session_st_addr is null\n"); + // debug_bpf_printk("ssl_session_st_addr is null\n"); return 0; } debug_bpf_printk("s3_address:%llx, ssl_session_st_addr addr :%llx\n", diff --git a/kern/common.h b/kern/common.h index a0c407f7b..55b170612 100644 --- a/kern/common.h +++ b/kern/common.h @@ -40,14 +40,14 @@ #define SA_DATA_LEN 14 #define BASH_ERRNO_DEFAULT 128 -///////// for TC & XDP ebpf programs in openssl_tc.h +///////// for TC & XDP ebpf programs in tc.h #define TC_ACT_OK 0 #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define SKB_MAX_DATA_SIZE 2048 // .rodata section bug via : https://github.com/gojue/ecapture/issues/39 #ifndef KERNEL_LESS_5_2 -// alawyse, we used it in openssl_tc.h +// alawyse, we used it in tc.h const volatile u64 target_port = 443; // Optional Target PID and UID diff --git a/kern/gotls.h b/kern/go_argument.h similarity index 97% rename from kern/gotls.h rename to kern/go_argument.h index 7779f9b6d..c590e77df 100644 --- a/kern/gotls.h +++ b/kern/go_argument.h @@ -19,10 +19,6 @@ // false: newer //volatile const bool is_register_abi; -// // TLS record types in golang tls package -#define recordTypeApplicationData 23 - - // golang register-based ABI via https://tip.golang.org/src/cmd/compile/abi-internal #ifndef NOCORE diff --git a/kern/gotls_kern.c b/kern/gotls_kern.c index 24c5ef8fb..061d12ffb 100644 --- a/kern/gotls_kern.c +++ b/kern/gotls_kern.c @@ -14,7 +14,17 @@ /* Copyright © 2022 Hengqi Chen */ #include "ecapture.h" -#include "gotls.h" +#include "go_argument.h" +#include "tc.h" + +#define GOTLS_RANDOM_SIZE 32 + +// max length is "CLIENT_HANDSHAKE_TRAFFIC_SECRET"=31 +#define MASTER_SECRET_KEY_LEN 32 +#define EVP_MAX_MD_SIZE 64 + +// // TLS record types in golang tls package +#define recordTypeApplicationData 23 struct go_tls_event { u64 ts_ns; @@ -25,6 +35,22 @@ struct go_tls_event { char data[MAX_DATA_SIZE_OPENSSL]; }; +struct mastersecret_gotls_t { + u8 label[MASTER_SECRET_KEY_LEN]; + u8 labellen; + u8 client_random[EVP_MAX_MD_SIZE]; + u8 client_random_len; + u8 secret_[EVP_MAX_MD_SIZE]; + u8 secret_len; +}; + +/////////////////////////BPF MAPS //////////////////////////////// + +// bpf map +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); +} mastersecret_go_events SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); } events SEC(".maps"); @@ -57,13 +83,15 @@ static __always_inline struct go_tls_event *get_gotls_event() { return bpf_map_lookup_elem(>e_context, &id); } -static __always_inline int gotls_text(struct pt_regs *ctx, bool is_register_abi) { +static __always_inline int gotls_text(struct pt_regs *ctx, + bool is_register_abi) { s32 record_type, len; const char *str; - void * record_type_ptr; - void * len_ptr; + void *record_type_ptr; + void *len_ptr; record_type_ptr = (void *)go_get_argument(ctx, is_register_abi, 2); - bpf_probe_read_kernel(&record_type, sizeof(record_type), (void *)&record_type_ptr); + bpf_probe_read_kernel(&record_type, sizeof(record_type), + (void *)&record_type_ptr); str = (void *)go_get_argument(ctx, is_register_abi, 3); len_ptr = (void *)go_get_argument(ctx, is_register_abi, 4); bpf_probe_read_kernel(&len, sizeof(len), (void *)&len_ptr); @@ -79,7 +107,8 @@ static __always_inline int gotls_text(struct pt_regs *ctx, bool is_register_abi) } event->data_len = len; - int ret = bpf_probe_read_user(&event->data, sizeof(event->data), (void*)str); + int ret = + bpf_probe_read_user(&event->data, sizeof(event->data), (void *)str); if (ret < 0) { debug_bpf_printk( "gotls_text bpf_probe_read_user_str failed, ret:%d, str:%d\n", ret, @@ -91,18 +120,110 @@ static __always_inline int gotls_text(struct pt_regs *ctx, bool is_register_abi) return 0; } -// capture golang tls plaintext, supported golang stack-based ABI (go version >= 1.17) -// type recordType uint8 -// writeRecordLocked(typ recordType, data []byte) +// capture golang tls plaintext, supported golang stack-based ABI (go version +// >= 1.17) type recordType uint8 writeRecordLocked(typ recordType, data []byte) SEC("uprobe/gotls_text_register") -int gotls_text_register(struct pt_regs *ctx) { - return gotls_text(ctx, true); -} +int gotls_text_register(struct pt_regs *ctx) { return gotls_text(ctx, true); } -// capture golang tls plaintext, supported golang stack-based ABI (go version < 1.17) -// type recordType uint8 -// writeRecordLocked(typ recordType, data []byte) +// capture golang tls plaintext, supported golang stack-based ABI (go version +// < 1.17) type recordType uint8 writeRecordLocked(typ recordType, data []byte) SEC("uprobe/gotls_text_stack") -int gotls_text_stack(struct pt_regs *ctx) { - return gotls_text(ctx, false); -} \ No newline at end of file +int gotls_text_stack(struct pt_regs *ctx) { return gotls_text(ctx, false); } + +/* + * crypto/tls/common.go + * func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error + */ +static __always_inline int gotls_mastersecret(struct pt_regs *ctx, + bool is_register_abi) { + // const char *label, *clientrandom, *secret; + void *lab_ptr, *cr_ptr, *secret_ptr; + void *lab_len_ptr, *cr_len_ptr, *secret_len_ptr; + s32 lab_len, cr_len, secret_len; + + /* + * + * in golang struct, slice header like this + * type slice struct { + * array unsafe.Pointer + * len int + * cap int + * } + * so, arument index are in the order one by one + * + */ + lab_ptr = (void *)go_get_argument(ctx, is_register_abi, 2); + lab_len_ptr = (void *)go_get_argument(ctx, is_register_abi, 3); + cr_ptr = (void *)go_get_argument(ctx, is_register_abi, 4); + cr_len_ptr = (void *)go_get_argument(ctx, is_register_abi, 5); + secret_ptr = (void *)go_get_argument(ctx, is_register_abi, 7); + secret_len_ptr = (void *)go_get_argument(ctx, is_register_abi, 8); + + bpf_probe_read_kernel(&lab_len, sizeof(lab_len), (void *)&lab_len_ptr); + bpf_probe_read_kernel(&cr_len, sizeof(lab_len), (void *)&cr_len_ptr); + bpf_probe_read_kernel(&secret_len, sizeof(lab_len), + (void *)&secret_len_ptr); + + if (lab_len <= 0 || cr_len <= 0 || secret_len <= 0) { + return 0; + } + + debug_bpf_printk( + "gotls_mastersecret read params length success, lab_len:%d, cr_len:%d, " + "secret_len:%d\n", + lab_len, cr_len, secret_len); + + struct mastersecret_gotls_t mastersecret_gotls = {}; + mastersecret_gotls.labellen = lab_len; + mastersecret_gotls.client_random_len = cr_len; + mastersecret_gotls.secret_len = secret_len; + int ret = bpf_probe_read_user_str(&mastersecret_gotls.label, + sizeof(mastersecret_gotls.label), + (void *)lab_ptr); + if (ret < 0) { + debug_bpf_printk( + "gotls_mastersecret read mastersecret label failed, ret:%d, " + "lab_ptr:%p\n", + ret, lab_ptr); + return 0; + } + + debug_bpf_printk("gotls_mastersecret read mastersecret label%s\n", + mastersecret_gotls.label); + ret = bpf_probe_read_user_str(&mastersecret_gotls.client_random, + sizeof(mastersecret_gotls.client_random), + (void *)cr_ptr); + if (ret < 0) { + debug_bpf_printk( + "gotls_mastersecret read mastersecret client_random failed, " + "ret:%d, cr_ptr:%p\n", + ret, cr_ptr); + return 0; + } + + ret = bpf_probe_read_user_str(&mastersecret_gotls.secret_, + sizeof(mastersecret_gotls.secret_), + (void *)secret_ptr); + if (ret < 0) { + debug_bpf_printk( + "gotls_mastersecret read mastersecret secret_ failed, ret:%d, " + "secret_ptr:%p\n", + ret, secret_ptr); + return 0; + } + + bpf_perf_event_output(ctx, &mastersecret_go_events, BPF_F_CURRENT_CPU, + &mastersecret_gotls, + sizeof(struct mastersecret_gotls_t)); + return 0; +} + +SEC("uprobe/gotls_mastersecret_register") +int gotls_mastersecret_register(struct pt_regs *ctx) { + return gotls_mastersecret(ctx, true); +} + +SEC("uprobe/gotls_mastersecret_stack") +int gotls_mastersecret_stack(struct pt_regs *ctx) { + return gotls_mastersecret(ctx, false); +} diff --git a/kern/openssl.h b/kern/openssl.h index 64c25c345..aa667dc2d 100644 --- a/kern/openssl.h +++ b/kern/openssl.h @@ -13,7 +13,7 @@ // limitations under the License. #include "ecapture.h" -#include "openssl_tc.h" +#include "tc.h" enum ssl_data_event_type { kSSLRead, kSSLWrite }; const u32 invalidFD = 0; diff --git a/kern/openssl_tc.h b/kern/tc.h similarity index 100% rename from kern/openssl_tc.h rename to kern/tc.h diff --git a/user/event/event_mastersecret_gotls.go b/user/event/event_mastersecret_gotls.go new file mode 100644 index 000000000..59bc3dab2 --- /dev/null +++ b/user/event/event_mastersecret_gotls.go @@ -0,0 +1,104 @@ +// Copyright 2022 CFC4N . All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +// gotls_mastersecret_events + +const ( + GotlsRandomSize = 32 + MasterSecretKeyLen = 32 +) + +type MasterSecretGotlsEvent struct { + event_type EventType + Label [MasterSecretKeyLen]byte `json:"label"` // label name + LabelLen uint8 `json:"labelLen"` + ClientRandom [EvpMaxMdSize]byte `json:"clientRandom"` // Client Random + ClientRandomLen uint8 `json:"clientRandomLen"` + MasterSecret [EvpMaxMdSize]byte `json:"masterSecret"` // Master Secret + MasterSecretLen uint8 `json:"masterSecretLen"` + payload string +} + +func (this *MasterSecretGotlsEvent) Decode(payload []byte) (err error) { + buf := bytes.NewBuffer(payload) + if err = binary.Read(buf, binary.LittleEndian, &this.Label); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.LabelLen); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.ClientRandom); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.ClientRandomLen); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.MasterSecret); err != nil { + return + } + if err = binary.Read(buf, binary.LittleEndian, &this.MasterSecretLen); err != nil { + return + } + if int(this.LabelLen) > len(this.Label) { + return fmt.Errorf("invalid label length, LablenLen:%d, len(Label):%d", this.LabelLen, len(this.Label)) + } + if int(this.ClientRandomLen) > len(this.ClientRandom) { + return fmt.Errorf("invalid label length, ClientRandomLen:%d, len(ClientRandom):%d", this.ClientRandomLen, len(this.ClientRandom)) + } + if int(this.MasterSecretLen) > len(this.MasterSecret) { + return fmt.Errorf("invalid label length, MasterSecretLen:%d, len(MasterSecret):%d", this.MasterSecretLen, len(this.MasterSecret)) + } + this.payload = fmt.Sprintf("%s %02x %02x", this.Label, this.ClientRandom, this.MasterSecret) + return nil +} + +func (this *MasterSecretGotlsEvent) StringHex() string { + s := fmt.Sprintf("Label%s, ClientRandom:%02x, secret:%02x", this.Label[0:this.LabelLen], this.ClientRandom[0:this.ClientRandomLen], this.MasterSecret[0:this.MasterSecretLen]) + return s +} + +func (this *MasterSecretGotlsEvent) String() string { + s := fmt.Sprintf("Label:%s, ClientRandom:%02x, secret:%02x", this.Label[0:this.LabelLen], this.ClientRandom[0:this.ClientRandomLen], this.MasterSecret[0:this.MasterSecretLen]) + return s +} + +func (this *MasterSecretGotlsEvent) Clone() IEventStruct { + event := new(MasterSecretGotlsEvent) + event.event_type = EventTypeModuleData + return event +} + +func (this *MasterSecretGotlsEvent) EventType() EventType { + return this.event_type +} + +func (this *MasterSecretGotlsEvent) GetUUID() string { + return fmt.Sprintf("%02X", this.ClientRandom) +} + +func (this *MasterSecretGotlsEvent) Payload() []byte { + return []byte(this.payload) +} + +func (this *MasterSecretGotlsEvent) PayloadLen() int { + return len(this.payload) +} diff --git a/user/module/probe_gotls.go b/user/module/probe_gotls.go index 4d68a113b..b76b56bca 100644 --- a/user/module/probe_gotls.go +++ b/user/module/probe_gotls.go @@ -8,8 +8,14 @@ import ( "ecapture/pkg/proc" "ecapture/user/config" "ecapture/user/event" + "errors" + "fmt" "log" "math" + "os" + "path/filepath" + "sync" + "time" "github.com/cilium/ebpf" manager "github.com/gojue/ebpfmanager" @@ -21,12 +27,26 @@ func init() { Register(mod) } +const ( + goTlsHookFunc = "crypto/tls.(*Conn).writeRecordLocked" + goTlsMasterSecretFunc = "crypto/tls.(*Config).writeKeyLog" +) + // GoTLSProbe represents a probe for Go SSL type GoTLSProbe struct { Module - mngr *manager.Manager - path string - isRegisterABI bool + MTCProbe + bpfManager *manager.Manager + bpfManagerOptions manager.Options + eventFuncMaps map[*ebpf.Map]event.IEventStruct + eventMaps []*ebpf.Map + + keyloggerFilename string + keylogger *os.File + masterSecrets map[string]bool + eBPFProgramType EBPFPROGRAMTYPE + path string + isRegisterABI bool } func (this *GoTLSProbe) Init(ctx context.Context, l *log.Logger, cfg config.IConfig) error { @@ -34,6 +54,10 @@ func (this *GoTLSProbe) Init(ctx context.Context, l *log.Logger, cfg config.ICon this.conf = cfg this.Module.SetChild(this) + this.eventMaps = make([]*ebpf.Map, 0, 2) + this.eventFuncMaps = make(map[*ebpf.Map]event.IEventStruct) + + this.masterSecrets = make(map[string]bool) this.path = cfg.(*config.GoTLSConfig).Path ver, err := proc.ExtraceGoVersion(this.path) if err != nil { @@ -44,6 +68,41 @@ func (this *GoTLSProbe) Init(ctx context.Context, l *log.Logger, cfg config.ICon if ver.After(1, 17) { this.isRegisterABI = true } + + this.keyloggerFilename = "ecapture_masterkey.log" + file, err := os.OpenFile(this.keyloggerFilename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return err + } + this.keylogger = file + + var writeFile = this.conf.(*config.GoTLSConfig).Write + if len(writeFile) > 0 { + this.eBPFProgramType = EbpfprogramtypeOpensslTc + fileInfo, err := filepath.Abs(writeFile) + if err != nil { + return err + } + this.pcapngFilename = fileInfo + } else { + this.eBPFProgramType = EbpfprogramtypeOpensslUprobe + this.logger.Printf("%s\tmaster key keylogger: %s\n", this.Name(), this.keyloggerFilename) + } + + var ts unix.Timespec + err = unix.ClockGettime(unix.CLOCK_MONOTONIC, &ts) + if err != nil { + return err + } + startTime := ts.Nano() + bootTime := time.Now().UnixNano() - startTime + + this.startTime = uint64(startTime) + this.bootTime = uint64(bootTime) + + this.tcPackets = make([]*TcPacket, 0, 1024) + this.tcPacketLocker = &sync.Mutex{} + this.masterKeyBuffer = bytes.NewBuffer([]byte{}) return nil } @@ -52,85 +111,264 @@ func (this *GoTLSProbe) Name() string { } func (this *GoTLSProbe) Start() error { + return this.start() +} + +func (this *GoTLSProbe) start() error { + var err error + switch this.eBPFProgramType { + case EbpfprogramtypeOpensslTc: + this.logger.Printf("%s\tTC MODEL\n", this.Name()) + err = this.setupManagersTC() + case EbpfprogramtypeOpensslUprobe: + this.logger.Printf("%s\tUPROBE MODEL\n", this.Name()) + err = this.setupManagersUprobe() + default: + this.logger.Printf("%s\tUPROBE MODEL\n", this.Name()) + err = this.setupManagersUprobe() + } + if err != nil { + return err + } + + var bpfFileName = this.geteBPFName("user/bytecode/gotls_kern.o") + this.logger.Printf("%s\tBPF bytecode filename:%s\n", this.Name(), bpfFileName) + byteBuf, err := assets.Asset(bpfFileName) + if err != nil { + return err + } + + if err = this.bpfManager.InitWithOptions(bytes.NewReader(byteBuf), this.bpfManagerOptions); err != nil { + return fmt.Errorf("couldn't init manager %v", err) + } + // start the bootstrap manager + if err = this.bpfManager.Start(); err != nil { + return fmt.Errorf("couldn't start bootstrap manager %v .", err) + } + + // 加载map信息,map对应events decode表。 + switch this.eBPFProgramType { + case EbpfprogramtypeOpensslTc: + err = this.initDecodeFunTC() + case EbpfprogramtypeOpensslUprobe: + err = this.initDecodeFun() + default: + err = this.initDecodeFun() + } + if err != nil { + return err + } + return nil +} + +func (this *GoTLSProbe) setupManagersUprobe() error { var ( - sec string - fn string + sec, ms_sec string + fn, ms_fn string ) if this.isRegisterABI { sec = "uprobe/gotls_text_register" fn = "gotls_text_register" + ms_sec = "uprobe/gotls_mastersecret_register" + ms_fn = "gotls_mastersecret_register" } else { sec = "uprobe/gotls_text_stack" fn = "gotls_text_stack" + ms_sec = "uprobe/gotls_mastersecret_stack" + ms_fn = "gotls_mastersecret_stack" } this.logger.Printf("%s\teBPF Function Name:%s, isRegisterABI:%t\n", this.Name(), fn, this.isRegisterABI) - this.mngr = &manager.Manager{ + this.bpfManager = &manager.Manager{ Probes: []*manager.Probe{ { Section: sec, EbpfFuncName: fn, - AttachToFuncName: "crypto/tls.(*Conn).writeRecordLocked", + AttachToFuncName: goTlsHookFunc, BinaryPath: this.path, }, - - //{ - // Section: "uprobe/gotls_masterkey", - // EbpfFuncName: "gotls_masterkey", - // AttachToFuncName: "crypto/tls.(*Conn).writeRecordLocked", - // BinaryPath: this.path, - //}, + // gotls master secrets + // crypto/tls.(*Config).writeKeyLog + // crypto/tls/common.go + /* + func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error { + } + */ + { + Section: ms_sec, + EbpfFuncName: ms_fn, + AttachToFuncName: goTlsMasterSecretFunc, + BinaryPath: this.path, + UID: "uprobe_gotls_master_secret", + }, }, Maps: []*manager.Map{ + { + Name: "mastersecret_go_events", + }, { Name: "events", }, }, } - // crypto/tls.(*Config).writeKeyLog - // crypto/tls/common.go - /* - func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error { - } - */ + this.bpfManagerOptions = manager.Options{ + DefaultKProbeMaxActive: 512, - var bpfFileName = this.geteBPFName("user/bytecode/gotls_kern.o") - this.logger.Printf("%s\tBPF bytecode filename:%s\n", this.Name(), bpfFileName) - byteBuf, err := assets.Asset(bpfFileName) - if err != nil { - return err - } + VerifierOptions: ebpf.CollectionOptions{ + Programs: ebpf.ProgramOptions{ + LogSize: 2097152, + }, + }, - opts := manager.Options{ RLimit: &unix.Rlimit{ Cur: math.MaxUint64, Max: math.MaxUint64, }, } - if err := this.mngr.InitWithOptions(bytes.NewReader(byteBuf), opts); err != nil { - return err + + if this.conf.EnableGlobalVar() { + // 填充 RewriteContants 对应map + this.bpfManagerOptions.ConstantEditors = this.constantEditor() + } + return nil +} + +// 通过elf的常量替换方式传递数据 +func (this *GoTLSProbe) constantEditor() []manager.ConstantEditor { + var editor = []manager.ConstantEditor{ + { + Name: "target_pid", + Value: uint64(this.conf.GetPid()), + //FailOnMissing: true, + }, + { + Name: "target_uid", + Value: uint64(this.conf.GetUid()), + }, + { + Name: "target_port", + Value: uint64(this.conf.(*config.GoTLSConfig).Port), + }, } - return this.mngr.Start() + if this.conf.GetPid() <= 0 { + this.logger.Printf("%s\ttarget all process. \n", this.Name()) + } else { + this.logger.Printf("%s\ttarget PID:%d \n", this.Name(), this.conf.GetPid()) + } + + if this.conf.GetUid() <= 0 { + this.logger.Printf("%s\ttarget all users. \n", this.Name()) + } else { + this.logger.Printf("%s\ttarget UID:%d \n", this.Name(), this.conf.GetUid()) + } + + return editor } -func (this *GoTLSProbe) Events() []*ebpf.Map { - var maps []*ebpf.Map +func (this *GoTLSProbe) initDecodeFun() error { - m, ok, err := this.mngr.GetMap("events") - if err != nil || !ok { - return maps + m, found, err := this.bpfManager.GetMap("events") + if err != nil { + return err + } + if !found { + return errors.New("cant found map:tls_events") } - maps = append(maps, m) - return maps + this.eventMaps = append(this.eventMaps, m) + gotlsEvent := &event.GoTLSEvent{} + //sslEvent.SetModule(this) + this.eventFuncMaps[m] = gotlsEvent + // master secrets map at ebpf code + MasterkeyEventsMap, found, err := this.bpfManager.GetMap("mastersecret_go_events") + if err != nil { + return err + } + if !found { + return errors.New("cant found map:mastersecret_events") + } + this.eventMaps = append(this.eventMaps, MasterkeyEventsMap) + + var masterkeyEvent event.IEventStruct + + // goTLS Event struct + masterkeyEvent = &event.MasterSecretGotlsEvent{} + + this.eventFuncMaps[MasterkeyEventsMap] = masterkeyEvent + return nil } func (this *GoTLSProbe) DecodeFun(m *ebpf.Map) (event.IEventStruct, bool) { - return &event.GoTLSEvent{}, true + fun, found := this.eventFuncMaps[m] + return fun, found } func (this *GoTLSProbe) Close() error { + + if this.eBPFProgramType == EbpfprogramtypeOpensslTc { + this.logger.Printf("%s\tsaving pcapng file %s\n", this.Name(), this.pcapngFilename) + i, err := this.savePcapng() + if err != nil { + this.logger.Printf("%s\tsave pcanNP failed, error:%v. \n", this.Name(), err) + } + if i == 0 { + this.logger.Printf("nothing captured, please check your network interface, see \"ecapture tls -h\" for more information.") + } else { + this.logger.Printf("%s\t save %d packets into pcapng file.\n", this.Name(), i) + } + } + + this.logger.Printf("%s\tclose. \n", this.Name()) + if err := this.bpfManager.Stop(manager.CleanAll); err != nil { + return fmt.Errorf("couldn't stop manager %v .", err) + } return this.Module.Close() } + +func (this *GoTLSProbe) saveMasterSecret(secretEvent *event.MasterSecretGotlsEvent) { + var label, clientRandom, secret string + label = string(secretEvent.Label[0:secretEvent.LabelLen]) + clientRandom = string(secretEvent.ClientRandom[0:secretEvent.ClientRandomLen]) + secret = string(secretEvent.MasterSecret[0:secretEvent.MasterSecretLen]) + + var k = fmt.Sprintf("%s-%02x", label, clientRandom) + + _, f := this.masterSecrets[k] + if f { + // 已存在该随机数的masterSecret,不需要重复写入 + return + } + + // TODO 保存多个lable 整组里??? + // save to file + var b string + b = fmt.Sprintf("%s %02x %02x\n", label, clientRandom, secret) + l, e := this.keylogger.WriteString(b) + if e != nil { + this.logger.Fatalf("%s: save masterSecrets to file error:%s", secretEvent.String(), e.Error()) + return + } + this.logger.Printf("%s: save CLIENT_RANDOM %02x to file success, %d bytes", label, clientRandom, l) + e = this.savePcapngSslKeyLog([]byte(b)) + if e != nil { + this.logger.Fatalf("%s: save masterSecrets to pcapng error:%s", secretEvent.String(), e.Error()) + return + } + +} + +func (this *GoTLSProbe) Dispatcher(eventStruct event.IEventStruct) { + // detect eventStruct type + switch eventStruct.(type) { + case *event.MasterSecretGotlsEvent: + this.saveMasterSecret(eventStruct.(*event.MasterSecretGotlsEvent)) + case *event.TcSkbEvent: + err := this.dumpTcSkb(eventStruct.(*event.TcSkbEvent)) + if err != nil { + this.logger.Printf("%s\t save packet error %s .\n", this.Name(), err.Error()) + } + } + //this.logger.Println(eventStruct) +} diff --git a/user/module/probe_gotls_tc.go b/user/module/probe_gotls_tc.go new file mode 100644 index 000000000..fdea94132 --- /dev/null +++ b/user/module/probe_gotls_tc.go @@ -0,0 +1,168 @@ +// Copyright 2022 CFC4N . All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package module + +import ( + "ecapture/user/config" + "ecapture/user/event" + "errors" + "fmt" + "github.com/cilium/ebpf" + manager "github.com/gojue/ebpfmanager" + "golang.org/x/sys/unix" + "math" + "net" +) + +func (this *GoTLSProbe) setupManagersTC() error { + var ifname string + + ifname = this.conf.(*config.GoTLSConfig).Ifname + this.ifName = ifname + interf, err := net.InterfaceByName(this.ifName) + if err != nil { + return err + } + + // loopback devices are special, some tc probes should be skipped + isNetIfaceLo := interf.Flags&net.FlagLoopback == net.FlagLoopback + skipLoopback := true // TODO: detect loopback devices via aquasecrity/tracee/pkg/ebpf/probes/probe.go line 322 + if isNetIfaceLo && skipLoopback { + return fmt.Errorf("%s\t%s is a loopback interface, skip it", this.Name(), this.ifName) + } + this.ifIdex = interf.Index + + this.logger.Printf("%s\tHOOK type:golang elf, binrayPath:%s\n", this.Name(), this.path) + this.logger.Printf("%s\tIfname:%s, Ifindex:%d, Port:%d, Pcapng filepath:%s\n", this.Name(), this.ifName, this.ifIdex, this.conf.(*config.GoTLSConfig).Port, this.pcapngFilename) + this.logger.Printf("%s\tHook masterKey function:%s\n", this.Name(), goTlsMasterSecretFunc) + + // create pcapng writer + netIfs, err := net.Interfaces() + if err != nil { + return err + } + + err = this.createPcapng(netIfs) + if err != nil { + return err + } + + var ( + sec string + fn string + ) + + if this.isRegisterABI { + sec = "uprobe/gotls_mastersecret_register" + fn = "gotls_mastersecret_register" + } else { + sec = "uprobe/gotls_mastersecret_stack" + fn = "gotls_mastersecret_stack" + } + + this.bpfManager = &manager.Manager{ + Probes: []*manager.Probe{ + { + Section: "classifier/egress", + EbpfFuncName: "egress_cls_func", + Ifname: this.ifName, + NetworkDirection: manager.Egress, + }, + { + Section: "classifier/ingress", + EbpfFuncName: "ingress_cls_func", + Ifname: this.ifName, + NetworkDirection: manager.Ingress, + }, + // -------------------------------------------------- + + // gotls master secrets + { + Section: sec, + EbpfFuncName: fn, + AttachToFuncName: goTlsMasterSecretFunc, + BinaryPath: this.path, + UID: "uprobe_gotls_master_secret", + }, + }, + + Maps: []*manager.Map{ + { + Name: "mastersecret_go_events", + }, + { + Name: "skb_events", + }, + }, + } + + this.bpfManagerOptions = manager.Options{ + DefaultKProbeMaxActive: 512, + + VerifierOptions: ebpf.CollectionOptions{ + Programs: ebpf.ProgramOptions{ + LogSize: 2097152, + }, + }, + + RLimit: &unix.Rlimit{ + Cur: math.MaxUint64, + Max: math.MaxUint64, + }, + } + + if this.conf.EnableGlobalVar() { + // 填充 RewriteContants 对应map + this.bpfManagerOptions.ConstantEditors = this.constantEditor() + } + return nil +} + +func (this *GoTLSProbe) initDecodeFunTC() error { + //SkbEventsMap 与解码函数映射 + SkbEventsMap, found, err := this.bpfManager.GetMap("skb_events") + if err != nil { + return err + } + if !found { + return errors.New("cant found map:skb_events") + } + this.eventMaps = append(this.eventMaps, SkbEventsMap) + sslEvent := &event.TcSkbEvent{} + //sslEvent.SetModule(this) + this.eventFuncMaps[SkbEventsMap] = sslEvent + + // master secrets map at ebpf code + MasterkeyEventsMap, found, err := this.bpfManager.GetMap("mastersecret_go_events") + if err != nil { + return err + } + if !found { + return errors.New("cant found map:mastersecret_events") + } + this.eventMaps = append(this.eventMaps, MasterkeyEventsMap) + + var masterkeyEvent event.IEventStruct + + // goTLS Event struct + masterkeyEvent = &event.MasterSecretGotlsEvent{} + + this.eventFuncMaps[MasterkeyEventsMap] = masterkeyEvent + return nil +} + +func (this *GoTLSProbe) Events() []*ebpf.Map { + return this.eventMaps +} diff --git a/user/module/probe_openssl.go b/user/module/probe_openssl.go index ab7041839..f27dcd78e 100644 --- a/user/module/probe_openssl.go +++ b/user/module/probe_openssl.go @@ -26,7 +26,6 @@ import ( "fmt" "github.com/cilium/ebpf" manager "github.com/gojue/ebpfmanager" - "github.com/google/gopacket/pcapgo" "golang.org/x/sys/unix" "log" "math" @@ -58,27 +57,19 @@ const ( type MOpenSSLProbe struct { Module + MTCProbe bpfManager *manager.Manager bpfManagerOptions manager.Options eventFuncMaps map[*ebpf.Map]event.IEventStruct eventMaps []*ebpf.Map // pid[fd:Addr] - pidConns map[uint32]map[uint32]string + //pidConns map[uint32]map[uint32]string keyloggerFilename string keylogger *os.File masterKeys map[string]bool eBPFProgramType EBPFPROGRAMTYPE - pcapngFilename string - ifIdex int - ifName string - pcapWriter *pcapgo.NgWriter - startTime uint64 - bootTime uint64 - tcPackets []*TcPacket - masterKeyBuffer *bytes.Buffer - tcPacketLocker *sync.Mutex sslVersionBpfMap map[string]string // bpf map key: ssl version, value: bpf map key sslBpfFile string // ssl bpf file @@ -93,7 +84,7 @@ func (this *MOpenSSLProbe) Init(ctx context.Context, logger *log.Logger, conf co this.Module.SetChild(this) this.eventMaps = make([]*ebpf.Map, 0, 2) this.eventFuncMaps = make(map[*ebpf.Map]event.IEventStruct) - this.pidConns = make(map[uint32]map[uint32]string) + //this.pidConns = make(map[uint32]map[uint32]string) this.masterKeys = make(map[string]bool) this.sslVersionBpfMap = make(map[string]string) @@ -227,14 +218,18 @@ func (this *MOpenSSLProbe) start() error { func (this *MOpenSSLProbe) Close() error { if this.eBPFProgramType == EbpfprogramtypeOpensslTc { this.logger.Printf("%s\tsaving pcapng file %s\n", this.Name(), this.pcapngFilename) - err := this.savePcapng() + i, err := this.savePcapng() if err != nil { - return err + this.logger.Printf("%s\tsave pcanNP failed, error:%v. \n", this.Name(), err) + } + if i == 0 { + this.logger.Printf("nothing captured, please check your network interface, see \"ecapture tls -h\" for more information.") + } else { + this.logger.Printf("%s\t save %d packets into pcapng file.\n", this.Name(), i) } } this.logger.Printf("%s\tclose. \n", this.Name()) - if err := this.bpfManager.Stop(manager.CleanAll); err != nil { return fmt.Errorf("couldn't stop manager %v .", err) } @@ -474,59 +469,6 @@ func (this *MOpenSSLProbe) Events() []*ebpf.Map { return this.eventMaps } -func (this *MOpenSSLProbe) AddConn(pid, fd uint32, addr string) { - // save to map - var m map[uint32]string - var f bool - m, f = this.pidConns[pid] - if !f { - m = make(map[uint32]string) - } - m[fd] = addr - this.pidConns[pid] = m - return -} - -// process exit :fd is 0 , delete all pid map -// fd exit :pid > 0, fd > 0, delete fd value -// TODO add fd * pid exit event hook -func (this *MOpenSSLProbe) DelConn(pid, fd uint32) { - // delete from map - if pid == 0 { - return - } - - if fd == 0 { - delete(this.pidConns, pid) - } - - var m map[uint32]string - var f bool - m, f = this.pidConns[pid] - if !f { - return - } - delete(m, fd) - this.pidConns[pid] = m - return -} - -func (this *MOpenSSLProbe) GetConn(pid, fd uint32) string { - addr := "" - var m map[uint32]string - var f bool - m, f = this.pidConns[pid] - if !f { - return ConnNotFound - } - - addr, f = m[fd] - if !f { - return ConnNotFound - } - return addr -} - func (this *MOpenSSLProbe) saveMasterSecret(secretEvent *event.MasterSecretEvent) { var k = fmt.Sprintf("%02x", secretEvent.ClientRandom) @@ -709,13 +651,16 @@ func (this *MOpenSSLProbe) Dispatcher(eventStruct event.IEventStruct) { // detect eventStruct type switch eventStruct.(type) { case *event.ConnDataEvent: - this.AddConn(eventStruct.(*event.ConnDataEvent).Pid, eventStruct.(*event.ConnDataEvent).Fd, eventStruct.(*event.ConnDataEvent).Addr) + //this.AddConn(eventStruct.(*event.ConnDataEvent).Pid, eventStruct.(*event.ConnDataEvent).Fd, eventStruct.(*event.ConnDataEvent).Addr) case *event.MasterSecretEvent: this.saveMasterSecret(eventStruct.(*event.MasterSecretEvent)) case *event.MasterSecretBSSLEvent: this.saveMasterSecretBSSL(eventStruct.(*event.MasterSecretBSSLEvent)) case *event.TcSkbEvent: - this.dumpTcSkb(eventStruct.(*event.TcSkbEvent)) + err := this.dumpTcSkb(eventStruct.(*event.TcSkbEvent)) + if err != nil { + this.logger.Printf("%s\t save packet error %s .\n", this.Name(), err.Error()) + } } //this.logger.Println(eventStruct) } diff --git a/user/module/probe_openssl_tc.go b/user/module/probe_openssl_tc.go index 06c70c8c8..471396290 100644 --- a/user/module/probe_openssl_tc.go +++ b/user/module/probe_openssl_tc.go @@ -21,32 +21,12 @@ import ( "fmt" "github.com/cilium/ebpf" manager "github.com/gojue/ebpfmanager" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/google/gopacket/pcapgo" "golang.org/x/sys/unix" "math" "net" - "os" "strings" - "time" ) -// packets of TC probe -type TcPacket struct { - info gopacket.CaptureInfo - data []byte -} - -type NetCaptureData struct { - PacketLength uint32 `json:"pktLen"` - ConfigIfaceIndex uint32 `json:"ifIndex"` -} - -func (NetCaptureData) GetSizeBytes() uint32 { - return 8 -} - type NetEventMetadata struct { TimeStamp uint64 `json:"timeStamp"` HostTid uint32 `json:"hostTid"` @@ -208,109 +188,3 @@ func (this *MOpenSSLProbe) initDecodeFunTC() error { this.eventFuncMaps[MasterkeyEventsMap] = masterkeyEvent return nil } - -func (this *MOpenSSLProbe) dumpTcSkb(tcEvent *event.TcSkbEvent) { - var timeStamp = this.bootTime + tcEvent.Ts - if err := this.writePacket(tcEvent.Len, this.ifIdex, time.Unix(0, int64(timeStamp)), tcEvent.Payload()); err != nil { - this.logger.Printf("%s\t save packet error %s .\n", this.Name(), err.Error()) - } - return -} - -// save pcapng file ,merge master key into pcapng file TODO -func (this *MOpenSSLProbe) savePcapng() error { - var i int = 0 - err := this.pcapWriter.WriteDecryptionSecretsBlock(pcapgo.DSB_SECRETS_TYPE_TLS, this.masterKeyBuffer.Bytes()) - if err != nil { - return err - } - this.tcPacketLocker.Lock() - defer this.tcPacketLocker.Unlock() - for _, packet := range this.tcPackets { - err := this.pcapWriter.WritePacket(packet.info, packet.data) - i++ - if err != nil { - return err - } - } - this.logger.Printf("%s\t save %d packets into pcapng file.\n", this.Name(), i) - if i == 0 { - this.logger.Printf("nothing captured, please check your network interface, see \"ecapture tls -h\" for more information.") - } - return this.pcapWriter.Flush() -} - -func (this *MOpenSSLProbe) createPcapng(netIfs []net.Interface) error { - pcapFile, err := os.OpenFile(this.pcapngFilename, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return fmt.Errorf("error creating pcap file: %v", err) - } - - // TODO : write Application "ecapture.lua" to decode PID/Comm info. - pcapOption := pcapgo.NgWriterOptions{ - SectionInfo: pcapgo.NgSectionInfo{ - Hardware: "eCapture Hardware", - OS: "", - Application: "ecapture.lua", - Comment: "see https://ecapture.cc for more information. CFC4N ", - }, - } - // write interface description - ngIface := pcapgo.NgInterface{ - Name: this.conf.(*config.OpensslConfig).Ifname, - Comment: "eCapture (旁观者): github.com/gojue/ecapture", - Filter: "", - LinkType: layers.LinkTypeEthernet, - SnapLength: uint32(math.MaxUint16), - } - - pcapWriter, err := pcapgo.NewNgWriterInterface(pcapFile, ngIface, pcapOption) - if err != nil { - return err - } - - // insert other interfaces into pcapng file - for _, iface := range netIfs { - ngIface = pcapgo.NgInterface{ - Name: iface.Name, - Comment: "eCapture (旁观者): github.com/gojue/ecapture", - Filter: "", - LinkType: layers.LinkTypeEthernet, - SnapLength: uint32(math.MaxUint16), - } - - _, err := pcapWriter.AddInterface(ngIface) - if err != nil { - return err - } - } - - // Flush the header - err = pcapWriter.Flush() - if err != nil { - return err - } - - // TODO 保存数据包所属进程ID信息,以LRU Cache方式存储。 - this.pcapWriter = pcapWriter - return nil -} - -func (this *MOpenSSLProbe) writePacket(dataLen uint32, ifaceIdx int, timeStamp time.Time, packetBytes []byte) error { - info := gopacket.CaptureInfo{ - Timestamp: timeStamp, - CaptureLength: int(dataLen), - Length: int(dataLen), - InterfaceIndex: ifaceIdx, - } - - packet := &TcPacket{info: info, data: packetBytes} - - this.tcPackets = append(this.tcPackets, packet) - return nil -} - -func (this *MOpenSSLProbe) savePcapngSslKeyLog(sslKeyLog []byte) (err error) { - _, e := this.masterKeyBuffer.Write(sslKeyLog) - return e -} diff --git a/user/module/probe_tc.go b/user/module/probe_tc.go new file mode 100644 index 000000000..02872a46b --- /dev/null +++ b/user/module/probe_tc.go @@ -0,0 +1,147 @@ +package module + +import ( + "bytes" + "ecapture/user/event" + "fmt" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcapgo" + "math" + "net" + "os" + "sync" + "time" +) + +// packets of TC probe +type TcPacket struct { + info gopacket.CaptureInfo + data []byte +} + +type NetCaptureData struct { + PacketLength uint32 `json:"pktLen"` + ConfigIfaceIndex uint32 `json:"ifIndex"` +} + +func (NetCaptureData) GetSizeBytes() uint32 { + return 8 +} + +type MTCProbe struct { + //logger *log.Logger + //mName string + pcapngFilename string + ifIdex int + ifName string + pcapWriter *pcapgo.NgWriter + startTime uint64 + bootTime uint64 + tcPackets []*TcPacket + masterKeyBuffer *bytes.Buffer + tcPacketLocker *sync.Mutex +} + +func (this *MTCProbe) dumpTcSkb(tcEvent *event.TcSkbEvent) error { + var timeStamp = this.bootTime + tcEvent.Ts + return this.writePacket(tcEvent.Len, this.ifIdex, time.Unix(0, int64(timeStamp)), tcEvent.Payload()) +} + +// save pcapng file ,merge master key into pcapng file TODO +func (this *MTCProbe) savePcapng() (i int, err error) { + err = this.pcapWriter.WriteDecryptionSecretsBlock(pcapgo.DSB_SECRETS_TYPE_TLS, this.masterKeyBuffer.Bytes()) + if err != nil { + return + } + this.tcPacketLocker.Lock() + defer this.tcPacketLocker.Unlock() + for _, packet := range this.tcPackets { + err = this.pcapWriter.WritePacket(packet.info, packet.data) + i++ + if err != nil { + return + } + } + + if i == 0 { + return + } + err = this.pcapWriter.Flush() + return +} + +func (this *MTCProbe) createPcapng(netIfs []net.Interface) error { + pcapFile, err := os.OpenFile(this.pcapngFilename, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return fmt.Errorf("error creating pcap file: %v", err) + } + + // TODO : write Application "ecapture.lua" to decode PID/Comm info. + pcapOption := pcapgo.NgWriterOptions{ + SectionInfo: pcapgo.NgSectionInfo{ + Hardware: "eCapture Hardware", + OS: "", + Application: "ecapture.lua", + Comment: "see https://ecapture.cc for more information. CFC4N ", + }, + } + // write interface description + ngIface := pcapgo.NgInterface{ + Name: this.ifName, + Comment: "eCapture (旁观者): github.com/gojue/ecapture", + Filter: "", + LinkType: layers.LinkTypeEthernet, + SnapLength: uint32(math.MaxUint16), + } + + pcapWriter, err := pcapgo.NewNgWriterInterface(pcapFile, ngIface, pcapOption) + if err != nil { + return err + } + + // insert other interfaces into pcapng file + for _, iface := range netIfs { + ngIface = pcapgo.NgInterface{ + Name: iface.Name, + Comment: "eCapture (旁观者): github.com/gojue/ecapture", + Filter: "", + LinkType: layers.LinkTypeEthernet, + SnapLength: uint32(math.MaxUint16), + } + + _, err := pcapWriter.AddInterface(ngIface) + if err != nil { + return err + } + } + + // Flush the header + err = pcapWriter.Flush() + if err != nil { + return err + } + + // TODO 保存数据包所属进程ID信息,以LRU Cache方式存储。 + this.pcapWriter = pcapWriter + return nil +} + +func (this *MTCProbe) writePacket(dataLen uint32, ifaceIdx int, timeStamp time.Time, packetBytes []byte) error { + info := gopacket.CaptureInfo{ + Timestamp: timeStamp, + CaptureLength: int(dataLen), + Length: int(dataLen), + InterfaceIndex: ifaceIdx, + } + + packet := &TcPacket{info: info, data: packetBytes} + + this.tcPackets = append(this.tcPackets, packet) + return nil +} + +func (this *MTCProbe) savePcapngSslKeyLog(sslKeyLog []byte) (err error) { + _, e := this.masterKeyBuffer.Write(sslKeyLog) + return e +}