Skip to content

Commit ef3171c

Browse files
mateusz834gopherbot
authored andcommitted
net: handle the network parameter properly in LookupPort
The cgo version (unix) is populating the GetAddrInfo hints based on the network parameter, but windows not quite. This change populates the hints the same way as the cgo unix version does now. This bug was spotted by Bryan in CL 530415. https://go-review.googlesource.com/c/go/+/530415/comment/76640dc7_ed0409ca/ Change-Id: I6fc29b1e4cdc879123ab0f5a624b6f37c68c00ba GitHub-Last-Rev: eaa6163 GitHub-Pull-Request: #63284 Reviewed-on: https://go-review.googlesource.com/c/go/+/531635 Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Mateusz Poliwczak <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: David du Colombier <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent 340a4f5 commit ef3171c

File tree

5 files changed

+130
-43
lines changed

5 files changed

+130
-43
lines changed

src/net/cgo_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error)
8080
func cgoLookupPort(ctx context.Context, network, service string) (port int, err error) {
8181
var hints _C_struct_addrinfo
8282
switch network {
83-
case "": // no hints
83+
case "ip": // no hints
8484
case "tcp", "tcp4", "tcp6":
8585
*_C_ai_socktype(&hints) = _C_SOCK_STREAM
8686
*_C_ai_protocol(&hints) = _C_IPPROTO_TCP

src/net/lookup.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,20 @@ var services = map[string]map[string]int{
4141
"domain": 53,
4242
},
4343
"tcp": {
44-
"ftp": 21,
45-
"ftps": 990,
46-
"gopher": 70, // ʕ◔ϖ◔ʔ
47-
"http": 80,
48-
"https": 443,
49-
"imap2": 143,
50-
"imap3": 220,
51-
"imaps": 993,
52-
"pop3": 110,
53-
"pop3s": 995,
54-
"smtp": 25,
55-
"ssh": 22,
56-
"telnet": 23,
44+
"ftp": 21,
45+
"ftps": 990,
46+
"gopher": 70, // ʕ◔ϖ◔ʔ
47+
"http": 80,
48+
"https": 443,
49+
"imap2": 143,
50+
"imap3": 220,
51+
"imaps": 993,
52+
"pop3": 110,
53+
"pop3s": 995,
54+
"smtp": 25,
55+
"submissions": 465,
56+
"ssh": 22,
57+
"telnet": 23,
5758
},
5859
}
5960

@@ -83,22 +84,30 @@ const maxPortBufSize = len("mobility-header") + 10
8384

8485
func lookupPortMap(network, service string) (port int, error error) {
8586
switch network {
86-
case "tcp4", "tcp6":
87-
network = "tcp"
88-
case "udp4", "udp6":
89-
network = "udp"
87+
case "ip": // no hints
88+
if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil {
89+
return p, nil
90+
}
91+
return lookupPortMapWithNetwork("udp", "ip", service)
92+
case "tcp", "tcp4", "tcp6":
93+
return lookupPortMapWithNetwork("tcp", "tcp", service)
94+
case "udp", "udp4", "udp6":
95+
return lookupPortMapWithNetwork("udp", "udp", service)
9096
}
97+
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
98+
}
9199

100+
func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) {
92101
if m, ok := services[network]; ok {
93102
var lowerService [maxPortBufSize]byte
94103
n := copy(lowerService[:], service)
95104
lowerASCIIBytes(lowerService[:n])
96105
if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
97106
return port, nil
98107
}
99-
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
108+
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
100109
}
101-
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
110+
return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service}
102111
}
103112

104113
// ipVersion returns the provided network's IP version: '4', '6' or 0
@@ -415,11 +424,13 @@ func LookupPort(network, service string) (port int, err error) {
415424
}
416425

417426
// LookupPort looks up the port for the given network and service.
427+
//
428+
// The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip".
418429
func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
419430
port, needsLookup := parsePort(service)
420431
if needsLookup {
421432
switch network {
422-
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
433+
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip":
423434
case "": // a hint wildcard for Go 1.0 undocumented behavior
424435
network = "ip"
425436
default:

src/net/lookup_plan9.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,26 +203,36 @@ func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []
203203
return
204204
}
205205

206-
func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
206+
func (r *Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
207207
switch network {
208-
case "tcp4", "tcp6":
209-
network = "tcp"
210-
case "udp4", "udp6":
211-
network = "udp"
208+
case "ip": // no hints
209+
if p, err := r.lookupPortWithNetwork(ctx, "tcp", "ip", service); err == nil {
210+
return p, nil
211+
}
212+
return r.lookupPortWithNetwork(ctx, "udp", "ip", service)
213+
case "tcp", "tcp4", "tcp6":
214+
return r.lookupPortWithNetwork(ctx, "tcp", "tcp", service)
215+
case "udp", "udp4", "udp6":
216+
return r.lookupPortWithNetwork(ctx, "udp", "udp", service)
217+
default:
218+
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
212219
}
220+
}
221+
222+
func (*Resolver) lookupPortWithNetwork(ctx context.Context, network, errNetwork, service string) (port int, err error) {
213223
lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
214224
if err != nil {
215225
if stringsHasSuffix(err.Error(), "can't translate service") {
216-
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
226+
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
217227
}
218228
return
219229
}
220230
if len(lines) == 0 {
221-
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
231+
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
222232
}
223233
f := getFields(lines[0])
224234
if len(f) < 2 {
225-
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
235+
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
226236
}
227237
s := f[1]
228238
if i := bytealg.IndexByteString(s, '!'); i >= 0 {
@@ -231,7 +241,7 @@ func (*Resolver) lookupPort(ctx context.Context, network, service string) (port
231241
if n, _, ok := dtoi(s); ok {
232242
return n, nil
233243
}
234-
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
244+
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
235245
}
236246

237247
func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {

src/net/lookup_test.go

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,9 +1462,65 @@ func testLookupNoData(t *testing.T, prefix string) {
14621462
}
14631463

14641464
func TestLookupPortNotFound(t *testing.T) {
1465-
_, err := LookupPort("udp", "_-unknown-service-")
1466-
var dnsErr *DNSError
1467-
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
1468-
t.Fatalf("unexpected error: %v", err)
1465+
allResolvers(t, func(t *testing.T) {
1466+
_, err := LookupPort("udp", "_-unknown-service-")
1467+
var dnsErr *DNSError
1468+
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
1469+
t.Fatalf("unexpected error: %v", err)
1470+
}
1471+
})
1472+
}
1473+
1474+
// submissions service is only available through a tcp network, see:
1475+
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=submissions
1476+
var tcpOnlyService = func() string {
1477+
// plan9 does not have submissions service defined in the service database.
1478+
if runtime.GOOS == "plan9" {
1479+
return "https"
14691480
}
1481+
return "submissions"
1482+
}()
1483+
1484+
func TestLookupPortDifferentNetwork(t *testing.T) {
1485+
allResolvers(t, func(t *testing.T) {
1486+
_, err := LookupPort("udp", tcpOnlyService)
1487+
var dnsErr *DNSError
1488+
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
1489+
t.Fatalf("unexpected error: %v", err)
1490+
}
1491+
})
1492+
}
1493+
1494+
func TestLookupPortEmptyNetworkString(t *testing.T) {
1495+
allResolvers(t, func(t *testing.T) {
1496+
_, err := LookupPort("", tcpOnlyService)
1497+
if err != nil {
1498+
t.Fatalf("unexpected error: %v", err)
1499+
}
1500+
})
1501+
}
1502+
1503+
func TestLookupPortIPNetworkString(t *testing.T) {
1504+
allResolvers(t, func(t *testing.T) {
1505+
_, err := LookupPort("ip", tcpOnlyService)
1506+
if err != nil {
1507+
t.Fatalf("unexpected error: %v", err)
1508+
}
1509+
})
1510+
}
1511+
1512+
func allResolvers(t *testing.T, f func(t *testing.T)) {
1513+
t.Run("default resolver", f)
1514+
t.Run("forced go resolver", func(t *testing.T) {
1515+
if fixup := forceGoDNS(); fixup != nil {
1516+
defer fixup()
1517+
f(t)
1518+
}
1519+
})
1520+
t.Run("forced cgo resolver", func(t *testing.T) {
1521+
if fixup := forceCgoDNS(); fixup != nil {
1522+
defer fixup()
1523+
f(t)
1524+
}
1525+
})
14701526
}

src/net/lookup_windows.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,28 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int
200200
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
201201
acquireThread()
202202
defer releaseThread()
203-
var stype int32
203+
204+
var hints syscall.AddrinfoW
205+
204206
switch network {
205-
case "tcp4", "tcp6":
206-
stype = syscall.SOCK_STREAM
207-
case "udp4", "udp6":
208-
stype = syscall.SOCK_DGRAM
207+
case "ip": // no hints
208+
case "tcp", "tcp4", "tcp6":
209+
hints.Socktype = syscall.SOCK_STREAM
210+
hints.Protocol = syscall.IPPROTO_TCP
211+
case "udp", "udp4", "udp6":
212+
hints.Socktype = syscall.SOCK_DGRAM
213+
hints.Protocol = syscall.IPPROTO_UDP
214+
default:
215+
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
209216
}
210-
hints := syscall.AddrinfoW{
211-
Family: syscall.AF_UNSPEC,
212-
Socktype: stype,
213-
Protocol: syscall.IPPROTO_IP,
217+
218+
switch ipVersion(network) {
219+
case '4':
220+
hints.Family = syscall.AF_INET
221+
case '6':
222+
hints.Family = syscall.AF_INET6
214223
}
224+
215225
var result *syscall.AddrinfoW
216226
e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
217227
if e != nil {

0 commit comments

Comments
 (0)