net.go 7.97 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 14 15 16 17 18 19 20 21 22
func NetAddrAF(addr net.Addr) int {
	switch addr := addr.(type) {
	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
23
		return AF_UNIX
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26

	default:
		return AF_UNSPEC
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 {
	case ip.To4() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35
		return AF_INET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36 37

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

	default:
		return AF_UNSPEC
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42 43 44
	}
}

45 46 47 48 49 50 51
// 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) {
	case *net.IPAddr:
		switch {
		default:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
52
			return IPPROTO_IP
53 54

		case addr.IP.To4() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55
			return IPPROTO_IPV4
56 57

		case addr.IP.To16() != nil:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58
			return IPPROTO_IPV6
59 60 61
		}

	case *net.TCPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
62
		return IPPROTO_TCP
63 64

	case *net.UDPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65
		return IPPROTO_UDP
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66 67 68

	default:
		return -1
69 70 71 72 73 74 75 76
	}
}

// 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) {
	case *net.IPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77
		return SOCK_DGRAM
78
	case *net.TCPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
		return SOCK_STREAM
80
	case *net.UDPAddr:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
		return SOCK_DGRAM
82 83 84 85 86
	case *net.UnixAddr:
		switch addr.Net {
		default:
			return 0
		case "unix":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87
			return SOCK_STREAM
88
		case "unixgram":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89
			return SOCK_DGRAM
90
		case "unixpacket":
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
			return SOCK_SEQPACKET
92
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93 94
	default:
		return 0
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
// 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) {
	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
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112
	default:
		return nil
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
113 114 115 116 117 118 119
	}
}

// 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
}

// 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) {
	case *syscall.SockaddrInet4:
		sa.Port = addr.Port
		return sa
	case *syscall.SockaddrInet6:
		sa.Port = addr.Port
		return sa
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
154 155
	default:
		return nil
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169
	}
}

// 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) {
	case *syscall.SockaddrInet4:
		sa.Port = addr.Port
		return sa
	case *syscall.SockaddrInet6:
		sa.Port = addr.Port
		return sa
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
170 171
	default:
		return nil
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	}
}

// 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 {
	case "unix":
		t = syscall.SOCK_STREAM
	case "unixgram":
		t = syscall.SOCK_DGRAM
	case "unixpacket":
		t = syscall.SOCK_SEQPACKET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
187 188
	default:
		return nil, 0
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
189 190 191 192
	}
	return &syscall.SockaddrUnix{Name: addr.Name}, t
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
193 194 195 196 197
// 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:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
198
		ip := make([]byte, 16)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
199 200 201 202
		copy(ip[12:16], sa.Addr[:])
		return ip, ""

	case *syscall.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
203
		ip := make([]byte, 16)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
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
		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
}