sockaddr_linux.go 4.1 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
	"syscall"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5
	"unsafe"
Steven Allen's avatar
Steven Allen committed
6 7

	"golang.org/x/sys/unix"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8 9
)

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15
	switch sa := sa.(type) {
Steven Allen's avatar
Steven Allen committed
16
	case *unix.SockaddrInet4:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17
		if sa.Port < 0 || sa.Port > 0xFFFF {
Steven Allen's avatar
Steven Allen committed
18
			return nil, 0, syscall.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19
		}
Steven Allen's avatar
Steven Allen committed
20 21
		var raw unix.RawSockaddrInet4
		raw.Family = unix.AF_INET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
22 23 24 25 26 27
		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
28
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrInet4, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29

Steven Allen's avatar
Steven Allen committed
30
	case *unix.SockaddrInet6:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31
		if sa.Port < 0 || sa.Port > 0xFFFF {
Steven Allen's avatar
Steven Allen committed
32
			return nil, 0, syscall.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33
		}
Steven Allen's avatar
Steven Allen committed
34 35
		var raw unix.RawSockaddrInet6
		raw.Family = unix.AF_INET6
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36 37 38 39 40 41 42
		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
43
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrInet6, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
44

Steven Allen's avatar
Steven Allen committed
45
	case *unix.SockaddrUnix:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46 47
		name := sa.Name
		n := len(name)
Steven Allen's avatar
Steven Allen committed
48
		var raw unix.RawSockaddrUnix
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
49
		if n >= len(raw.Path) {
Steven Allen's avatar
Steven Allen committed
50
			return nil, 0, syscall.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51
		}
Steven Allen's avatar
Steven Allen committed
52
		raw.Family = unix.AF_UNIX
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
53 54 55 56 57 58 59 60 61 62 63 64 65
		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
66
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), sl, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
67

Steven Allen's avatar
Steven Allen committed
68
	case *unix.SockaddrLinklayer:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69
		if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
Steven Allen's avatar
Steven Allen committed
70
			return nil, 0, syscall.EINVAL
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71
		}
Steven Allen's avatar
Steven Allen committed
72 73
		var raw unix.RawSockaddrLinklayer
		raw.Family = unix.AF_PACKET
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
74 75 76 77 78 79 80 81
		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
82
		return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrLinklayer, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83
	}
Steven Allen's avatar
Steven Allen committed
84
	return nil, 0, syscall.EAFNOSUPPORT
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85 86
}

Steven Allen's avatar
Steven Allen committed
87
func anyToSockaddr(rsa *unix.RawSockaddrAny) (unix.Sockaddr, error) {
Steven Allen's avatar
Steven Allen committed
88 89 90 91
	if rsa == nil {
		return nil, syscall.EINVAL
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92
	switch rsa.Addr.Family {
Steven Allen's avatar
Steven Allen committed
93 94 95
	case unix.AF_NETLINK:
		pp := (*unix.RawSockaddrNetlink)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrNetlink)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96 97 98 99 100 101
		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
102 103 104
	case unix.AF_PACKET:
		pp := (*unix.RawSockaddrLinklayer)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrLinklayer)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
105 106 107 108 109 110 111 112 113 114
		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
115 116 117
	case unix.AF_UNIX:
		pp := (*unix.RawSockaddrUnix)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrUnix)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
		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
140 141 142
	case unix.AF_INET:
		pp := (*unix.RawSockaddrInet4)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrInet4)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143 144 145 146 147 148 149
		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
150 151 152
	case unix.AF_INET6:
		pp := (*unix.RawSockaddrInet6)(unsafe.Pointer(rsa))
		sa := new(unix.SockaddrInet6)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153 154 155 156 157 158 159 160
		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
161
	return nil, syscall.EAFNOSUPPORT
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
162
}