mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net: implement ip protocol name to number resolver for windows
Fixes #2215. Fixes #2216. R=golang-dev, dave, rsc CC=golang-dev https://golang.org/cl/5248055
This commit is contained in:
parent
d69b820e01
commit
059c68bf0c
8 changed files with 103 additions and 37 deletions
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -64,7 +65,7 @@ var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO
|
||||||
|
|
||||||
// test (raw) IP socket using ICMP
|
// test (raw) IP socket using ICMP
|
||||||
func TestICMP(t *testing.T) {
|
func TestICMP(t *testing.T) {
|
||||||
if os.Getuid() != 0 {
|
if runtime.GOOS != "windows" && os.Getuid() != 0 {
|
||||||
t.Logf("test disabled; must be root")
|
t.Logf("test disabled; must be root")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,9 @@ package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
var onceReadProtocols sync.Once
|
|
||||||
|
|
||||||
func sockaddrToIP(sa syscall.Sockaddr) Addr {
|
func sockaddrToIP(sa syscall.Sockaddr) Addr {
|
||||||
switch sa := sa.(type) {
|
switch sa := sa.(type) {
|
||||||
case *syscall.SockaddrInet4:
|
case *syscall.SockaddrInet4:
|
||||||
|
|
@ -209,33 +206,7 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
|
||||||
return c.WriteToIP(b, a)
|
return c.WriteToIP(b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
var protocols map[string]int
|
|
||||||
|
|
||||||
func readProtocols() {
|
|
||||||
protocols = make(map[string]int)
|
|
||||||
if file, err := open("/etc/protocols"); err == nil {
|
|
||||||
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
|
|
||||||
// tcp 6 TCP # transmission control protocol
|
|
||||||
if i := byteIndex(line, '#'); i >= 0 {
|
|
||||||
line = line[0:i]
|
|
||||||
}
|
|
||||||
f := getFields(line)
|
|
||||||
if len(f) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if proto, _, ok := dtoi(f[1], 0); ok {
|
|
||||||
protocols[f[0]] = proto
|
|
||||||
for _, alias := range f[2:] {
|
|
||||||
protocols[alias] = proto
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitNetProto(netProto string) (net string, proto int, err os.Error) {
|
func splitNetProto(netProto string) (net string, proto int, err os.Error) {
|
||||||
onceReadProtocols.Do(readProtocols)
|
|
||||||
i := last(netProto, ':')
|
i := last(netProto, ':')
|
||||||
if i < 0 { // no colon
|
if i < 0 { // no colon
|
||||||
return "", 0, os.NewError("no IP protocol specified")
|
return "", 0, os.NewError("no IP protocol specified")
|
||||||
|
|
@ -244,13 +215,12 @@ func splitNetProto(netProto string) (net string, proto int, err os.Error) {
|
||||||
protostr := netProto[i+1:]
|
protostr := netProto[i+1:]
|
||||||
proto, i, ok := dtoi(protostr, 0)
|
proto, i, ok := dtoi(protostr, 0)
|
||||||
if !ok || i != len(protostr) {
|
if !ok || i != len(protostr) {
|
||||||
// lookup by name
|
proto, err = lookupProtocol(protostr)
|
||||||
proto, ok = protocols[protostr]
|
if err != nil {
|
||||||
if ok {
|
return "", 0, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return net, proto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialIP connects to the remote address raddr on the network net,
|
// DialIP connects to the remote address raddr on the network net,
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,50 @@ package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
protocols map[string]int
|
||||||
|
onceReadProtocols sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// readProtocols loads contents of /etc/protocols into protocols map
|
||||||
|
// for quick access.
|
||||||
|
func readProtocols() {
|
||||||
|
protocols = make(map[string]int)
|
||||||
|
if file, err := open("/etc/protocols"); err == nil {
|
||||||
|
for line, ok := file.readLine(); ok; line, ok = file.readLine() {
|
||||||
|
// tcp 6 TCP # transmission control protocol
|
||||||
|
if i := byteIndex(line, '#'); i >= 0 {
|
||||||
|
line = line[0:i]
|
||||||
|
}
|
||||||
|
f := getFields(line)
|
||||||
|
if len(f) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if proto, _, ok := dtoi(f[1], 0); ok {
|
||||||
|
protocols[f[0]] = proto
|
||||||
|
for _, alias := range f[2:] {
|
||||||
|
protocols[alias] = proto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookupProtocol looks up IP protocol name in /etc/protocols and
|
||||||
|
// returns correspondent protocol number.
|
||||||
|
func lookupProtocol(name string) (proto int, err os.Error) {
|
||||||
|
onceReadProtocols.Do(readProtocols)
|
||||||
|
proto, found := protocols[name]
|
||||||
|
if !found {
|
||||||
|
return 0, os.NewError("unknown IP protocol specified: " + name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// LookupHost looks up the given host using the local resolver.
|
// LookupHost looks up the given host using the local resolver.
|
||||||
// It returns an array of that host's addresses.
|
// It returns an array of that host's addresses.
|
||||||
func LookupHost(host string) (addrs []string, err os.Error) {
|
func LookupHost(host string) (addrs []string, err os.Error) {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,22 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var hostentLock sync.Mutex
|
var (
|
||||||
var serventLock sync.Mutex
|
protoentLock sync.Mutex
|
||||||
|
hostentLock sync.Mutex
|
||||||
|
serventLock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// lookupProtocol looks up IP protocol name and returns correspondent protocol number.
|
||||||
|
func lookupProtocol(name string) (proto int, err os.Error) {
|
||||||
|
protoentLock.Lock()
|
||||||
|
defer protoentLock.Unlock()
|
||||||
|
p, e := syscall.GetProtoByName(name)
|
||||||
|
if e != 0 {
|
||||||
|
return 0, os.NewSyscallError("GetProtoByName", e)
|
||||||
|
}
|
||||||
|
return int(p.Proto), nil
|
||||||
|
}
|
||||||
|
|
||||||
func LookupHost(name string) (addrs []string, err os.Error) {
|
func LookupHost(name string) (addrs []string, err os.Error) {
|
||||||
ips, err := LookupIP(name)
|
ips, err := LookupIP(name)
|
||||||
|
|
|
||||||
|
|
@ -502,6 +502,7 @@ func Chmod(path string, mode uint32) (errno int) {
|
||||||
//sys GetHostByName(name string) (h *Hostent, errno int) [failretval==nil] = ws2_32.gethostbyname
|
//sys GetHostByName(name string) (h *Hostent, errno int) [failretval==nil] = ws2_32.gethostbyname
|
||||||
//sys GetServByName(name string, proto string) (s *Servent, errno int) [failretval==nil] = ws2_32.getservbyname
|
//sys GetServByName(name string, proto string) (s *Servent, errno int) [failretval==nil] = ws2_32.getservbyname
|
||||||
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
|
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
|
||||||
|
//sys GetProtoByName(name string) (p *Protoent, errno int) [failretval==nil] = ws2_32.getprotobyname
|
||||||
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
|
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
|
||||||
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
|
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
|
||||||
//sys GetIfEntry(pIfRow *MibIfRow) (errcode int) = iphlpapi.GetIfEntry
|
//sys GetIfEntry(pIfRow *MibIfRow) (errcode int) = iphlpapi.GetIfEntry
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ var (
|
||||||
procgethostbyname = modws2_32.NewProc("gethostbyname")
|
procgethostbyname = modws2_32.NewProc("gethostbyname")
|
||||||
procgetservbyname = modws2_32.NewProc("getservbyname")
|
procgetservbyname = modws2_32.NewProc("getservbyname")
|
||||||
procntohs = modws2_32.NewProc("ntohs")
|
procntohs = modws2_32.NewProc("ntohs")
|
||||||
|
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
||||||
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
||||||
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
||||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||||
|
|
@ -1314,6 +1315,21 @@ func Ntohs(netshort uint16) (u uint16) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetProtoByName(name string) (p *Protoent, errno int) {
|
||||||
|
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
|
||||||
|
p = (*Protoent)(unsafe.Pointer(r0))
|
||||||
|
if p == nil {
|
||||||
|
if e1 != 0 {
|
||||||
|
errno = int(e1)
|
||||||
|
} else {
|
||||||
|
errno = EINVAL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errno = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
|
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
|
||||||
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
|
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
|
||||||
status = uint32(r0)
|
status = uint32(r0)
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ var (
|
||||||
procgethostbyname = modws2_32.NewProc("gethostbyname")
|
procgethostbyname = modws2_32.NewProc("gethostbyname")
|
||||||
procgetservbyname = modws2_32.NewProc("getservbyname")
|
procgetservbyname = modws2_32.NewProc("getservbyname")
|
||||||
procntohs = modws2_32.NewProc("ntohs")
|
procntohs = modws2_32.NewProc("ntohs")
|
||||||
|
procgetprotobyname = modws2_32.NewProc("getprotobyname")
|
||||||
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
|
||||||
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
||||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||||
|
|
@ -1314,6 +1315,21 @@ func Ntohs(netshort uint16) (u uint16) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetProtoByName(name string) (p *Protoent, errno int) {
|
||||||
|
r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
|
||||||
|
p = (*Protoent)(unsafe.Pointer(r0))
|
||||||
|
if p == nil {
|
||||||
|
if e1 != 0 {
|
||||||
|
errno = int(e1)
|
||||||
|
} else {
|
||||||
|
errno = EINVAL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errno = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
|
func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
|
||||||
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
|
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
|
||||||
status = uint32(r0)
|
status = uint32(r0)
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,12 @@ type Hostent struct {
|
||||||
AddrList **byte
|
AddrList **byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Protoent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Proto uint16
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DNS_TYPE_A = 0x0001
|
DNS_TYPE_A = 0x0001
|
||||||
DNS_TYPE_NS = 0x0002
|
DNS_TYPE_NS = 0x0002
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue