mirror of
https://github.com/golang/go
synced 2024-11-23 15:00:03 -07:00
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 <iant@golang.org>
This commit is contained in:
parent
deb6c5b920
commit
99f5f796d9
23
src/net/cgo_resnew.go
Normal file
23
src/net/cgo_resnew.go
Normal file
@ -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
|
||||
}
|
23
src/net/cgo_resold.go
Normal file
23
src/net/cgo_resold.go
Normal file
@ -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
|
||||
}
|
33
src/net/cgo_socknew.go
Normal file
33
src/net/cgo_socknew.go
Normal file
@ -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))
|
||||
}
|
33
src/net/cgo_sockold.go
Normal file
33
src/net/cgo_sockold.go
Normal file
@ -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))
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
ptrs, err, ok := cgoLookupPTR(addr)
|
||||
if !ok {
|
||||
ptrs, err = goLookupPTR(addr)
|
||||
}
|
||||
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
|
||||
return ptrs, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user