net.go 7.81 KB
Newer Older
Steven Allen's avatar
Steven Allen committed
1
// package sockaddrnet provides conversions between net.Addr and unix.Sockaddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
2
package sockaddrnet
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
3 4

import (
Steven Allen's avatar
Steven Allen committed
5
	"golang.org/x/sys/unix"
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
6 7 8
	"net"
)

Steven Allen's avatar
Steven Allen committed
9
// NetAddrAF returns the unix 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
	}
}

Steven Allen's avatar
Steven Allen committed
30
// IPAF returns the unix 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
	}
}

Steven Allen's avatar
Steven Allen committed
45
// NetAddrIPPROTO returns the unix IPPROTO_* type for a given net.Addr
46 47 48 49 50 51
// 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
	}
}

Steven Allen's avatar
Steven Allen committed
72
// NetAddrSOCK returns the unix SOCK_* type for a given net.Addr
73 74 75 76
// 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
	}
}

Steven Allen's avatar
Steven Allen committed
98
// NetAddrToSockaddr converts a net.Addr to a unix.Sockaddr.
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
99
// Returns nil if the input is invalid or conversion is not possible.
Steven Allen's avatar
Steven Allen committed
100
func NetAddrToSockaddr(addr net.Addr) unix.Sockaddr {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
101 102 103 104 105 106 107 108 109 110
	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
	}
}

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

	case ip.To4() != nil:
		var buf [4]byte
		copy(buf[:], ip[12:16]) // last 4 bytes
Steven Allen's avatar
Steven Allen committed
127
		return &unix.SockaddrInet4{Addr: buf}
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
128 129 130 131

	case ip.To16() != nil:
		var buf [16]byte
		copy(buf[:], ip)
Steven Allen's avatar
Steven Allen committed
132
		return &unix.SockaddrInet6{Addr: buf, ZoneId: uint32(IP6ZoneToInt(zone))}
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
133
	}
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
}

Steven Allen's avatar
Steven Allen committed
137
// IPAddrToSockaddr converts a net.IPAddr to a unix.Sockaddr.
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
138
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
139
func IPAddrToSockaddr(addr *net.IPAddr) unix.Sockaddr {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
140 141 142
	return IPAndZoneToSockaddr(addr.IP, addr.Zone)
}

Steven Allen's avatar
Steven Allen committed
143
// TCPAddrToSockaddr converts a net.TCPAddr to a unix.Sockaddr.
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
144
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
145
func TCPAddrToSockaddr(addr *net.TCPAddr) unix.Sockaddr {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
146 147
	sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
148
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
149 150
		sa.Port = addr.Port
		return sa
Steven Allen's avatar
Steven Allen committed
151
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
152 153
		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
	}
}

Steven Allen's avatar
Steven Allen committed
159
// UDPAddrToSockaddr converts a net.UDPAddr to a unix.Sockaddr.
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
160
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
161
func UDPAddrToSockaddr(addr *net.UDPAddr) unix.Sockaddr {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
162 163
	sa := IPAndZoneToSockaddr(addr.IP, addr.Zone)
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
164
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
165 166
		sa.Port = addr.Port
		return sa
Steven Allen's avatar
Steven Allen committed
167
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
168 169
		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
	}
}

Steven Allen's avatar
Steven Allen committed
175 176
// UnixAddrToSockaddr converts a net.UnixAddr to a unix.Sockaddr, and returns
// the type (unix.SOCK_STREAM, unix.SOCK_DGRAM, unix.SOCK_SEQPACKET)
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
177
// Returns (nil, 0) if conversion fails.
Steven Allen's avatar
Steven Allen committed
178
func UnixAddrToSockaddr(addr *net.UnixAddr) (unix.Sockaddr, int) {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
179 180 181
	t := 0
	switch addr.Net {
	case "unix":
Steven Allen's avatar
Steven Allen committed
182
		t = unix.SOCK_STREAM
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
183
	case "unixgram":
Steven Allen's avatar
Steven Allen committed
184
		t = unix.SOCK_DGRAM
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
185
	case "unixpacket":
Steven Allen's avatar
Steven Allen committed
186
		t = unix.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
	}
Steven Allen's avatar
Steven Allen committed
190
	return &unix.SockaddrUnix{Name: addr.Name}, t
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
191 192
}

Steven Allen's avatar
Steven Allen committed
193
// IPAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a unix.Sockaddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
194
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
195
func SockaddrToIPAndZone(sa unix.Sockaddr) (net.IP, string) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
196
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
197
	case *unix.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
		copy(ip[12:16], sa.Addr[:])
		return ip, ""

Steven Allen's avatar
Steven Allen committed
202
	case *unix.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
		copy(ip, sa.Addr[:])
		return ip, IP6ZoneToString(int(sa.ZoneId))
	}
	return nil, ""
}

Steven Allen's avatar
Steven Allen committed
210
// SockaddrToIPAddr converts a unix.Sockaddr to a net.IPAddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
211
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
212
func SockaddrToIPAddr(sa unix.Sockaddr) *net.IPAddr {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
213 214
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa.(type) {
Steven Allen's avatar
Steven Allen committed
215
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
216
		return &net.IPAddr{IP: ip}
Steven Allen's avatar
Steven Allen committed
217
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
218 219 220 221 222
		return &net.IPAddr{IP: ip, Zone: zone}
	}
	return nil
}

Steven Allen's avatar
Steven Allen committed
223
// SockaddrToTCPAddr converts a unix.Sockaddr to a net.TCPAddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
224
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
225
func SockaddrToTCPAddr(sa unix.Sockaddr) *net.TCPAddr {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
226 227
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
228
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
229
		return &net.TCPAddr{IP: ip, Port: sa.Port}
Steven Allen's avatar
Steven Allen committed
230
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
231 232 233 234 235
		return &net.TCPAddr{IP: ip, Port: sa.Port, Zone: zone}
	}
	return nil
}

Steven Allen's avatar
Steven Allen committed
236
// SockaddrToUDPAddr converts a unix.Sockaddr to a net.UDPAddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
237
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
238
func SockaddrToUDPAddr(sa unix.Sockaddr) *net.UDPAddr {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
239 240
	ip, zone := SockaddrToIPAndZone(sa)
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
241
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
242
		return &net.UDPAddr{IP: ip, Port: sa.Port}
Steven Allen's avatar
Steven Allen committed
243
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
244 245 246 247 248
		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
// from: go/src/pkg/net/unixsock_posix.go

Steven Allen's avatar
Steven Allen committed
251
// SockaddrToUnixAddr converts a unix.Sockaddr to a net.UnixAddr
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
252
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
253 254
func SockaddrToUnixAddr(sa unix.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*unix.SockaddrUnix); ok {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
255 256 257 258 259
		return &net.UnixAddr{Name: s.Name, Net: "unix"}
	}
	return nil
}

Steven Allen's avatar
Steven Allen committed
260
// SockaddrToUnixgramAddr converts a unix.Sockaddr to a net.UnixAddr
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
261
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
262 263
func SockaddrToUnixgramAddr(sa unix.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*unix.SockaddrUnix); ok {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
264 265 266 267 268
		return &net.UnixAddr{Name: s.Name, Net: "unixgram"}
	}
	return nil
}

Steven Allen's avatar
Steven Allen committed
269
// SockaddrToUnixpacketAddr converts a unix.Sockaddr to a net.UnixAddr
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
270
// Returns nil if conversion fails.
Steven Allen's avatar
Steven Allen committed
271 272
func SockaddrToUnixpacketAddr(sa unix.Sockaddr) *net.UnixAddr {
	if s, ok := sa.(*unix.SockaddrUnix); ok {
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
273 274 275 276 277 278 279
		return &net.UnixAddr{Name: s.Name, Net: "unixpacket"}
	}
	return nil
}

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

Steven Allen's avatar
Steven Allen committed
280
// IP6ZoneToString converts an IP6 Zone unix int to a net string
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
281 282 283 284 285 286 287 288 289 290 291
// 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))
}

Steven Allen's avatar
Steven Allen committed
292
// IP6ZoneToInt converts an IP6 Zone net string to a unix int
Juan Batiz-Benet's avatar
net pkg  
Juan Batiz-Benet committed
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
// 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
}