Skip to content

Commit 0c490f1

Browse files
committed
nat: add parsePortNumber utility
Add a utility for parsing and validating port-numbers to reduce repetition and improve errors. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 2e42eb8 commit 0c490f1

4 files changed

Lines changed: 108 additions & 5 deletions

File tree

nat/nat.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ func ParsePort(rawPort string) (int, error) {
4747
if rawPort == "" {
4848
return 0, nil
4949
}
50-
port, err := strconv.ParseUint(rawPort, 10, 16)
50+
port, err := parsePortNumber(rawPort)
5151
if err != nil {
52-
return 0, fmt.Errorf("invalid port '%s': %w", rawPort, errors.Unwrap(err))
52+
return 0, fmt.Errorf("invalid port '%s': %w", rawPort, err)
5353
}
54-
return int(port), nil
54+
return port, nil
5555
}
5656

5757
// ParsePortRangeToInt parses the port range string and returns start/end ints

nat/nat_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestParsePort(t *testing.T) {
3838
doc: "negative value",
3939
input: "-1",
4040
expPort: 0,
41-
expErr: `invalid port '-1': invalid syntax`,
41+
expErr: `invalid port '-1': value out of range (0–65535)`,
4242
},
4343
// FIXME currently this is a valid port. I don't think it should be.
4444
// I'm leaving this test until we make a decision.
@@ -57,7 +57,7 @@ func TestParsePort(t *testing.T) {
5757
doc: "value out of range",
5858
input: "65536",
5959
expPort: 0,
60-
expErr: `invalid port '65536': value out of range`,
60+
expErr: `invalid port '65536': value out of range (0–65535)`,
6161
},
6262
}
6363

nat/parse.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,24 @@ func ParsePortRange(ports string) (uint64, uint64, error) {
3131
}
3232
return start, end, nil
3333
}
34+
35+
// parsePortNumber parses rawPort into an int, unwrapping strconv errors
36+
// and returning a single "out of range" error for any value outside 0–65535.
37+
func parsePortNumber(rawPort string) (int, error) {
38+
if rawPort == "" {
39+
return 0, errors.New("value is empty")
40+
}
41+
port, err := strconv.ParseInt(rawPort, 10, 0)
42+
if err != nil {
43+
var numErr *strconv.NumError
44+
if errors.As(err, &numErr) {
45+
err = numErr.Err
46+
}
47+
return 0, err
48+
}
49+
if port < 0 || port > 65535 {
50+
return 0, errors.New("value out of range (0–65535)")
51+
}
52+
53+
return int(port), nil
54+
}

nat/parse_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,85 @@ func TestParsePortRange(t *testing.T) {
120120
})
121121
}
122122
}
123+
124+
func TestParsePortNumber(t *testing.T) {
125+
tests := []struct {
126+
doc string
127+
input string
128+
exp int
129+
expErr string
130+
}{
131+
{
132+
doc: "empty string",
133+
input: "",
134+
expErr: "value is empty",
135+
},
136+
{
137+
doc: "whitespace only",
138+
input: " ",
139+
expErr: "invalid syntax",
140+
},
141+
{
142+
doc: "single valid port",
143+
input: "1234",
144+
exp: 1234,
145+
},
146+
{
147+
doc: "zero port",
148+
input: "0",
149+
exp: 0,
150+
},
151+
{
152+
doc: "max valid port",
153+
input: "65535",
154+
exp: 65535,
155+
},
156+
{
157+
doc: "leading/trailing spaces",
158+
input: " 42 ",
159+
expErr: "invalid syntax",
160+
},
161+
{
162+
doc: "negative port",
163+
input: "-1",
164+
expErr: "value out of range (0–65535)",
165+
},
166+
{
167+
doc: "too large port",
168+
input: "70000",
169+
expErr: "value out of range (0–65535)",
170+
},
171+
{
172+
doc: "non-numeric",
173+
input: "foo",
174+
expErr: "invalid syntax",
175+
},
176+
{
177+
doc: "trailing garbage",
178+
input: "1234abc",
179+
expErr: "invalid syntax",
180+
},
181+
}
182+
183+
for _, tc := range tests {
184+
t.Run(tc.doc, func(t *testing.T) {
185+
got, err := parsePortNumber(tc.input)
186+
187+
if tc.expErr == "" {
188+
if err != nil {
189+
t.Fatalf("unexpected error: %v", err)
190+
}
191+
if got != tc.exp {
192+
t.Errorf("expected %d, got %d", tc.exp, got)
193+
}
194+
} else {
195+
if err == nil {
196+
t.Fatalf("expected error %q, got nil", tc.expErr)
197+
}
198+
if err.Error() != tc.expErr {
199+
t.Errorf("expected error %q, got %q", tc.expErr, err.Error())
200+
}
201+
}
202+
})
203+
}
204+
}

0 commit comments

Comments
 (0)