Skip to content

Commit 97c1c1a

Browse files
cfc4nclaude
andauthored
test/e2e: improve pcap interface detection with route verification (#1021)
Extract shared get_default_interface, get_route_interface, and verify_traffic_interface functions into common.sh to eliminate duplicate definitions across tls_e2e_test, tls_pcap_advanced_test, and gotls_advanced_test scripts. verify_traffic_interface uses 'ip route get' to confirm the kernel actually routes traffic to the test target through the detected interface, correcting DEFAULT_IFACE when a mismatch is found (e.g., multi-homed hosts, Docker bridges, VPN tunnels). This fixes the "[303] nothing captured" error on GitHub Actions runners where the default route interface may differ from the interface actually used for outbound traffic. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4253aeb commit 97c1c1a

4 files changed

Lines changed: 73 additions & 16 deletions

File tree

test/e2e/common.sh

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,61 @@ verify_content_match() {
267267
return 1
268268
fi
269269
}
270+
271+
# ============================================================================
272+
# Network Interface Detection (shared by all e2e test scripts)
273+
# ============================================================================
274+
275+
# Get default network interface from routing table (needed for pcap mode)
276+
get_default_interface() {
277+
ip route | grep default | awk '{print $5}' | head -1 || echo ""
278+
}
279+
280+
# Get the interface that would actually be used to reach a given target.
281+
# Uses "ip route get" to query the kernel's routing decision.
282+
# Args: target hostname or IP
283+
# Returns: interface name (e.g., eth0, ens5) or empty string
284+
get_route_interface() {
285+
local target="${1:-1.1.1.1}"
286+
# Resolve hostname to IP (use first result) if target is not already an IP
287+
local target_ip
288+
target_ip=$(dig +short "$target" 2>/dev/null | grep -E '^[0-9]' | head -1 || echo "")
289+
if [ -z "$target_ip" ]; then
290+
# dig failed or returned no result, try getent as fallback
291+
target_ip=$(getent ahosts "$target" 2>/dev/null | awk '{print $1; exit}' || echo "$target")
292+
fi
293+
# Query kernel routing table: which dev would be used for this IP?
294+
ip route get "$target_ip" 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") {print $(i+1); exit}}' || echo ""
295+
}
296+
297+
# Verify that traffic to the test target actually goes through the detected interface.
298+
# Corrects DEFAULT_IFACE (global variable) if a mismatch is found.
299+
# Must be called after DEFAULT_IFACE is set via get_default_interface.
300+
# Args: target hostname (e.g., "api.github.com")
301+
verify_traffic_interface() {
302+
local target="${1:-api.github.com}"
303+
local route_iface
304+
route_iface=$(get_route_interface "$target")
305+
306+
if [ -z "$route_iface" ]; then
307+
log_warn "Could not determine route interface for $target (dig/getent may be unavailable)"
308+
return 1
309+
fi
310+
311+
log_info "Kernel routes traffic to $target via interface: $route_iface"
312+
313+
if [ -z "$DEFAULT_IFACE" ]; then
314+
log_info "No default interface was set, using route-detected interface: $route_iface"
315+
DEFAULT_IFACE="$route_iface"
316+
return 0
317+
fi
318+
319+
if [ "$DEFAULT_IFACE" != "$route_iface" ]; then
320+
log_warn "Default route interface ($DEFAULT_IFACE) != route to $target ($route_iface)"
321+
log_warn "Using $route_iface for pcap capture (matches actual traffic path)"
322+
DEFAULT_IFACE="$route_iface"
323+
else
324+
log_success "Traffic to $target matches default interface: $DEFAULT_IFACE"
325+
fi
326+
return 0
327+
}

test/e2e/gotls_advanced_test.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ cleanup_handler() {
3939

4040
setup_cleanup_trap
4141

42-
# Get default network interface (needed for pcap mode)
43-
get_default_interface() {
44-
ip route | grep default | awk '{print $5}' | head -1 || echo ""
45-
}
4642
DEFAULT_IFACE=""
4743

4844
# Build Go test programs
@@ -519,8 +515,11 @@ main() {
519515
# Detect default network interface (required for pcap mode)
520516
DEFAULT_IFACE=$(get_default_interface)
521517
if [ -z "$DEFAULT_IFACE" ]; then
522-
log_warn "Could not determine default network interface, pcap tests may fail"
518+
log_warn "Could not determine default network interface from routing table"
523519
fi
520+
521+
# Verify traffic to test target actually uses the detected interface
522+
verify_traffic_interface "api.github.com" || true
524523

525524
test_gotls_text_mode || true
526525
kill_by_pattern "$ECAPTURE_BINARY.*gotls" || true

test/e2e/tls_e2e_test.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ cleanup_handler() {
5050
# Setup trap
5151
setup_cleanup_trap
5252

53-
# Get default network interface (needed for pcap mode)
54-
get_default_interface() {
55-
ip route | grep default | awk '{print $5}' | head -1 || echo ""
56-
}
5753
DEFAULT_IFACE=""
5854

5955
# Test text mode - captures plaintext directly
@@ -334,8 +330,13 @@ main() {
334330
# Detect default network interface (required for pcap mode)
335331
DEFAULT_IFACE=$(get_default_interface)
336332
if [ -z "$DEFAULT_IFACE" ]; then
337-
log_warn "Could not determine default network interface, pcap tests may fail"
333+
log_warn "Could not determine default network interface from routing table"
338334
fi
335+
336+
# Verify traffic to test target actually uses the detected interface.
337+
# This corrects DEFAULT_IFACE if the kernel routes traffic differently
338+
# (e.g., multi-homed hosts, Docker bridges, VPN tunnels).
339+
verify_traffic_interface "$(echo "$TEST_URL" | sed 's|https://||')" || true
339340

340341
# Test text mode
341342
if test_text_mode; then

test/e2e/tls_pcap_advanced_test.sh

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ cleanup_handler() {
3232

3333
setup_cleanup_trap
3434

35-
# Get default network interface (needed for pcap mode)
36-
get_default_interface() {
37-
ip route | grep default | awk '{print $5}' | head -1 || echo ""
38-
}
3935
DEFAULT_IFACE=""
4036

4137
# Verify pcapng file format
@@ -442,9 +438,12 @@ main() {
442438
# Detect default network interface (required for pcap mode)
443439
DEFAULT_IFACE=$(get_default_interface)
444440
if [ -z "$DEFAULT_IFACE" ]; then
445-
log_warn "Could not determine default network interface, pcap tests may fail"
441+
log_warn "Could not determine default network interface from routing table"
446442
fi
447-
443+
444+
# Verify traffic to test target actually uses the detected interface
445+
verify_traffic_interface "api.github.com" || true
446+
448447
test_pcapng_basic || true
449448
kill_by_pattern "$ECAPTURE_BINARY.*tls" || true
450449
sleep 1

0 commit comments

Comments
 (0)