Source file src/pkg/net/ipsock.go
1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // IP sockets 6 7 package net 8 9 var supportsIPv6, supportsIPv4map = probeIPv6Stack() 10 11 func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) { 12 if filter == nil { 13 // We'll take any IP address, but since the dialing code 14 // does not yet try multiple addresses, prefer to use 15 // an IPv4 address if possible. This is especially relevant 16 // if localhost resolves to [ipv6-localhost, ipv4-localhost]. 17 // Too much code assumes localhost == ipv4-localhost. 18 addr = firstSupportedAddr(ipv4only, addrs) 19 if addr == nil { 20 addr = firstSupportedAddr(anyaddr, addrs) 21 } 22 } else { 23 addr = firstSupportedAddr(filter, addrs) 24 } 25 return 26 } 27 28 func firstSupportedAddr(filter func(IP) IP, addrs []string) IP { 29 for _, s := range addrs { 30 if addr := filter(ParseIP(s)); addr != nil { 31 return addr 32 } 33 } 34 return nil 35 } 36 37 func anyaddr(x IP) IP { 38 if x4 := x.To4(); x4 != nil { 39 return x4 40 } 41 if supportsIPv6 { 42 return x 43 } 44 return nil 45 } 46 47 func ipv4only(x IP) IP { return x.To4() } 48 49 func ipv6only(x IP) IP { 50 // Only return addresses that we can use 51 // with the kernel's IPv6 addressing modes. 52 if len(x) == IPv6len && x.To4() == nil && supportsIPv6 { 53 return x 54 } 55 return nil 56 } 57 58 type InvalidAddrError string 59 60 func (e InvalidAddrError) Error() string { return string(e) } 61 func (e InvalidAddrError) Timeout() bool { return false } 62 func (e InvalidAddrError) Temporary() bool { return false } 63 64 // SplitHostPort splits a network address of the form 65 // "host:port" or "[host]:port" into host and port. 66 // The latter form must be used when host contains a colon. 67 func SplitHostPort(hostport string) (host, port string, err error) { 68 // The port starts after the last colon. 69 i := last(hostport, ':') 70 if i < 0 { 71 err = &AddrError{"missing port in address", hostport} 72 return 73 } 74 75 host, port = hostport[0:i], hostport[i+1:] 76 77 // Can put brackets around host ... 78 if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { 79 host = host[1 : len(host)-1] 80 } else { 81 // ... but if there are no brackets, no colons. 82 if byteIndex(host, ':') >= 0 { 83 err = &AddrError{"too many colons in address", hostport} 84 return 85 } 86 } 87 return 88 } 89 90 // JoinHostPort combines host and port into a network address 91 // of the form "host:port" or, if host contains a colon, "[host]:port". 92 func JoinHostPort(host, port string) string { 93 // If host has colons, have to bracket it. 94 if byteIndex(host, ':') >= 0 { 95 return "[" + host + "]:" + port 96 } 97 return host + ":" + port 98 } 99 100 // Convert "host:port" into IP address and port. 101 func hostPortToIP(net, hostport string) (ip IP, iport int, err error) { 102 host, port, err := SplitHostPort(hostport) 103 if err != nil { 104 return nil, 0, err 105 } 106 107 var addr IP 108 if host != "" { 109 // Try as an IP address. 110 addr = ParseIP(host) 111 if addr == nil { 112 var filter func(IP) IP 113 if net != "" && net[len(net)-1] == '4' { 114 filter = ipv4only 115 } 116 if net != "" && net[len(net)-1] == '6' { 117 filter = ipv6only 118 } 119 // Not an IP address. Try as a DNS name. 120 addrs, err := LookupHost(host) 121 if err != nil { 122 return nil, 0, err 123 } 124 addr = firstFavoriteAddr(filter, addrs) 125 if addr == nil { 126 // should not happen 127 return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]} 128 } 129 } 130 } 131 132 p, i, ok := dtoi(port, 0) 133 if !ok || i != len(port) { 134 p, err = LookupPort(net, port) 135 if err != nil { 136 return nil, 0, err 137 } 138 } 139 if p < 0 || p > 0xFFFF { 140 return nil, 0, &AddrError{"invalid port", port} 141 } 142 143 return addr, p, nil 144 145 }