conn.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package genetlink
  2. import (
  3. "syscall"
  4. "time"
  5. "github.com/mdlayher/netlink"
  6. "golang.org/x/net/bpf"
  7. )
  8. // Protocol is the netlink protocol constant used to specify generic netlink.
  9. const Protocol = 0x10 // unix.NETLINK_GENERIC
  10. // A Conn is a generic netlink connection. A Conn can be used to send and
  11. // receive generic netlink messages to and from netlink.
  12. //
  13. // A Conn is safe for concurrent use, but to avoid contention in
  14. // high-throughput applications, the caller should almost certainly create a
  15. // pool of Conns and distribute them among workers.
  16. type Conn struct {
  17. // Operating system-specific netlink connection.
  18. c *netlink.Conn
  19. }
  20. // Dial dials a generic netlink connection. Config specifies optional
  21. // configuration for the underlying netlink connection. If config is
  22. // nil, a default configuration will be used.
  23. func Dial(config *netlink.Config) (*Conn, error) {
  24. c, err := netlink.Dial(Protocol, config)
  25. if err != nil {
  26. return nil, err
  27. }
  28. return NewConn(c), nil
  29. }
  30. // NewConn creates a Conn that wraps an existing *netlink.Conn for
  31. // generic netlink communications.
  32. //
  33. // NewConn is primarily useful for tests. Most applications should use
  34. // Dial instead.
  35. func NewConn(c *netlink.Conn) *Conn {
  36. return &Conn{c: c}
  37. }
  38. // Close closes the connection. Close will unblock any concurrent calls to
  39. // Receive which are waiting on a response from the kernel.
  40. func (c *Conn) Close() error {
  41. return c.c.Close()
  42. }
  43. // GetFamily retrieves a generic netlink family with the specified name.
  44. //
  45. // If the family does not exist, the error value can be checked using
  46. // netlink.IsNotExist.
  47. func (c *Conn) GetFamily(name string) (Family, error) {
  48. return c.getFamily(name)
  49. }
  50. // ListFamilies retrieves all registered generic netlink families.
  51. func (c *Conn) ListFamilies() ([]Family, error) {
  52. return c.listFamilies()
  53. }
  54. // JoinGroup joins a netlink multicast group by its ID.
  55. func (c *Conn) JoinGroup(group uint32) error {
  56. return c.c.JoinGroup(group)
  57. }
  58. // LeaveGroup leaves a netlink multicast group by its ID.
  59. func (c *Conn) LeaveGroup(group uint32) error {
  60. return c.c.LeaveGroup(group)
  61. }
  62. // SetBPF attaches an assembled BPF program to a Conn.
  63. func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
  64. return c.c.SetBPF(filter)
  65. }
  66. // RemoveBPF removes a BPF filter from a Conn.
  67. func (c *Conn) RemoveBPF() error {
  68. return c.c.RemoveBPF()
  69. }
  70. // SetOption enables or disables a netlink socket option for the Conn.
  71. func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
  72. return c.c.SetOption(option, enable)
  73. }
  74. // SetReadBuffer sets the size of the operating system's receive buffer
  75. // associated with the Conn.
  76. func (c *Conn) SetReadBuffer(bytes int) error {
  77. return c.c.SetReadBuffer(bytes)
  78. }
  79. // SetWriteBuffer sets the size of the operating system's transmit buffer
  80. // associated with the Conn.
  81. func (c *Conn) SetWriteBuffer(bytes int) error {
  82. return c.c.SetWriteBuffer(bytes)
  83. }
  84. // SyscallConn returns a raw network connection. This implements the
  85. // syscall.Conn interface.
  86. //
  87. // On Go 1.12+, all methods of the returned syscall.RawConn are supported and
  88. // the Conn is integrated with the runtime network poller. On versions of Go
  89. // prior to Go 1.12, only the Control method of the returned syscall.RawConn
  90. // is implemented.
  91. //
  92. // SyscallConn is intended for advanced use cases, such as getting and setting
  93. // arbitrary socket options using the netlink socket's file descriptor.
  94. //
  95. // Once invoked, it is the caller's responsibility to ensure that operations
  96. // performed using Conn and the syscall.RawConn do not conflict with
  97. // each other.
  98. func (c *Conn) SyscallConn() (syscall.RawConn, error) {
  99. return c.c.SyscallConn()
  100. }
  101. // SetDeadline sets the read and write deadlines associated with the connection.
  102. //
  103. // Deadline functionality is only supported on Go 1.12+. Calling this function
  104. // on older versions of Go will result in an error.
  105. func (c *Conn) SetDeadline(t time.Time) error {
  106. return c.c.SetDeadline(t)
  107. }
  108. // SetReadDeadline sets the read deadline associated with the connection.
  109. //
  110. // Deadline functionality is only supported on Go 1.12+. Calling this function
  111. // on older versions of Go will result in an error.
  112. func (c *Conn) SetReadDeadline(t time.Time) error {
  113. return c.c.SetReadDeadline(t)
  114. }
  115. // SetWriteDeadline sets the write deadline associated with the connection.
  116. //
  117. // Deadline functionality is only supported on Go 1.12+. Calling this function
  118. // on older versions of Go will result in an error.
  119. func (c *Conn) SetWriteDeadline(t time.Time) error {
  120. return c.c.SetWriteDeadline(t)
  121. }
  122. // Send sends a single Message to netlink, wrapping it in a netlink.Message
  123. // using the specified generic netlink family and flags. On success, Send
  124. // returns a copy of the netlink.Message with all parameters populated, for
  125. // later validation.
  126. func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
  127. nm, err := packMessage(m, family, flags)
  128. if err != nil {
  129. return netlink.Message{}, err
  130. }
  131. reqnm, err := c.c.Send(nm)
  132. if err != nil {
  133. return netlink.Message{}, err
  134. }
  135. return reqnm, nil
  136. }
  137. // Receive receives one or more Messages from netlink. The netlink.Messages
  138. // used to wrap each Message are available for later validation.
  139. func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
  140. msgs, err := c.c.Receive()
  141. if err != nil {
  142. return nil, nil, err
  143. }
  144. gmsgs, err := unpackMessages(msgs)
  145. if err != nil {
  146. return nil, nil, err
  147. }
  148. return gmsgs, msgs, nil
  149. }
  150. // Execute sends a single Message to netlink using Send, receives one or more
  151. // replies using Receive, and then checks the validity of the replies against
  152. // the request using netlink.Validate.
  153. //
  154. // Execute acquires a lock for the duration of the function call which blocks
  155. // concurrent calls to Send and Receive, in order to ensure consistency between
  156. // generic netlink request/reply messages.
  157. //
  158. // See the documentation of Send, Receive, and netlink.Validate for details
  159. // about each function.
  160. func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
  161. nm, err := packMessage(m, family, flags)
  162. if err != nil {
  163. return nil, err
  164. }
  165. // Locking behavior handled by netlink.Conn.Execute.
  166. msgs, err := c.c.Execute(nm)
  167. if err != nil {
  168. return nil, err
  169. }
  170. return unpackMessages(msgs)
  171. }
  172. // packMessage packs a generic netlink Message into a netlink.Message with the
  173. // appropriate generic netlink family and netlink flags.
  174. func packMessage(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
  175. nm := netlink.Message{
  176. Header: netlink.Header{
  177. Type: netlink.HeaderType(family),
  178. Flags: flags,
  179. },
  180. }
  181. mb, err := m.MarshalBinary()
  182. if err != nil {
  183. return netlink.Message{}, err
  184. }
  185. nm.Data = mb
  186. return nm, nil
  187. }
  188. // unpackMessages unpacks generic netlink Messages from a slice of netlink.Messages.
  189. func unpackMessages(msgs []netlink.Message) ([]Message, error) {
  190. gmsgs := make([]Message, 0, len(msgs))
  191. for _, nm := range msgs {
  192. var gm Message
  193. if err := (&gm).UnmarshalBinary(nm.Data); err != nil {
  194. return nil, err
  195. }
  196. gmsgs = append(gmsgs, gm)
  197. }
  198. return gmsgs, nil
  199. }