From 9a8c64da4e47eb97627849670be77cd442ddada7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=83=88=E9=A6=99?= Date: Sun, 26 Jan 2025 23:12:23 +0800 Subject: [PATCH] feat: support trace socket event for ipv6 (#278) --- agent/compatible/type.go | 51 +++++++++++++++++-------- bpf/agent_arm64_bpfel.go | 3 ++ bpf/agent_x86_bpfel.go | 3 ++ bpf/agentlagacykernel310_arm64_bpfel.go | 3 ++ bpf/agentlagacykernel310_x86_bpfel.go | 3 ++ bpf/loader/loader.go | 8 +++- bpf/pktlatency.bpf.c | 38 +++++++++--------- testdata/test_ipv6.sh | 25 ++++++++++++ 8 files changed, 97 insertions(+), 37 deletions(-) create mode 100755 testdata/test_ipv6.sh diff --git a/agent/compatible/type.go b/agent/compatible/type.go index d6b82a22..59f1c8b2 100644 --- a/agent/compatible/type.go +++ b/agent/compatible/type.go @@ -27,6 +27,27 @@ const ( type InstrumentFunction struct { KernelFunctionName string BPFGoProgName string + Backup bool +} + +func MakeInstrumentFunction(k string, b string) InstrumentFunction { + return InstrumentFunction{ + KernelFunctionName: k, + BPFGoProgName: b, + Backup: false, + } +} + +func MakeBackupInstrumentFunction(k string, b string) InstrumentFunction { + return InstrumentFunction{ + KernelFunctionName: k, + BPFGoProgName: b, + Backup: true, + } +} + +func (f *InstrumentFunction) IsBackup() bool { + return f.Backup } func (f *InstrumentFunction) GetRealKernelFunctionName() string { @@ -106,13 +127,13 @@ func init() { baseVersion := KernelVersion{ Version: "5.15.0", InstrumentFunctions: map[bpf.AgentStepT][]InstrumentFunction{ - bpf.AgentStepTIP_OUT: {InstrumentFunction{"kprobe/__ip_queue_xmit", "IpQueueXmit"}}, - bpf.AgentStepTQDISC_OUT: {InstrumentFunction{"kprobe/dev_queue_xmit", "DevQueueXmit"}}, - bpf.AgentStepTDEV_OUT: {InstrumentFunction{"kprobe/dev_hard_start_xmit", "DevHardStartXmit"}}, - bpf.AgentStepTDEV_IN: {InstrumentFunction{"tracepoint/net/netif_receive_skb", "TracepointNetifReceiveSkb"}}, - bpf.AgentStepTIP_IN: {InstrumentFunction{"kprobe/ip_rcv_core", "IpRcvCore"}}, - bpf.AgentStepTTCP_IN: {InstrumentFunction{"kprobe/tcp_v4_do_rcv", "TcpV4DoRcv"}}, - bpf.AgentStepTUSER_COPY: {InstrumentFunction{"tracepoint/skb/skb_copy_datagram_iovec", "TracepointSkbCopyDatagramIovec"}}, + bpf.AgentStepTIP_OUT: {MakeInstrumentFunction("kprobe/__ip_queue_xmit", "IpQueueXmit")}, + bpf.AgentStepTQDISC_OUT: {MakeInstrumentFunction("kprobe/dev_queue_xmit", "DevQueueXmit")}, + bpf.AgentStepTDEV_OUT: {MakeInstrumentFunction("kprobe/dev_hard_start_xmit", "DevHardStartXmit")}, + bpf.AgentStepTDEV_IN: {MakeInstrumentFunction("tracepoint/net/netif_receive_skb", "TracepointNetifReceiveSkb")}, + bpf.AgentStepTIP_IN: {MakeInstrumentFunction("kprobe/ip_rcv_core", "IpRcvCore")}, + bpf.AgentStepTTCP_IN: {MakeInstrumentFunction("kprobe/tcp_v4_do_rcv", "TcpV4DoRcv"), MakeInstrumentFunction("kprobe/tcp_v6_do_rcv", "TcpV6DoRcv")}, + bpf.AgentStepTUSER_COPY: {MakeInstrumentFunction("tracepoint/skb/skb_copy_datagram_iovec", "TracepointSkbCopyDatagramIovec")}, }, Capabilities: map[Capability]bool{ SupportConstants: true, @@ -122,32 +143,32 @@ func init() { SupportFilterByContainer: true, }, } - baseVersion.addBackupInstrumentFunction(bpf.AgentStepTQDISC_OUT, InstrumentFunction{"kprobe/__dev_queue_xmit", "DevQueueXmit"}) + baseVersion.addBackupInstrumentFunction(bpf.AgentStepTQDISC_OUT, MakeBackupInstrumentFunction("kprobe/__dev_queue_xmit", "DevQueueXmit")) v5d15 := copyKernelVersion(baseVersion) KernelVersionsMap.Put(v5d15.Version, v5d15) v5d4 := copyKernelVersion(v5d15) v5d4.Version = "5.4.0" - v5d4.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, InstrumentFunction{"kprobe/ip_rcv_core.isra.0", "IpRcvCore"}) - v5d4.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, InstrumentFunction{"kprobe/ip_rcv_core.isra.20", "IpRcvCore"}) + v5d4.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, MakeBackupInstrumentFunction("kprobe/ip_rcv_core.isra.0", "IpRcvCore")) + v5d4.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, MakeBackupInstrumentFunction("kprobe/ip_rcv_core.isra.20", "IpRcvCore")) v5d4.removeCapability(SupportRingBuffer).removeCapability(SupportXDP) KernelVersionsMap.Put(v5d4.Version, v5d4) v4d14 := copyKernelVersion(v5d4) v4d14.Version = "4.14.0" v4d14.InstrumentFunctions[bpf.AgentStepTIP_OUT] = - []InstrumentFunction{{"kprobe/ip_queue_xmit", "IpQueueXmit"}} - v4d14.addBackupInstrumentFunction(bpf.AgentStepTIP_OUT, InstrumentFunction{"kprobe/__ip_queue_xmit", "IpQueueXmit"}) + []InstrumentFunction{MakeInstrumentFunction("kprobe/ip_queue_xmit", "IpQueueXmit")} + v4d14.addBackupInstrumentFunction(bpf.AgentStepTIP_OUT, MakeBackupInstrumentFunction("kprobe/__ip_queue_xmit", "IpQueueXmit")) v4d14.InstrumentFunctions[bpf.AgentStepTIP_IN] = - []InstrumentFunction{{"kprobe/ip_rcv", "IpRcvCore"}} + []InstrumentFunction{MakeInstrumentFunction("kprobe/ip_rcv", "IpRcvCore")} v4d14.removeCapability(SupportConstants).removeCapability(SupportRawTracepoint).removeCapability(SupportBTF).removeCapability(SupportXDP) KernelVersionsMap.Put(v4d14.Version, v4d14) v310 := copyKernelVersion(v5d4) v310.Version = "3.10.0" v310.InstrumentFunctions[bpf.AgentStepTIP_OUT] = - []InstrumentFunction{{"kprobe/ip_queue_xmit", "IpQueueXmit2"}} - v310.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, InstrumentFunction{"kprobe/ip_rcv", "IpRcvCore"}) + []InstrumentFunction{MakeInstrumentFunction("kprobe/ip_queue_xmit", "IpQueueXmit2")} + v310.addBackupInstrumentFunction(bpf.AgentStepTIP_IN, MakeBackupInstrumentFunction("kprobe/ip_rcv", "IpRcvCore")) v310.removeCapability(SupportConstants). removeCapability(SupportRawTracepoint). removeCapability(SupportXDP). diff --git a/bpf/agent_arm64_bpfel.go b/bpf/agent_arm64_bpfel.go index 30059e97..572e0312 100644 --- a/bpf/agent_arm64_bpfel.go +++ b/bpf/agent_arm64_bpfel.go @@ -298,6 +298,7 @@ type AgentProgramSpecs struct { TcpRcvEstablished *ebpf.ProgramSpec `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.ProgramSpec `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.ProgramSpec `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exit"` @@ -493,6 +494,7 @@ type AgentPrograms struct { TcpRcvEstablished *ebpf.Program `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.Program `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.Program `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.Program `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.Program `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exit"` @@ -543,6 +545,7 @@ func (p *AgentPrograms) Close() error { p.TcpRcvEstablished, p.TcpV4DoRcv, p.TcpV4Rcv, + p.TcpV6DoRcv, p.TracepointNetifReceiveSkb, p.TracepointSchedSchedProcessExec, p.TracepointSchedSchedProcessExit, diff --git a/bpf/agent_x86_bpfel.go b/bpf/agent_x86_bpfel.go index 2eed4192..6b37365f 100644 --- a/bpf/agent_x86_bpfel.go +++ b/bpf/agent_x86_bpfel.go @@ -298,6 +298,7 @@ type AgentProgramSpecs struct { TcpRcvEstablished *ebpf.ProgramSpec `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.ProgramSpec `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.ProgramSpec `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exit"` @@ -493,6 +494,7 @@ type AgentPrograms struct { TcpRcvEstablished *ebpf.Program `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.Program `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.Program `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.Program `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.Program `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exit"` @@ -543,6 +545,7 @@ func (p *AgentPrograms) Close() error { p.TcpRcvEstablished, p.TcpV4DoRcv, p.TcpV4Rcv, + p.TcpV6DoRcv, p.TracepointNetifReceiveSkb, p.TracepointSchedSchedProcessExec, p.TracepointSchedSchedProcessExit, diff --git a/bpf/agentlagacykernel310_arm64_bpfel.go b/bpf/agentlagacykernel310_arm64_bpfel.go index 4b624442..5933faa9 100644 --- a/bpf/agentlagacykernel310_arm64_bpfel.go +++ b/bpf/agentlagacykernel310_arm64_bpfel.go @@ -70,6 +70,7 @@ type AgentLagacyKernel310ProgramSpecs struct { TcpRcvEstablished *ebpf.ProgramSpec `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.ProgramSpec `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.ProgramSpec `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exit"` @@ -265,6 +266,7 @@ type AgentLagacyKernel310Programs struct { TcpRcvEstablished *ebpf.Program `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.Program `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.Program `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.Program `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.Program `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exit"` @@ -315,6 +317,7 @@ func (p *AgentLagacyKernel310Programs) Close() error { p.TcpRcvEstablished, p.TcpV4DoRcv, p.TcpV4Rcv, + p.TcpV6DoRcv, p.TracepointNetifReceiveSkb, p.TracepointSchedSchedProcessExec, p.TracepointSchedSchedProcessExit, diff --git a/bpf/agentlagacykernel310_x86_bpfel.go b/bpf/agentlagacykernel310_x86_bpfel.go index e234014b..c9e39b1e 100644 --- a/bpf/agentlagacykernel310_x86_bpfel.go +++ b/bpf/agentlagacykernel310_x86_bpfel.go @@ -70,6 +70,7 @@ type AgentLagacyKernel310ProgramSpecs struct { TcpRcvEstablished *ebpf.ProgramSpec `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.ProgramSpec `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.ProgramSpec `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.ProgramSpec `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.ProgramSpec `ebpf:"tracepoint__sched__sched_process_exit"` @@ -265,6 +266,7 @@ type AgentLagacyKernel310Programs struct { TcpRcvEstablished *ebpf.Program `ebpf:"tcp_rcv_established"` TcpV4DoRcv *ebpf.Program `ebpf:"tcp_v4_do_rcv"` TcpV4Rcv *ebpf.Program `ebpf:"tcp_v4_rcv"` + TcpV6DoRcv *ebpf.Program `ebpf:"tcp_v6_do_rcv"` TracepointNetifReceiveSkb *ebpf.Program `ebpf:"tracepoint__netif_receive_skb"` TracepointSchedSchedProcessExec *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exec"` TracepointSchedSchedProcessExit *ebpf.Program `ebpf:"tracepoint__sched__sched_process_exit"` @@ -315,6 +317,7 @@ func (p *AgentLagacyKernel310Programs) Close() error { p.TcpRcvEstablished, p.TcpV4DoRcv, p.TcpV4Rcv, + p.TcpV6DoRcv, p.TracepointNetifReceiveSkb, p.TracepointSchedSchedProcessExec, p.TracepointSchedSchedProcessExit, diff --git a/bpf/loader/loader.go b/bpf/loader/loader.go index 16112b72..0c05419c 100644 --- a/bpf/loader/loader.go +++ b/bpf/loader/loader.go @@ -509,14 +509,18 @@ func attachBpfProgs(ifName string, kernelVersion *compatible.KernelVersion, opti if isNonCriticalStep { common.AgentLog.Debugf("Attach failed: %v, functions: %v skip it because it's a non-criticalstep", err, functions) } else { - return nil, fmt.Errorf("Attach failed: %v, functions: %v", err, functions) + return nil, fmt.Errorf("attach failed: %v, functions: %v", err, functions) } } else { common.AgentLog.Debugf("Attach failed but has fallback: %v, functions: %v", err, functions) } } else { linkList.PushBack(l) - break + if idx < len(functions)-1 && !functions[idx+1].IsBackup() { + continue + } else { + break + } } } } diff --git a/bpf/pktlatency.bpf.c b/bpf/pktlatency.bpf.c index d7dc58f7..3119ac7f 100644 --- a/bpf/pktlatency.bpf.c +++ b/bpf/pktlatency.bpf.c @@ -297,21 +297,16 @@ static bool __always_inline use_ipv6(struct sock_common * skc) { static bool __always_inline parse_sock_key_sk(struct sock* sk, struct sock_key* key) { struct sock_common *skc = {0}; skc = (struct sock_common *)sk; - bool supportIpv6 = use_ipv6(skc); switch (_C(skc, skc_family)) { case AF_INET: key->dip[0] = _C(skc, skc_daddr); key->sip[0] = _C(skc, skc_rcv_saddr); break; case AF_INET6: - if (supportIpv6) { - bpf_probe_read_kernel((void *)(key->dip), sizeof(struct in6_addr), (const void *)__builtin_preserve_access_index(&((typeof((skc)))((skc)))->skc_v6_daddr)); - bpf_probe_read_kernel((void *)(key->sip), sizeof(struct in6_addr), (const void *)__builtin_preserve_access_index(&((typeof((skc)))((skc)))->skc_v6_rcv_saddr)); - } else { - key->dip[0] = _C(skc, skc_daddr); - key->sip[0] = _C(skc, skc_rcv_saddr); - } - break; + bpf_probe_read_kernel((void *)(key->dip), sizeof(struct in6_addr), (const void *)__builtin_preserve_access_index(&((typeof((skc)))((skc)))->skc_v6_daddr.in6_u.u6_addr32)); + bpf_probe_read_kernel((void *)(key->sip), sizeof(struct in6_addr), (const void *)__builtin_preserve_access_index(&((typeof((skc)))((skc)))->skc_v6_rcv_saddr.in6_u.u6_addr32)); + // bpf_printk("ipv6!, sport: %d, dport: %d", _C(skc, skc_num), _C(skc, skc_dport)); + break; default: return false; } @@ -472,7 +467,7 @@ static __always_inline int parse_skb(void* ctx, struct sk_buff *skb, bool sk_not l3 = (void *)eth + ETH_HLEN; BPF_CORE_READ_INTO(&l3_proto, eth, h_proto); l3_proto = bpf_ntohs(l3_proto); - // bpf_printk("%s, l3_proto: %x",func_name, l3_proto); + // bpf_printk("test l3_proto: %x", l3_proto); if (l3_proto == ETH_P_IP || l3_proto == ETH_P_IPV6) { __l3: if (!skb_l4_check(trans_header, network_header)) { @@ -506,7 +501,8 @@ static __always_inline int parse_skb(void* ctx, struct sk_buff *skb, bool sk_not } } else if (l3_proto == ETH_P_IPV6) { proto_l4 = _(ipv6->nexthdr); - tcp_len = _C(ipv6, payload_len); + tcp_len = bpf_ntohs(_C(ipv6, payload_len)); + // bpf_printk("testipv6, tcp_len: %d", tcp_len); l4 = l4 ? l4 : ip + sizeof(*ipv6); }else{ goto err; @@ -664,6 +660,13 @@ int BPF_KPROBE(tcp_v4_do_rcv, struct sock *sk, struct sk_buff *skb) { parse_skb(ctx, skb, 1, TCP_IN); return BPF_OK; } + + +SEC("kprobe/tcp_v6_do_rcv") +int BPF_KPROBE(tcp_v6_do_rcv, struct sock *sk, struct sk_buff *skb) { + parse_skb(ctx, skb, 1, TCP_IN); + return BPF_OK; +} SEC("kprobe/tcp_v4_rcv") int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { @@ -890,14 +893,14 @@ static __inline void read_sockaddr_kernel(struct conn_info_t* conn_info, conn_info->laddr.in6.sin6_port = lport; conn_info->raddr.in6.sin6_port = rport; - if (family == AF_INET || !use_ipv6(sk_common)) { + if (family == AF_INET) { conn_info->laddr.in6.sin6_addr.in6_u.u6_addr32[0] = _C(sk_common, skc_rcv_saddr); conn_info->raddr.in6.sin6_addr.in6_u.u6_addr32[0] = _C(sk_common, skc_daddr); // BPF_CORE_READ_INTO(&conn_info->laddr.in4.sin_addr.s_addr, sk_common, skc_rcv_saddr); // BPF_CORE_READ_INTO(&conn_info->raddr.in4.sin_addr.s_addr, sk_common, skc_daddr); } else if (family == AF_INET6) { - BPF_CORE_READ_INTO(&conn_info->laddr.in6.sin6_addr, sk_common, skc_v6_rcv_saddr); - BPF_CORE_READ_INTO(&conn_info->raddr.in6.sin6_addr, sk_common, skc_v6_daddr); + BPF_CORE_READ_INTO(&conn_info->laddr.in6.sin6_addr, sk_common, skc_v6_rcv_saddr.in6_u.u6_addr32); + BPF_CORE_READ_INTO(&conn_info->raddr.in6.sin6_addr, sk_common, skc_v6_daddr.in6_u.u6_addr32); } } @@ -1041,7 +1044,6 @@ enum endpoint_role_t role, uint64_t start_ts) { // print_sock_key(&key); struct sock_common *sk_common = (struct sock_common *) tcp_sk; - bool is_ipv6 = use_ipv6(sk_common); if (socket == NULL) { // conn_info.laddr.in4.sin_addr.s_addr = role == kRoleClient ? key.sip : key.dip; // conn_info.laddr.in4.sin_port = role == kRoleClient ? key.sport : key.dport; @@ -1054,7 +1056,7 @@ enum endpoint_role_t role, uint64_t start_ts) { uint16_t family = -1; BPF_CORE_READ_INTO(&family, sk_common, skc_family); // bpf_printk("AF: %d", family); - if (family == AF_INET || !is_ipv6) { + if (family == AF_INET ) { // conn_info.laddr.in4.sin_addr.s_addr = (u32)key.sip[0] ; // conn_info.raddr.in4.sin_addr.s_addr = (u32)key.dip[0]; conn_info.laddr.in6.sin6_addr.in6_u.u6_addr32[0] = (u32)key.sip[0]; @@ -1066,10 +1068,6 @@ enum endpoint_role_t role, uint64_t start_ts) { conn_info.laddr.sa.sa_family = family; conn_info.raddr.sa.sa_family = family; } - if (!use_ipv6(sk_common)) { - conn_info.laddr.sa.sa_family = AF_INET; - conn_info.raddr.sa.sa_family = AF_INET; - } // bpf_printk("submit_new_conn laddr: port:%u", conn_info.laddr.in4.sin_port); // bpf_printk("submit_new_conn raddr: port:%u", conn_info.raddr.in4.sin_port); diff --git a/testdata/test_ipv6.sh b/testdata/test_ipv6.sh new file mode 100755 index 00000000..4d167a90 --- /dev/null +++ b/testdata/test_ipv6.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +. $(dirname "$0")/common.sh +set -ex + +CMD="$1" +FILE_PREFIX="/tmp/kyanos" +CLIENT_LNAME="${FILE_PREFIX}_ipv6_client.log" + + +function test_client() { + # client start after kyanos + timeout 30 ${CMD} watch --debug-output http --comm curl --trace-ssl-event=false 2>&1 | tee "${CLIENT_LNAME}" & + sleep 15 + curl -6 'http://ipv6.baidu.com' &>/dev/null || true + wait + + cat "${CLIENT_LNAME}" + cat "${CLIENT_LNAME}" | grep "Host: ipv6.baidu.com" +} + +function main() { + test_client +} + +main \ No newline at end of file