1
2
3 package sockets
4
5 import (
6 "errors"
7 "io"
8 "net"
9 "strconv"
10 "strings"
11
12 "golang.org/x/sys/unix"
13 )
14
15 var (
16 ErrInvalidIP = errors.New("invalid ip address")
17 ErrInvalidPort = errors.New("invalid port")
18 ErrInvalidSocketAddress = errors.New("address must be in the format of <ip>:<port>")
19 )
20
21 type Mode uint32
22
23 const (
24 KernelEvent Mode = 1
25
26 UdevEvent Mode = 2
27 )
28
29
30
31 func NewUEventNetlinkReader() (io.ReadCloser, int, error) {
32 fd, err := newUEventNetlinkSocket()
33 if err != nil {
34 return nil, 0, err
35 }
36
37 sockAddr := unix.SockaddrNetlink{
38 Family: unix.AF_NETLINK,
39 Groups: uint32(UdevEvent),
40 }
41
42 if err = unix.Bind(fd, &sockAddr); err != nil {
43 unix.Close(fd)
44 }
45 return &monitor{fd: fd}, fd, err
46 }
47
48
49 func NewUEventRemoteReader(address string) (io.ReadCloser, int, error) {
50 fd, err := newUEventRemoteSocket(address)
51 if err != nil {
52 return nil, 0, err
53 }
54 return &monitor{fd: fd}, fd, nil
55 }
56
57
58
59 func newUEventNetlinkSocket() (int, error) {
60 fd, err := unix.Socket(
61 unix.AF_NETLINK,
62 unix.SOCK_RAW,
63 unix.NETLINK_KOBJECT_UEVENT,
64 )
65 if err != nil {
66 return 0, err
67 }
68
69
70 unix.CloseOnExec(fd)
71 return fd, err
72 }
73
74
75
76 func newUEventRemoteSocket(address string) (int, error) {
77 fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, unix.IPPROTO_TCP)
78 if err != nil {
79 return 0, err
80 }
81
82 port, ip, err := parseAddress(address)
83 if err != nil {
84 return 0, err
85 }
86
87 addr := unix.SockaddrInet4{
88 Port: port,
89 Addr: ip,
90 }
91
92 if err := unix.Connect(fd, &addr); err != nil {
93 unix.Close(fd)
94 return 0, err
95 }
96
97 unix.CloseOnExec(fd)
98 return fd, nil
99 }
100
101
102
103 func parseAddress(address string) (port int, ip [4]byte, err error) {
104 addressSplit := strings.Split(address, ":")
105 if len(addressSplit) != 2 {
106 return 0, ip, ErrInvalidSocketAddress
107 }
108
109 port, err = strconv.Atoi(addressSplit[1])
110 if err != nil {
111 return 0, ip, ErrInvalidPort
112 }
113
114 ipAddr := net.ParseIP(addressSplit[0]).To4()
115 if len(ipAddr) != 4 {
116 return 0, ip, ErrInvalidIP
117 }
118 copy(ip[:], ipAddr)
119 return port, ip, nil
120 }
121
View as plain text