summaryrefslogtreecommitdiff
path: root/src/pkg/net/ipsock.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/ipsock.go')
-rw-r--r--src/pkg/net/ipsock.go46
1 files changed, 38 insertions, 8 deletions
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 80bc3eea5..e8bcac646 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -35,15 +35,28 @@ func kernelSupportsIPv6() bool {
var preferIPv4 = !kernelSupportsIPv6()
-func firstSupportedAddr(addrs []string) (addr IP) {
+func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
for _, s := range addrs {
- addr = ParseIP(s)
- if !preferIPv4 || addr.To4() != nil {
- break
+ if addr := filter(ParseIP(s)); addr != nil {
+ return addr
}
- addr = nil
}
- return addr
+ return nil
+}
+
+func anyaddr(x IP) IP { return x }
+func ipv4only(x IP) IP { return x.To4() }
+
+func ipv6only(x IP) IP {
+ // Only return addresses that we can use
+ // with the kernel's IPv6 addressing modes.
+ // If preferIPv4 is set, it means the IPv6 stack
+ // cannot take IPv4 addresses directly (we prefer
+ // to use the IPv4 stack) so reject IPv4 addresses.
+ if x.To4() != nil && preferIPv4 {
+ return nil
+ }
+ return x
}
// TODO(rsc): if syscall.OS == "linux", we're supposd to read
@@ -131,7 +144,6 @@ func (e InvalidAddrError) String() string { return string(e) }
func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
-
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
switch family {
case syscall.AF_INET:
@@ -218,13 +230,31 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
+ filter := anyaddr
+ if len(net) >= 4 && net[3] == '4' {
+ filter = ipv4only
+ } else if len(net) >= 4 && net[3] == '6' {
+ filter = ipv6only
+ }
// Not an IP address. Try as a DNS name.
addrs, err1 := LookupHost(host)
if err1 != nil {
err = err1
goto Error
}
- addr = firstSupportedAddr(addrs)
+ if filter == anyaddr {
+ // We'll take any IP address, but since the dialing code
+ // does not yet try multiple addresses, prefer to use
+ // an IPv4 address if possible. This is especially relevant
+ // if localhost resolves to [ipv6-localhost, ipv4-localhost].
+ // Too much code assumes localhost == ipv4-localhost.
+ addr = firstSupportedAddr(ipv4only, addrs)
+ if addr == nil {
+ addr = firstSupportedAddr(anyaddr, addrs)
+ }
+ } else {
+ addr = firstSupportedAddr(filter, addrs)
+ }
if addr == nil {
// should not happen
err = &AddrError{"LookupHost returned invalid address", addrs[0]}