Skip to content

net: handle the network parameter properly in LookupPort #63284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/net/cgo_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error)
func cgoLookupPort(ctx context.Context, network, service string) (port int, err error) {
var hints _C_struct_addrinfo
switch network {
case "": // no hints
case "ip": // no hints
case "tcp", "tcp4", "tcp6":
*_C_ai_socktype(&hints) = _C_SOCK_STREAM
*_C_ai_protocol(&hints) = _C_IPPROTO_TCP
Expand Down
51 changes: 31 additions & 20 deletions src/net/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@ var services = map[string]map[string]int{
"domain": 53,
},
"tcp": {
"ftp": 21,
"ftps": 990,
"gopher": 70, // ʕ◔ϖ◔ʔ
"http": 80,
"https": 443,
"imap2": 143,
"imap3": 220,
"imaps": 993,
"pop3": 110,
"pop3s": 995,
"smtp": 25,
"ssh": 22,
"telnet": 23,
"ftp": 21,
"ftps": 990,
"gopher": 70, // ʕ◔ϖ◔ʔ
"http": 80,
"https": 443,
"imap2": 143,
"imap3": 220,
"imaps": 993,
"pop3": 110,
"pop3s": 995,
"smtp": 25,
"submissions": 465,
"ssh": 22,
"telnet": 23,
},
}

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

func lookupPortMap(network, service string) (port int, error error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
case "udp4", "udp6":
network = "udp"
case "ip": // no hints
if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil {
return p, nil
}
return lookupPortMapWithNetwork("udp", "ip", service)
case "tcp", "tcp4", "tcp6":
return lookupPortMapWithNetwork("tcp", "tcp", service)
case "udp", "udp4", "udp6":
return lookupPortMapWithNetwork("udp", "udp", service)
}
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
}

func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) {
if m, ok := services[network]; ok {
var lowerService [maxPortBufSize]byte
n := copy(lowerService[:], service)
lowerASCIIBytes(lowerService[:n])
if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
return port, nil
}
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
}
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service}
}

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

// LookupPort looks up the port for the given network and service.
//
// The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip".
func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
port, needsLookup := parsePort(service)
if needsLookup {
switch network {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip":
case "": // a hint wildcard for Go 1.0 undocumented behavior
network = "ip"
default:
Expand Down
28 changes: 19 additions & 9 deletions src/net/lookup_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,26 +203,36 @@ func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []
return
}

func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
func (r *Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
case "udp4", "udp6":
network = "udp"
case "ip": // no hints
if p, err := r.lookupPortWithNetwork(ctx, "tcp", "ip", service); err == nil {
return p, nil
}
return r.lookupPortWithNetwork(ctx, "udp", "ip", service)
case "tcp", "tcp4", "tcp6":
return r.lookupPortWithNetwork(ctx, "tcp", "tcp", service)
case "udp", "udp4", "udp6":
return r.lookupPortWithNetwork(ctx, "udp", "udp", service)
default:
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
}
}

func (*Resolver) lookupPortWithNetwork(ctx context.Context, network, errNetwork, service string) (port int, err error) {
lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
if err != nil {
if stringsHasSuffix(err.Error(), "can't translate service") {
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
}
return
}
if len(lines) == 0 {
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
}
f := getFields(lines[0])
if len(f) < 2 {
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
}
s := f[1]
if i := bytealg.IndexByteString(s, '!'); i >= 0 {
Expand All @@ -231,7 +241,7 @@ func (*Resolver) lookupPort(ctx context.Context, network, service string) (port
if n, _, ok := dtoi(s); ok {
return n, nil
}
return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true}
return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true}
}

func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
Expand Down
64 changes: 60 additions & 4 deletions src/net/lookup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1462,9 +1462,65 @@ func testLookupNoData(t *testing.T, prefix string) {
}

func TestLookupPortNotFound(t *testing.T) {
_, err := LookupPort("udp", "_-unknown-service-")
var dnsErr *DNSError
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
t.Fatalf("unexpected error: %v", err)
allResolvers(t, func(t *testing.T) {
_, err := LookupPort("udp", "_-unknown-service-")
var dnsErr *DNSError
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
t.Fatalf("unexpected error: %v", err)
}
})
}

// submissions service is only available through a tcp network, see:
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=submissions
var tcpOnlyService = func() string {
// plan9 does not have submissions service defined in the service database.
if runtime.GOOS == "plan9" {
return "https"
}
return "submissions"
}()

func TestLookupPortDifferentNetwork(t *testing.T) {
allResolvers(t, func(t *testing.T) {
_, err := LookupPort("udp", tcpOnlyService)
var dnsErr *DNSError
if !errors.As(err, &dnsErr) || !dnsErr.IsNotFound {
t.Fatalf("unexpected error: %v", err)
}
})
}

func TestLookupPortEmptyNetworkString(t *testing.T) {
allResolvers(t, func(t *testing.T) {
_, err := LookupPort("", tcpOnlyService)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
})
}

func TestLookupPortIPNetworkString(t *testing.T) {
allResolvers(t, func(t *testing.T) {
_, err := LookupPort("ip", tcpOnlyService)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
})
}

func allResolvers(t *testing.T, f func(t *testing.T)) {
t.Run("default resolver", f)
t.Run("forced go resolver", func(t *testing.T) {
if fixup := forceGoDNS(); fixup != nil {
defer fixup()
f(t)
}
})
t.Run("forced cgo resolver", func(t *testing.T) {
if fixup := forceCgoDNS(); fixup != nil {
defer fixup()
f(t)
}
})
}
28 changes: 19 additions & 9 deletions src/net/lookup_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,18 +200,28 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var stype int32

var hints syscall.AddrinfoW

switch network {
case "tcp4", "tcp6":
stype = syscall.SOCK_STREAM
case "udp4", "udp6":
stype = syscall.SOCK_DGRAM
case "ip": // no hints
case "tcp", "tcp4", "tcp6":
hints.Socktype = syscall.SOCK_STREAM
hints.Protocol = syscall.IPPROTO_TCP
case "udp", "udp4", "udp6":
hints.Socktype = syscall.SOCK_DGRAM
hints.Protocol = syscall.IPPROTO_UDP
default:
return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
}
hints := syscall.AddrinfoW{
Family: syscall.AF_UNSPEC,
Socktype: stype,
Protocol: syscall.IPPROTO_IP,

switch ipVersion(network) {
case '4':
hints.Family = syscall.AF_INET
case '6':
hints.Family = syscall.AF_INET6
}

var result *syscall.AddrinfoW
e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
if e != nil {
Expand Down