forked from remyoudompheng/go-netlink
-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket.go
121 lines (106 loc) · 2.67 KB
/
socket.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package netlink
import (
"bufio"
"fmt"
"net"
"os"
"syscall"
)
var netlinkFamilies = map[uint16]string{
syscall.NETLINK_GENERIC: "generic",
syscall.NETLINK_ROUTE: "route",
syscall.NETLINK_CONNECTOR: "conn",
}
type NetlinkConn struct {
fd int
family uint16
addr syscall.SockaddrNetlink
rbuf *bufio.Reader
}
type NetlinkAddr struct {
family uint16
}
func (addr NetlinkAddr) Network() string {
return netlinkFamilies[addr.family]
}
func (addr NetlinkAddr) String() string {
return "netlink:" + netlinkFamilies[addr.family]
}
func DialNetlink(family string, mask uint32) (conn *NetlinkConn, er error) {
var (
fd int
errno error
familyno uint16
)
switch family {
case "generic":
familyno = syscall.NETLINK_GENERIC
case "route":
familyno = syscall.NETLINK_ROUTE
case "conn":
familyno = syscall.NETLINK_CONNECTOR
default:
fd = 0
er = fmt.Errorf("Invalid netlink family: %s", family)
return nil, er
}
// Create socket
fd, errno = syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, int(familyno))
if errno != nil {
er = os.NewSyscallError("socket", errno)
return nil, fmt.Errorf("Cannot create netlink socket: %s", er)
}
conn = new(NetlinkConn)
conn.fd = fd
conn.family = familyno
conn.addr.Family = syscall.AF_NETLINK
conn.addr.Pid = 0
conn.addr.Groups = mask
conn.rbuf = bufio.NewReader(conn)
errno = syscall.Bind(fd, &conn.addr)
if errno != nil {
er = os.NewSyscallError("bind", errno)
syscall.Close(fd)
return nil, fmt.Errorf("Cannot bind netlink socket: %s", er)
}
return conn, nil
}
// net.Conn interface implementation
func (s NetlinkConn) Read(b []byte) (n int, err error) {
nr, _, e := syscall.Recvfrom(s.fd, b, 0)
return nr, os.NewSyscallError("recvfrom", e)
}
func (s NetlinkConn) Write(b []byte) (n int, err error) {
e := syscall.Sendto(s.fd, b, 0, &s.addr)
return len(b), os.NewSyscallError("sendto", e)
}
func (s NetlinkConn) Close() error {
e := syscall.Close(s.fd)
return os.NewSyscallError("close", e)
}
func (s NetlinkConn) LocalAddr() net.Addr {
return NetlinkAddr{s.family}
}
func (s NetlinkConn) RemoteAddr() net.Addr {
return NetlinkAddr{s.family}
}
// from <linux/socket.h>
const (
SOL_NETLINK = 270
)
// Joins a multicast group
func (s NetlinkConn) JoinGroup(grp int) error {
errno := syscall.SetsockoptInt(s.fd, SOL_NETLINK, syscall.NETLINK_ADD_MEMBERSHIP, grp)
if errno != nil {
return os.NewSyscallError("setsockopt", errno)
}
return nil
}
// Leaves a multicast group
func (s NetlinkConn) LeaveGroup(grp int) error {
errno := syscall.SetsockoptInt(s.fd, SOL_NETLINK, syscall.NETLINK_DROP_MEMBERSHIP, grp)
if errno != nil {
return os.NewSyscallError("setsockopt", errno)
}
return nil
}