--- /dev/null
+// 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
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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))
+}
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
+}
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()
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
+}
}
}
-var lookupGooglePublicDNSAddrs = []struct {
+var lookupGooglePublicDNSAddrTests = []struct {
addr, name string
}{
{"8.8.8.8", ".google.com"},
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)
}
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
}