=== CMD 1: curl request with Connection: close === $ kubectl -n istio-vt-t57 exec client -c curl -- curl -s -o /dev/null -w 'http_code=%{http_code} ' -H 'Connection: close' http://echo.istio-vt-t57.svc.homelab.local/ http_code=200 === CMD 2: T0 time-wait count (:80) === T0=1783209415 (Sun Jul 5 08:56:55 AM KST 2026) $ kubectl -n istio-vt-t57 exec client -c istio-proxy -- ss -tan state time-wait | grep ':80 ' Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:44558 0 0 127.0.0.1:15001 10.255.194.71:58046 0 0 10.255.194.71:15021 192.168.0.213:44556 count(:80 )=0 === CMD 3: polling loop, 7x10s, literal spec grep ':80 ' === $ for i in $(seq 1 7); do sleep 10; N=$(kubectl -n istio-vt-t57 exec client -c istio-proxy -- ss -tan state time-wait 2>/dev/null | grep -c ':80 '); echo "t+$((i*10))s time_wait_count=$N"; done t+10s time_wait_count(:80 literal)=0 [diag] t+10s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:41184 0 0 10.255.194.71:15021 192.168.0.213:42872 0 0 127.0.0.1:33684 127.0.0.1:15000 0 0 10.255.194.71:15021 192.168.0.213:53092 [diag] t+10s count(:15001 envoy-side)=0 t+20s time_wait_count(:80 literal)=0 [diag] t+20s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:41184 0 0 10.255.194.71:15021 192.168.0.213:42872 0 0 127.0.0.1:33684 127.0.0.1:15000 0 0 10.255.194.71:15021 192.168.0.213:53092 [diag] t+20s count(:15001 envoy-side)=0 t+30s time_wait_count(:80 literal)=0 [diag] t+30s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:41184 0 0 10.255.194.71:15021 192.168.0.213:42872 [diag] t+30s count(:15001 envoy-side)=0 t+40s time_wait_count(:80 literal)=0 [diag] t+40s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:35258 0 0 10.255.194.71:15021 192.168.0.213:41184 [diag] t+40s count(:15001 envoy-side)=0 t+50s time_wait_count(:80 literal)=0 [diag] t+50s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:39544 0 0 10.255.194.71:15021 192.168.0.213:35258 [diag] t+50s count(:15001 envoy-side)=0 t+60s time_wait_count(:80 literal)=0 [diag] t+60s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:39544 0 0 10.255.194.71:15021 192.168.0.213:35258 [diag] t+60s count(:15001 envoy-side)=0 t+70s time_wait_count(:80 literal)=0 [diag] t+70s full_time_wait_dump: Recv-Q Send-Q Local Address:Port Peer Address:Port Process 0 0 10.255.194.71:15021 192.168.0.213:39544 0 0 10.255.194.71:15021 192.168.0.213:35258 [diag] t+70s count(:15001 envoy-side)=0 === SUPPLEMENTARY DIAGNOSTIC (not in spec, added because literal ':80 ' grep never matches due to Istio iptables redirect to 15001/targetPort) === Purpose: precisely track TIME_WAIT lifecycle for the actual client<->envoy(15001) socket generated by our own request, using tight in-pod polling (no kubectl-exec latency jitter). sh: 0: cannot open /tmp/diag.sh: No such file command terminated with exit code 2 T0=1783209717 http_code=200 TCLOSE=1783209717 t+0s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+2s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+4s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+6s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+8s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+10s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+12s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+14s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+16s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+18s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+20s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+22s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+24s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+26s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+28s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+30s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+32s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+34s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+36s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+38s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+40s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+42s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+44s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+46s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+48s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+50s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+52s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+54s count=1 lines=[0 0 10.255.194.71:58058 10.250.220.69:80 ] t+56s count=0 t+58s count=0 t+60s count=0 t+62s count=0 t+64s count=0 t+66s count=0 t+68s count=0 t+70s count=0 t+72s count=0 t+74s count=0 t+76s count=0 t+78s count=0 === Confirm peer IP is echo Service ClusterIP + sysctl check (does any sysctl control TIME_WAIT duration directly?) === $ kubectl -n istio-vt-t57 get svc echo -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR echo ClusterIP 10.250.220.69 80/TCP,443/TCP 7m44s app=echo $ sysctl net.ipv4.tcp_fin_timeout net.ipv4.tcp_fin_timeout = 60 $ sysctl -a 2>/dev/null | grep -i time_wait net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 NOTE: tcp_fin_timeout(60) controls FIN_WAIT_2 timeout, NOT TIME_WAIT duration. nf_conntrack_tcp_timeout_time_wait(120) is a separate netfilter conntrack table aging window, NOT the kernel TCP stack's own per-socket TIME_WAIT timer. Neither sysctl controls the actual TCP_TIMEWAIT_LEN (hardcoded 60*HZ in kernel source net/tcp.h), which is what 'ss state time-wait' reports and what we measured empirically above (~55-56s observed, consistent with ~60s given 2s poll granularity). Confirmed: echo Service ClusterIP = 10.250.220.69, matching the peer address seen in the TIME_WAIT socket -> the istio-proxy-originated curl bypassed Envoy's iptables redirect (excluded via UID ownership match) and went through the normal kube-proxy DNAT path, which preserves the literal ClusterIP:80 tuple in the app's own socket view (unlike REDIRECT-based sidecar interception which rewrites to 127.0.0.1:15001).