sockaddr_linux.go 4.02 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package sockaddr

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

Steven Allen's avatar
Steven Allen committed
8
func sockaddrToAny(sa unix.Sockaddr) (*unix.RawSockaddrAny, Socklen, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9
	if sa == nil {
Steven Allen's avatar
Steven Allen committed
10
		return nil, 0, unix.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11 12
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
13
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
14
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15
		if sa.Port < 0 || sa.Port > 0xFFFF {
Steven Allen's avatar
Steven Allen committed
16
			return nil, 0, unix.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17
		}
Steven Allen's avatar
Steven Allen committed
18 19
		var raw unix.RawSockaddrInet4
		raw.Family = unix.AF_INET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21 22 23 24 25
		p := (*[2]byte)(unsafe.Pointer(&raw.Port))
		p[0] = byte(sa.Port >> 8)
		p[1] = byte(sa.Port)
		for i := 0; i < len(sa.Addr); i++ {
			raw.Addr[i] = sa.Addr[i]
		}
Steven Allen's avatar
Steven Allen committed
26
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrInet4, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27

Steven Allen's avatar
Steven Allen committed
28
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29
		if sa.Port < 0 || sa.Port > 0xFFFF {
Steven Allen's avatar
Steven Allen committed
30
			return nil, 0, unix.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31
		}
Steven Allen's avatar
Steven Allen committed
32 33
		var raw unix.RawSockaddrInet6
		raw.Family = unix.AF_INET6
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
34 35 36 37 38 39 40
		p := (*[2]byte)(unsafe.Pointer(&raw.Port))
		p[0] = byte(sa.Port >> 8)
		p[1] = byte(sa.Port)
		raw.Scope_id = sa.ZoneId
		for i := 0; i < len(sa.Addr); i++ {
			raw.Addr[i] = sa.Addr[i]
		}
Steven Allen's avatar
Steven Allen committed
41
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrInet6, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42

Steven Allen's avatar
Steven Allen committed
43
	case *unix.SockaddrUnix:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
44 45
		name := sa.Name
		n := len(name)
Steven Allen's avatar
Steven Allen committed
46
		var raw unix.RawSockaddrUnix
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47
		if n >= len(raw.Path) {
Steven Allen's avatar
Steven Allen committed
48
			return nil, 0, unix.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
49
		}
Steven Allen's avatar
Steven Allen committed
50
		raw.Family = unix.AF_UNIX
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51 52 53 54 55 56 57 58 59 60 61 62 63
		for i := 0; i < n; i++ {
			raw.Path[i] = int8(name[i])
		}
		// length is family (uint16), name, NUL.
		sl := Socklen(2)
		if n > 0 {
			sl += Socklen(n) + 1
		}
		if raw.Path[0] == '@' {
			raw.Path[0] = 0
			// Don't count trailing NUL for abstract address.
			sl--
		}
Steven Allen's avatar
Steven Allen committed
64
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), sl, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65

Steven Allen's avatar
Steven Allen committed
66
	case *unix.SockaddrLinklayer:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
67
		if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
Steven Allen's avatar
Steven Allen committed
68
			return nil, 0, unix.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69
		}
Steven Allen's avatar
Steven Allen committed
70 71
		var raw unix.RawSockaddrLinklayer
		raw.Family = unix.AF_PACKET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
72 73 74 75 76 77 78 79
		raw.Protocol = sa.Protocol
		raw.Ifindex = int32(sa.Ifindex)
		raw.Hatype = sa.Hatype
		raw.Pkttype = sa.Pkttype
		raw.Halen = sa.Halen
		for i := 0; i < len(sa.Addr); i++ {
			raw.Addr[i] = sa.Addr[i]
		}
Steven Allen's avatar
Steven Allen committed
80
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrLinklayer, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
	}
Steven Allen's avatar
Steven Allen committed
82
	return nil, 0, unix.EAFNOSUPPORT
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83 84
}

Steven Allen's avatar
Steven Allen committed
85
func anyToSockaddr(rsa *unix.RawSockaddrAny) (unix.Sockaddr, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86
	switch rsa.Addr.Family {
Steven Allen's avatar
Steven Allen committed
87 88 89
	case unix.AF_NETLINK:
		pp := (*unix.RawSockaddrNetlink)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrNetlink)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
90 91 92 93 94 95
		sa.Family = pp.Family
		sa.Pad = pp.Pad
		sa.Pid = pp.Pid
		sa.Groups = pp.Groups
		return sa, nil

Steven Allen's avatar
Steven Allen committed
96 97 98
	case unix.AF_PACKET:
		pp := (*unix.RawSockaddrLinklayer)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrLinklayer)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99 100 101 102 103 104 105 106 107 108
		sa.Protocol = pp.Protocol
		sa.Ifindex = int(pp.Ifindex)
		sa.Hatype = pp.Hatype
		sa.Pkttype = pp.Pkttype
		sa.Halen = pp.Halen
		for i := 0; i < len(sa.Addr); i++ {
			sa.Addr[i] = pp.Addr[i]
		}
		return sa, nil

Steven Allen's avatar
Steven Allen committed
109 110 111
	case unix.AF_UNIX:
		pp := (*unix.RawSockaddrUnix)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrUnix)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
		if pp.Path[0] == 0 {
			// "Abstract" Unix domain socket.
			// Rewrite leading NUL as @ for textual display.
			// (This is the standard convention.)
			// Not friendly to overwrite in place,
			// but the callers below don't care.
			pp.Path[0] = '@'
		}

		// Assume path ends at NUL.
		// This is not technically the Linux semantics for
		// abstract Unix domain sockets--they are supposed
		// to be uninterpreted fixed-size binary blobs--but
		// everyone uses this convention.
		n := 0
		for n < len(pp.Path) && pp.Path[n] != 0 {
			n++
		}
		bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
		sa.Name = string(bytes)
		return sa, nil

Steven Allen's avatar
Steven Allen committed
134 135 136
	case unix.AF_INET:
		pp := (*unix.RawSockaddrInet4)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrInet4)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
137 138 139 140 141 142 143
		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
		sa.Port = int(p[0])<<8 + int(p[1])
		for i := 0; i < len(sa.Addr); i++ {
			sa.Addr[i] = pp.Addr[i]
		}
		return sa, nil

Steven Allen's avatar
Steven Allen committed
144 145 146
	case unix.AF_INET6:
		pp := (*unix.RawSockaddrInet6)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrInet6)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
147 148 149 150 151 152 153 154
		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
		sa.Port = int(p[0])<<8 + int(p[1])
		sa.ZoneId = pp.Scope_id
		for i := 0; i < len(sa.Addr); i++ {
			sa.Addr[i] = pp.Addr[i]
		}
		return sa, nil
	}
Steven Allen's avatar
Steven Allen committed
155
	return nil, unix.EAFNOSUPPORT
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
156
}