forked from ti-mo/netfilter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
conn.go
124 lines (94 loc) · 2.83 KB
/
conn.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
122
123
124
package netfilter
import (
"sync"
"github.com/pkg/errors"
"github.com/mdlayher/netlink"
"golang.org/x/sys/unix"
)
// Conn represents a Netlink connection to the Netfilter subsystem.
type Conn struct {
conn *netlink.Conn
// Marks the Conn as being attached to one or more multicast groups,
// it can no longer be used for any queries for its remaining lifetime.
isMulticast bool
// Mutex to protect isMulticast
mu sync.RWMutex
}
// Dial opens a new Netlink connection to the Netfilter subsystem
// and returns it wrapped in a Conn structure.
func Dial(config *netlink.Config) (*Conn, error) {
var c Conn
var err error
c.conn, err = netlink.Dial(unix.NETLINK_NETFILTER, config)
if err != nil {
return nil, err
}
return &c, nil
}
// Close closes a Conn.
func (c *Conn) Close() error {
return c.conn.Close()
}
// Query sends a Netfilter message over Netlink and validates the response.
// The call will fail if the Conn is marked as Multicast. Any errors returned
// from the underlying Netlink layer are wrapped using pkg/errors.Wrap(). Use
// errors.Cause() to unwrap to compare to Errno.
func (c *Conn) Query(nlm netlink.Message) ([]netlink.Message, error) {
c.mu.RLock()
defer c.mu.RUnlock()
if c.isMulticast {
return nil, errConnIsMulticast
}
ret, err := c.conn.Execute(nlm)
if err != nil {
return nil, errors.Wrap(err, "netfilter query")
}
return ret, nil
}
// JoinGroups attaches the Netlink socket to one or more Netfilter multicast groups.
// Marks the Conn as Multicast, meaning it can no longer be used for any queries.
func (c *Conn) JoinGroups(groups []NetlinkGroup) error {
if len(groups) == 0 {
return errNoMulticastGroups
}
// Write lock
c.mu.Lock()
defer c.mu.Unlock()
for _, group := range groups {
err := c.conn.JoinGroup(uint32(group))
if err != nil {
return err
}
}
// Mark the Conn as being attached to a multicast group
c.isMulticast = true
return nil
}
// LeaveGroups detaches the Netlink socket from one or more Netfilter multicast groups.
// Does not remove the Multicast flag, open a separate Conn for making queries instead.
func (c *Conn) LeaveGroups(groups []NetlinkGroup) error {
// Write lock
c.mu.Lock()
defer c.mu.Unlock()
for _, group := range groups {
err := c.conn.LeaveGroup(uint32(group))
if err != nil {
return err
}
}
return nil
}
// Receive executes a blocking read on the underlying Netlink socket and returns a Message.
func (c *Conn) Receive() ([]netlink.Message, error) {
return c.conn.Receive()
}
// IsMulticast returns the Conn's Multicast flag. It is set by calling Listen().
func (c *Conn) IsMulticast() bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.isMulticast
}
// SetOption enables or disables a netlink socket option for the Conn.
func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
return c.conn.SetOption(option, enable)
}