mirror of
https://github.com/golang/go
synced 2024-11-18 11:55:01 -07:00
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: eaa616378b
GitHub-Pull-Request: golang/go#63284
Reviewed-on: https://go-review.googlesource.com/c/go/+/531635
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Mateusz Poliwczak <mpoliwczak34@gmail.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David du Colombier <0intro@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
This commit is contained in:
parent
340a4f55c4
commit
ef3171c5eb
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
@ -83,12 +84,20 @@ 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)
|
||||
@ -96,9 +105,9 @@ func lookupPortMap(network, service string) (port int, error error) {
|
||||
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
|
||||
@ -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:
|
||||
|
@ -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 {
|
||||
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user