package procutil import ( "net" "testing" ) func TestParseHexIPv4(t *testing.T) { tests := []struct { hex string want string isErr bool }{ // "0201010A" → 10.1.1.2 (little-endian kernel encoding) {"0201010A", "10.1.1.2", false}, // "0100007F" → 127.0.0.1 {"0100007F", "127.0.0.1", false}, // "00000000" → 0.0.0.0 {"00000000", "0.0.0.0", false}, // Invalid: wrong length {"0101", "", true}, {"", "", true}, // Invalid: non-hex {"ZZZZZZZZ", "", true}, } for _, tt := range tests { ip, err := parseHexIPv4(tt.hex) if tt.isErr { if err == nil { t.Errorf("parseHexIPv4(%q): expected error, got ip=%v", tt.hex, ip) } continue } if err != nil { t.Errorf("parseHexIPv4(%q): unexpected error: %v", tt.hex, err) continue } got := ip.String() if got != tt.want { t.Errorf("parseHexIPv4(%q) = %v, want %v", tt.hex, got, tt.want) } } } func TestParseHexIPv6(t *testing.T) { tests := []struct { name string hex string want string isErr bool }{ // IPv4-mapped ::ffff:127.0.0.1 // In /proc/net/tcp6: 4 x 32-bit LE words // word0=00000000 word1=00000000 word2=0xffff0000 (LE for 00 00 ff ff) word3=0x0100007f (LE for 7f 00 00 01) { "ipv4-mapped loopback", "0000000000000000FFFF00000100007F", "127.0.0.1", false, }, // Invalid: wrong length {"too short", "0000", "", true}, // Invalid: non-hex {"bad hex", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ip, err := parseHexIPv6(tt.hex) if tt.isErr { if err == nil { t.Errorf("parseHexIPv6(%q): expected error, got ip=%v", tt.hex, ip) } return } if err != nil { t.Errorf("parseHexIPv6(%q): unexpected error: %v", tt.hex, err) return } got := ip.String() if got != tt.want { t.Errorf("parseHexIPv6(%q) = %v, want %v", tt.hex, got, tt.want) } }) } } func TestParseHexIPv6_Native(t *testing.T) { // Full IPv6: 2001:db8::1 // Little-endian chunks: 0000:0000:0000:0000:0000:0000:0000:0001 → but in /proc format // "00000000000000000000000001000000" → maps to a real IPv6 ip, err := parseHexIPv6("01000000000000000000000000000000") if err != nil { t.Fatalf("unexpected error: %v", err) } // Should be native IPv6, not IPv4-mapped if ip.To4() != nil && !isIPv4MappedIPv6(ip.To16()) { t.Errorf("expected native IPv6, got IPv4: %v", ip) } } func TestIsIPv4MappedIPv6(t *testing.T) { tests := []struct { name string ip net.IP want bool }{ {"nil", nil, false}, {"4-byte", net.IP{10, 0, 0, 1}, false}, {"loopback mapped", net.ParseIP("::ffff:127.0.0.1"), true}, {"mapped 10.0.0.1", net.ParseIP("::ffff:10.0.0.1"), true}, {"not mapped", net.ParseIP("2001:db8::1"), false}, {"all zeros", net.IPv6zero, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := isIPv4MappedIPv6(tt.ip) if got != tt.want { t.Errorf("isIPv4MappedIPv6(%v) = %v, want %v", tt.ip, got, tt.want) } }) } }