From: Mikio Hara Date: Wed, 28 Jan 2015 11:08:41 +0000 (+0900) Subject: net: allow LookupAddr to use getnameinfo when cgo is enabled X-Git-Tag: go1.5beta1~229 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=99f5f796d9e689befdd27f5563e28cd49dcc1567;p=gostls13.git net: allow LookupAddr to use getnameinfo when cgo is enabled This change allows LookupAddr to use getnameinfo through cgo for working together with various name services other than DNS. Fixes #7855. Change-Id: I5b3b4aefe3d1b904541c3350865734d8cbb1c1c4 Reviewed-on: https://go-review.googlesource.com/3420 Reviewed-by: Ian Lance Taylor --- diff --git a/src/net/cgo_resnew.go b/src/net/cgo_resnew.go new file mode 100644 index 0000000000..a13e5d1050 --- /dev/null +++ b/src/net/cgo_resnew.go @@ -0,0 +1,23 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build darwin linux solaris + +package net + +/* +#include +#include + +#include +*/ +import "C" + +import "unsafe" + +func cgoNameinfoPTR(b []byte, sa *C.struct_sockaddr, salen C.socklen_t) (int, error) { + gerrno, err := C.getnameinfo(sa, salen, (*C.char)(unsafe.Pointer(&b[0])), C.socklen_t(len(b)), nil, 0, C.NI_NAMEREQD) + return int(gerrno), err +} diff --git a/src/net/cgo_resold.go b/src/net/cgo_resold.go new file mode 100644 index 0000000000..cf09e83e51 --- /dev/null +++ b/src/net/cgo_resold.go @@ -0,0 +1,23 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build freebsd dragonfly netbsd openbsd + +package net + +/* +#include +#include + +#include +*/ +import "C" + +import "unsafe" + +func cgoNameinfoPTR(b []byte, sa *C.struct_sockaddr, salen C.socklen_t) (int, error) { + gerrno, err := C.getnameinfo(sa, salen, (*C.char)(unsafe.Pointer(&b[0])), C.size_t(len(b)), nil, 0, C.NI_NAMEREQD) + return int(gerrno), err +} diff --git a/src/net/cgo_socknew.go b/src/net/cgo_socknew.go new file mode 100644 index 0000000000..b5082840fb --- /dev/null +++ b/src/net/cgo_socknew.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build android linux solaris + +package net + +/* +#include +#include + +#include +*/ +import "C" + +import ( + "syscall" + "unsafe" +) + +func cgoSockaddrInet4(ip IP) *C.struct_sockaddr { + sa := syscall.RawSockaddrInet4{Family: syscall.AF_INET} + copy(sa.Addr[:], ip) + return (*C.struct_sockaddr)(unsafe.Pointer(&sa)) +} + +func cgoSockaddrInet6(ip IP) *C.struct_sockaddr { + sa := syscall.RawSockaddrInet6{Family: syscall.AF_INET6} + copy(sa.Addr[:], ip) + return (*C.struct_sockaddr)(unsafe.Pointer(&sa)) +} diff --git a/src/net/cgo_sockold.go b/src/net/cgo_sockold.go new file mode 100644 index 0000000000..522e8e5880 --- /dev/null +++ b/src/net/cgo_sockold.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build darwin dragonfly freebsd netbsd openbsd + +package net + +/* +#include +#include + +#include +*/ +import "C" + +import ( + "syscall" + "unsafe" +) + +func cgoSockaddrInet4(ip IP) *C.struct_sockaddr { + sa := syscall.RawSockaddrInet4{Len: syscall.SizeofSockaddrInet4, Family: syscall.AF_INET} + copy(sa.Addr[:], ip) + return (*C.struct_sockaddr)(unsafe.Pointer(&sa)) +} + +func cgoSockaddrInet6(ip IP) *C.struct_sockaddr { + sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6} + copy(sa.Addr[:], ip) + return (*C.struct_sockaddr)(unsafe.Pointer(&sa)) +} diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go index c4937efde2..6ee052d138 100644 --- a/src/net/cgo_stub.go +++ b/src/net/cgo_stub.go @@ -27,3 +27,7 @@ func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { func cgoLookupCNAME(name string) (cname string, err error, completed bool) { return "", nil, false } + +func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) { + return nil, nil, false +} diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index 34588a3baa..d9d5f0377c 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -169,6 +169,72 @@ func cgoLookupCNAME(name string) (cname string, err error, completed bool) { return } +// These are roughly enough for the following: +// +// Source Encoding Maximum length of single name entry +// Unicast DNS ASCII or <=253 + a NUL terminator +// Unicode in RFC 5892 252 * total number of labels + delimiters + a NUL terminator +// Multicast DNS UTF-8 in RFC 5198 or <=253 + a NUL terminator +// the same as unicast DNS ASCII <=253 + a NUL terminator +// Local database various depends on implementation +const ( + nameinfoLen = 64 + maxNameinfoLen = 4096 +) + +func cgoLookupPTR(addr string) ([]string, error, bool) { + acquireThread() + defer releaseThread() + + ip := ParseIP(addr) + if ip == nil { + return nil, &DNSError{Err: "invalid address", Name: addr}, true + } + sa, salen := cgoSockaddr(ip) + if sa == nil { + return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true + } + var err error + var b []byte + var gerrno int + for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { + b = make([]byte, l) + gerrno, err = cgoNameinfoPTR(b, sa, salen) + if gerrno == 0 || gerrno != C.EAI_OVERFLOW { + break + } + } + if gerrno != 0 { + switch gerrno { + case C.EAI_SYSTEM: + if err == nil { // see golang.org/issue/6232 + err = syscall.EMFILE + } + default: + err = addrinfoErrno(gerrno) + } + return nil, &DNSError{Err: err.Error(), Name: addr}, true + } + + for i := 0; i < len(b); i++ { + if b[i] == 0 { + b = b[:i] + break + } + } + return []string{string(b)}, nil, true +} + +func cgoSockaddr(ip IP) (*C.struct_sockaddr, C.socklen_t) { + if ip4 := ip.To4(); ip4 != nil { + return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4) + } + if ip6 := ip.To16(); ip6 != nil { + return cgoSockaddrInet6(ip6), C.socklen_t(syscall.SizeofSockaddrInet6) + } + return nil, 0 +} + func copyIP(x IP) IP { if len(x) < 16 { return x.To16() diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index fab515f5c2..8a1745f3cb 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -479,3 +479,28 @@ func goLookupCNAME(name string) (cname string, err error) { cname = rr[0].(*dnsRR_CNAME).Cname return } + +// goLookupPTR is the native Go implementation of LookupAddr. +// Used only if cgoLookupPTR refuses to handle the request (that is, +// only if cgoLookupPTR is the stub in cgo_stub.go). +// Normally we let cgo use the C library resolver instead of depending +// on our lookup code, so that Go and C get the same answers. +func goLookupPTR(addr string) ([]string, error) { + names := lookupStaticAddr(addr) + if len(names) > 0 { + return names, nil + } + arpa, err := reverseaddr(addr) + if err != nil { + return nil, err + } + _, rrs, err := lookup(arpa, dnsTypePTR) + if err != nil { + return nil, err + } + ptrs := make([]string, len(rrs)) + for i, rr := range rrs { + ptrs[i] = rr.(*dnsRR_PTR).Ptr + } + return ptrs, nil +} diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 064bc0b9f1..a42ae298ef 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -174,7 +174,7 @@ func TestLookupGmailTXT(t *testing.T) { } } -var lookupGooglePublicDNSAddrs = []struct { +var lookupGooglePublicDNSAddrTests = []struct { addr, name string }{ {"8.8.8.8", ".google.com"}, @@ -191,7 +191,7 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) { t.Skip("both IPv4 and IPv6 are required") } - for _, tt := range lookupGooglePublicDNSAddrs { + for _, tt := range lookupGooglePublicDNSAddrTests { names, err := LookupAddr(tt.addr) if err != nil { t.Fatal(err) diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index 6484414e4b..1c811d2683 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -148,21 +148,9 @@ func lookupTXT(name string) ([]string, error) { } func lookupAddr(addr string) ([]string, error) { - names := lookupStaticAddr(addr) - if len(names) > 0 { - return names, nil - } - arpa, err := reverseaddr(addr) - if err != nil { - return nil, err - } - _, rrs, err := lookup(arpa, dnsTypePTR) - if err != nil { - return nil, err - } - ptrs := make([]string, len(rrs)) - for i, rr := range rrs { - ptrs[i] = rr.(*dnsRR_PTR).Ptr + ptrs, err, ok := cgoLookupPTR(addr) + if !ok { + ptrs, err = goLookupPTR(addr) } - return ptrs, nil + return ptrs, err }