net.go 7.95 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
// package sockaddrnet provides conversions between net.Addr and syscall.Sockaddr
package sockaddrnet
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
3 4 5 6 7 8

import (
	"net"
	"syscall"
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9
// NetAddrAF returns the syscall AF_* type for a given net.Addr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10
// returns AF_UNSPEC if unknown
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11 12 13
func NetAddrAF(addr net.Addr) int {
	switch addr := addr.(type) {
	default:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14
		return AF_UNSPEC
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15 16 17 18 19 20 21 22 23 24 25

	case *net.IPAddr:
		return IPAF(addr.IP)

	case *net.TCPAddr:
		return IPAF(addr.IP)

	case *net.UDPAddr:
		return IPAF(addr.IP)

	case *net.UnixAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
26
		return AF_UNIX
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27 28 29 30
	}
}

// IPAF returns the syscall AF_* type for a given IP address
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31
// returns AF_UNSPEC if unknown
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
32 33 34
func IPAF(ip net.IP) int {
	switch {
	default:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35
		return AF_UNSPEC
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36 37

	case ip.To4() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38
		return AF_INET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39 40

	case ip.To16() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41
		return AF_INET6
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42 43 44
	}
}

45 46 47 48 49 50 51 52 53 54
// NetAddrIPPROTO returns the syscall IPPROTO_* type for a given net.Addr
// returns -1 if protocol unknown
func NetAddrIPPROTO(addr net.Addr) int {
	switch addr := addr.(type) {
	default:
		return -1

	case *net.IPAddr:
		switch {
		default:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55
			return IPPROTO_IP
56 57

		case addr.IP.To4() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58
			return IPPROTO_IPV4
59 60

		case addr.IP.To16() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61
			return IPPROTO_IPV6
62 63 64
		}

	case *net.TCPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65
		return IPPROTO_TCP
66 67

	case *net.UDPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68
		return IPPROTO_UDP
69 70 71 72 73 74 75 76 77 78
	}
}

// NetAddrSOCK returns the syscall SOCK_* type for a given net.Addr
// returns 0 if type unknown
func NetAddrSOCK(addr net.Addr) int {
	switch addr := addr.(type) {
	default:
		return 0
	case *net.IPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
		return SOCK_DGRAM
80
	case *net.TCPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
		return SOCK_STREAM
82
	case *net.UDPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83
		return SOCK_DGRAM
84 85 86 87 88
	case *net.UnixAddr:
		switch addr.Net {
		default:
			return 0
		case "unix":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89
			return SOCK_STREAM
90
		case "unixgram":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
			return SOCK_DGRAM
92
		case "unixpacket":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93
			return SOCK_SEQPACKET
94 95 96 97
		}
	}
}

Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
// NetAddrToSockaddr converts a net.Addr to a syscall.Sockaddr.
// Returns nil if the input is invalid or conversion is not possible.
func NetAddrToSockaddr(addr net.Addr) syscall.Sockaddr {
	switch addr := addr.(type) {
	default:
		return nil
	case *net.IPAddr:
		return IPAddrToSockaddr(addr)
	case *net.TCPAddr:
		return TCPAddrToSockaddr(addr)
	case *net.UDPAddr:
		return UDPAddrToSockaddr(addr)
	case *net.UnixAddr:
		sa, _ := UnixAddrToSockaddr(addr)
		return sa
	}
}

// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr
// Returns nil if conversion fails.
func IPAndZoneToSockaddr(ip net.IP, zone string) syscall.Sockaddr {
	switch {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121 122
	case len(ip) < net.IPv4len: // default to IPv4
		buf := [4]byte{0, 0, 0, 0}
		return &syscall.SockaddrInet4{Addr: buf}
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
123 124 125 126 127 128 129 130 131 132 133

	case ip.To4() != nil:
		var buf [4]byte
		copy(buf[:], ip[12:16]) // last 4 bytes
		return &syscall.SockaddrInet4{Addr: buf}

	case ip.To16() != nil:
		var buf [16]byte
		copy(buf[:], ip)
		return &syscall.SockaddrInet6{Addr: buf, ZoneId: uint32(IP6ZoneToInt(zone))}
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
134
	panic("should be unreachable")
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
}

// IPAddrToSockaddr converts a net.IPAddr to a syscall.Sockaddr.
// Returns nil if conversion fails.
func IPAddrToSockaddr(addr *net.IPAddr) syscall.Sockaddr {
	return IPAndZoneToSockaddr(addr.IP, addr.Zone)
}

// TCPAddrToSockaddr converts a net.TCPAddr to a syscall.Sockaddr.
// Returns nil if conversion fails.
func TCPAddrToSockaddr(addr *net.TCPAddr) syscall.Sockaddr {
	sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
	switch sa := sa.(type) {
	default:
		return nil
	case *syscall.SockaddrInet4:
		sa.Port = addr.Port
		return sa
	case *syscall.SockaddrInet6:
		sa.Port = addr.Port
		return sa
	}
}

// UDPAddrToSockaddr converts a net.UDPAddr to a syscall.Sockaddr.
// Returns nil if conversion fails.
func UDPAddrToSockaddr(addr *net.UDPAddr) syscall.Sockaddr {
	sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
	switch sa := sa.(type) {
	default:
		return nil
	case *syscall.SockaddrInet4:
		sa.Port = addr.Port
		return sa
	case *syscall.SockaddrInet6:
		sa.Port = addr.Port
		return sa
	}
}

// UnixAddrToSockaddr converts a net.UnixAddr to a syscall.Sockaddr, and returns
// the type (syscall.SOCK_STREAM, syscall.SOCK_DGRAM, syscall.SOCK_SEQPACKET)
// Returns (nil, 0) if conversion fails.
func UnixAddrToSockaddr(addr *net.UnixAddr) (syscall.Sockaddr, int) {
	t := 0
	switch addr.Net {
	default:
		return nil, 0
	case "unix":
		t = syscall.SOCK_STREAM
	case "unixgram":
		t = syscall.SOCK_DGRAM
	case "unixpacket":
		t = syscall.SOCK_SEQPACKET
	}
	return &syscall.SockaddrUnix{Name: addr.Name}, t
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a syscall.Sockaddr
// Returns nil if conversion fails.
func SockaddrToIPAndZone(sa syscall.Sockaddr) (net.IP, string) {
	switch sa := sa.(type) {
	case *syscall.SockaddrInet4:
		var ip net.IP
		copy(ip[12:16], sa.Addr[:])
		return ip, ""

	case *syscall.SockaddrInet6:
		var ip net.IP
		copy(ip, sa.Addr[:])
		return ip, IP6ZoneToString(int(sa.ZoneId))
	}
	return nil, ""
}

// SockaddrToIPAddr converts a syscall.Sockaddr to a net.IPAddr
// Returns nil if conversion fails.
func SockaddrToIPAddr(sa syscall.Sockaddr) *net.IPAddr {
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa.(type) {
	case *syscall.SockaddrInet4:
		return &net.IPAddr{IP: ip}
	case *syscall.SockaddrInet6:
		return &net.IPAddr{IP: ip, Zone: zone}
	}
	return nil
}

// SockaddrToTCPAddr converts a syscall.Sockaddr to a net.TCPAddr
// Returns nil if conversion fails.
func SockaddrToTCPAddr(sa syscall.Sockaddr) *net.TCPAddr {
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa := sa.(type) {
	case *syscall.SockaddrInet4:
		return &net.TCPAddr{IP: ip, Port: sa.Port}
	case *syscall.SockaddrInet6:
		return &net.TCPAddr{IP: ip, Port: sa.Port, Zone: zone}
	}
	return nil
}

// SockaddrToUDPAddr converts a syscall.Sockaddr to a net.UDPAddr
// Returns nil if conversion fails.
func SockaddrToUDPAddr(sa syscall.Sockaddr) *net.UDPAddr {
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa := sa.(type) {
	case *syscall.SockaddrInet4:
		return &net.UDPAddr{IP: ip, Port: sa.Port}
	case *syscall.SockaddrInet6:
		return &net.UDPAddr{IP: ip, Port: sa.Port, Zone: zone}
	}
	return nil
}

Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
// from: go/src/pkg/net/unixsock_posix.go

// SockaddrToUnixAddr converts a syscall.Sockaddr to a net.UnixAddr
// Returns nil if conversion fails.
func SockaddrToUnixAddr(sa syscall.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		return &net.UnixAddr{Name: s.Name, Net: "unix"}
	}
	return nil
}

// SockaddrToUnixgramAddr converts a syscall.Sockaddr to a net.UnixAddr
// Returns nil if conversion fails.
func SockaddrToUnixgramAddr(sa syscall.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		return &net.UnixAddr{Name: s.Name, Net: "unixgram"}
	}
	return nil
}

// SockaddrToUnixpacketAddr converts a syscall.Sockaddr to a net.UnixAddr
// Returns nil if conversion fails.
func SockaddrToUnixpacketAddr(sa syscall.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*syscall.SockaddrUnix); ok {
		return &net.UnixAddr{Name: s.Name, Net: "unixpacket"}
	}
	return nil
}

// from: go/src/pkg/net/ipsock.go

// IP6ZoneToString converts an IP6 Zone syscall int to a net string
// returns "" if zone is 0
func IP6ZoneToString(zone int) string {
	if zone == 0 {
		return ""
	}
	if ifi, err := net.InterfaceByIndex(zone); err == nil {
		return ifi.Name
	}
	return itod(uint(zone))
}

// IP6ZoneToInt converts an IP6 Zone net string to a syscall int
// returns 0 if zone is ""
func IP6ZoneToInt(zone string) int {
	if zone == "" {
		return 0
	}
	if ifi, err := net.InterfaceByName(zone); err == nil {
		return ifi.Index
	}
	n, _, _ := dtoi(zone, 0)
	return n
}

// from: go/src/pkg/net/parse.go

// Convert i to decimal string.
func itod(i uint) string {
	if i == 0 {
		return "0"
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; i > 0; i /= 10 {
		bp--
		b[bp] = byte(i%10) + '0'
	}

	return string(b[bp:])
}

// Bigger than we need, not too big to worry about overflow
const big = 0xFFFFFF

// Decimal to integer starting at &s[i0].
// Returns number, new offset, success.
func dtoi(s string, i0 int) (n int, i int, ok bool) {
	n = 0
	for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
		n = n*10 + int(s[i]-'0')
		if n >= big {
			return 0, i, false
		}
	}
	if i == i0 {
		return 0, i, false
	}
	return n, i, true
}