]> Cypherpunks repositories - gostls13.git/commitdiff
net: allow LookupAddr to use getnameinfo when cgo is enabled
authorMikio Hara <mikioh.mikioh@gmail.com>
Wed, 28 Jan 2015 11:08:41 +0000 (20:08 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Wed, 17 Jun 2015 00:28:31 +0000 (00:28 +0000)
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 <iant@golang.org>
src/net/cgo_resnew.go [new file with mode: 0644]
src/net/cgo_resold.go [new file with mode: 0644]
src/net/cgo_socknew.go [new file with mode: 0644]
src/net/cgo_sockold.go [new file with mode: 0644]
src/net/cgo_stub.go
src/net/cgo_unix.go
src/net/dnsclient_unix.go
src/net/lookup_test.go
src/net/lookup_unix.go

diff --git a/src/net/cgo_resnew.go b/src/net/cgo_resnew.go
new file mode 100644 (file)
index 0000000..a13e5d1
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+*/
+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 (file)
index 0000000..cf09e83
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+*/
+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 (file)
index 0000000..b508284
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+*/
+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 (file)
index 0000000..522e8e5
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+*/
+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))
+}
index c4937efde2a6736843ef8c02e2a1976762c121cf..6ee052d138399a1beee6031bd727e2b2a5c7f2b9 100644 (file)
@@ -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
+}
index 34588a3baaafba0d9a3ed1ba98b35c44796b05cd..d9d5f0377cd82a709d9a694af870da8e8b296ca4 100644 (file)
@@ -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()
index fab515f5c29175683bfcdf3d9d33007a51e4f573..8a1745f3cb9b091d5c6c49de3c3718d306193009 100644 (file)
@@ -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
+}
index 064bc0b9f16c76e0572d576c39778e20b487612c..a42ae298ef13103e4a1c9480bad8a1b8acf5f7b9 100644 (file)
@@ -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)
index 6484414e4bdef234be6d7dd90aad6283859a7caf..1c811d268330a1d0d4911ee1bed9c2d9446fb4fb 100644 (file)
@@ -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
 }