Skip to content

Commit 9b0bea4

Browse files
committed
frontend: use more robust method to get host/port from WHOIS server setting
1 parent c98b546 commit 9b0bea4

File tree

2 files changed

+117
-9
lines changed

2 files changed

+117
-9
lines changed

frontend/whois.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ import (
1010
"github.com/google/shlex"
1111
)
1212

13+
// addDefaultWhoisPort adds the default whois port (43) if not specified.
14+
// Handles IPv4, IPv6 (bare and bracketed), and domain names.
15+
func addDefaultWhoisPort(server string) string {
16+
if _, _, err := net.SplitHostPort(server); err != nil {
17+
// No port specified, add default whois port
18+
// Strip brackets from IPv6 addresses like [::1] before JoinHostPort adds them back
19+
host := server
20+
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
21+
host = host[1 : len(host)-1]
22+
}
23+
return net.JoinHostPort(host, "43")
24+
}
25+
return server
26+
}
27+
1328
// Send a whois request
1429
func whois(s string) string {
1530
if setting.whoisServer == "" {
@@ -36,10 +51,7 @@ func whois(s string) string {
3651
} else {
3752
buf := make([]byte, 65536)
3853

39-
whoisServer := setting.whoisServer
40-
if !strings.Contains(whoisServer, ":") {
41-
whoisServer = whoisServer + ":43"
42-
}
54+
whoisServer := addDefaultWhoisPort(setting.whoisServer)
4355

4456
conn, err := net.DialTimeout("tcp", whoisServer, 5*time.Second)
4557
if err != nil {

frontend/whois_test.go

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,51 @@ import (
77
"testing"
88
)
99

10+
func TestAddDefaultWhoisPort(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
input string
14+
expected string
15+
}{
16+
// IPv4 addresses
17+
{"IPv4 without port", "192.0.2.1", "192.0.2.1:43"},
18+
{"IPv4 with port", "192.0.2.1:4343", "192.0.2.1:4343"},
19+
20+
// IPv6 addresses - bare format
21+
{"IPv6 bare without port", "::1", "[::1]:43"},
22+
{"IPv6 bare full without port", "2001:db8::1", "[2001:db8::1]:43"},
23+
24+
// IPv6 addresses - bracketed format
25+
{"IPv6 bracketed without port", "[::1]", "[::1]:43"},
26+
{"IPv6 bracketed full without port", "[2001:db8::1]", "[2001:db8::1]:43"},
27+
{"IPv6 bracketed with port", "[::1]:4343", "[::1]:4343"},
28+
{"IPv6 bracketed full with port", "[2001:db8::1]:4343", "[2001:db8::1]:4343"},
29+
30+
// Domain names
31+
{"Domain without port", "whois.example.com", "whois.example.com:43"},
32+
{"Domain with port", "whois.example.com:4343", "whois.example.com:4343"},
33+
34+
// Edge cases
35+
{"Localhost without port", "localhost", "localhost:43"},
36+
{"Localhost with port", "localhost:4343", "localhost:4343"},
37+
}
38+
39+
for _, tt := range tests {
40+
t.Run(tt.name, func(t *testing.T) {
41+
result := addDefaultWhoisPort(tt.input)
42+
if result != tt.expected {
43+
t.Errorf("addDefaultWhoisPort(%q) = %q, want %q", tt.input, result, tt.expected)
44+
}
45+
})
46+
}
47+
}
48+
1049
type WhoisServer struct {
1150
t *testing.T
1251
expectedQuery string
1352
response string
1453
server net.Listener
54+
listenAddr string // Address to listen on, defaults to "127.0.0.1:0"
1555
}
1656

1757
const AS6939Response = `
@@ -23,12 +63,14 @@ Updated: 2003-11-04
2363
Ref: https://rdap.arin.net/registry/autnum/6939
2464
`
2565

26-
func (s *WhoisServer) Listen() {
66+
func (s *WhoisServer) Listen() error {
2767
var err error
28-
s.server, err = net.Listen("tcp", "127.0.0.1:0")
29-
if err != nil {
30-
s.t.Error(err)
68+
listenAddr := s.listenAddr
69+
if listenAddr == "" {
70+
listenAddr = "127.0.0.1:0"
3171
}
72+
s.server, err = net.Listen("tcp", listenAddr)
73+
return err
3274
}
3375

3476
func (s *WhoisServer) Run() {
@@ -68,7 +110,9 @@ func TestWhois(t *testing.T) {
68110
response: AS6939Response,
69111
}
70112

71-
server.Listen()
113+
if err := server.Listen(); err != nil {
114+
t.Fatal(err)
115+
}
72116
go server.Run()
73117
defer server.Close()
74118

@@ -126,3 +170,55 @@ func TestWhoisHostProcessVeryLong(t *testing.T) {
126170
t.Errorf("Whois result incorrectly truncated, actual len %d", len(result))
127171
}
128172
}
173+
174+
func TestWhoisIPv6(t *testing.T) {
175+
server := WhoisServer{
176+
t: t,
177+
expectedQuery: "AS6939",
178+
response: AS6939Response,
179+
listenAddr: "[::1]:0",
180+
}
181+
182+
if err := server.Listen(); err != nil {
183+
t.Skip("IPv6 not available:", err)
184+
}
185+
go server.Run()
186+
defer server.Close()
187+
188+
setting.whoisServer = server.server.Addr().String()
189+
result := whois("AS6939")
190+
if !strings.Contains(result, "HURRICANE") {
191+
t.Errorf("Whois AS6939 over IPv6 failed, got %s", result)
192+
}
193+
}
194+
195+
func TestWhoisIPv6WithoutPort(t *testing.T) {
196+
server := WhoisServer{
197+
t: t,
198+
expectedQuery: "AS6939",
199+
response: AS6939Response,
200+
listenAddr: "[::1]:43",
201+
}
202+
203+
if err := server.Listen(); err != nil {
204+
t.Skip("IPv6 not available or port 43 not bindable:", err)
205+
}
206+
go server.Run()
207+
defer server.Close()
208+
209+
// Test that bare IPv6 address (without port) gets default port 43 appended
210+
setting.whoisServer = "::1"
211+
result := whois("AS6939")
212+
if !strings.Contains(result, "HURRICANE") {
213+
t.Errorf("Whois AS6939 over IPv6 (bare address) failed, got %s", result)
214+
}
215+
}
216+
217+
func TestWhoisIPv6ConnectionError(t *testing.T) {
218+
// Use IPv6 loopback with a port that should be refused
219+
setting.whoisServer = "[::1]:1"
220+
result := whois("AS6939")
221+
if !strings.Contains(result, "connect: connection refused") && !strings.Contains(result, "network is unreachable") {
222+
t.Errorf("Whois AS6939 IPv6 connection error produced unexpected output, got %s", result)
223+
}
224+
}

0 commit comments

Comments
 (0)