message.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package netlink
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/mdlayher/netlink/nlenc"
  6. )
  7. // Flags which may apply to netlink attribute types when communicating with
  8. // certain netlink families.
  9. const (
  10. Nested uint16 = 0x8000
  11. NetByteOrder uint16 = 0x4000
  12. // attrTypeMask masks off Type bits used for the above flags.
  13. attrTypeMask uint16 = 0x3fff
  14. )
  15. // Various errors which may occur when attempting to marshal or unmarshal
  16. // a Message to and from its binary form.
  17. var (
  18. errIncorrectMessageLength = errors.New("netlink message header length incorrect")
  19. errShortMessage = errors.New("not enough data to create a netlink message")
  20. errUnalignedMessage = errors.New("input data is not properly aligned for netlink message")
  21. )
  22. // HeaderFlags specify flags which may be present in a Header.
  23. type HeaderFlags uint16
  24. const (
  25. // General netlink communication flags.
  26. // Request indicates a request to netlink.
  27. Request HeaderFlags = 1
  28. // Multi indicates a multi-part message, terminated by Done on the
  29. // last message.
  30. Multi HeaderFlags = 2
  31. // Acknowledge requests that netlink reply with an acknowledgement
  32. // using Error and, if needed, an error code.
  33. Acknowledge HeaderFlags = 4
  34. // Echo requests that netlink echo this request back to the sender.
  35. Echo HeaderFlags = 8
  36. // DumpInterrupted indicates that a dump was inconsistent due to a
  37. // sequence change.
  38. DumpInterrupted HeaderFlags = 16
  39. // DumpFiltered indicates that a dump was filtered as requested.
  40. DumpFiltered HeaderFlags = 32
  41. // Flags used to retrieve data from netlink.
  42. // Root requests that netlink return a complete table instead of a
  43. // single entry.
  44. Root HeaderFlags = 0x100
  45. // Match requests that netlink return a list of all matching entries.
  46. Match HeaderFlags = 0x200
  47. // Atomic requests that netlink send an atomic snapshot of its entries.
  48. // Requires CAP_NET_ADMIN or an effective UID of 0.
  49. Atomic HeaderFlags = 0x400
  50. // Dump requests that netlink return a complete list of all entries.
  51. Dump HeaderFlags = Root | Match
  52. // Flags used to create objects.
  53. // Replace indicates request replaces an existing matching object.
  54. Replace HeaderFlags = 0x100
  55. // Excl indicates request does not replace the object if it already exists.
  56. Excl HeaderFlags = 0x200
  57. // Create indicates request creates an object if it doesn't already exist.
  58. Create HeaderFlags = 0x400
  59. // Append indicates request adds to the end of the object list.
  60. Append HeaderFlags = 0x800
  61. )
  62. // String returns the string representation of a HeaderFlags.
  63. func (f HeaderFlags) String() string {
  64. names := []string{
  65. "request",
  66. "multi",
  67. "acknowledge",
  68. "echo",
  69. "dumpinterrupted",
  70. "dumpfiltered",
  71. }
  72. var s string
  73. left := uint(f)
  74. for i, name := range names {
  75. if f&(1<<uint(i)) != 0 {
  76. if s != "" {
  77. s += "|"
  78. }
  79. s += name
  80. left ^= (1 << uint(i))
  81. }
  82. }
  83. if s == "" && left == 0 {
  84. s = "0"
  85. }
  86. if left > 0 {
  87. if s != "" {
  88. s += "|"
  89. }
  90. s += fmt.Sprintf("%#x", left)
  91. }
  92. return s
  93. }
  94. // HeaderType specifies the type of a Header.
  95. type HeaderType uint16
  96. const (
  97. // Noop indicates that no action was taken.
  98. Noop HeaderType = 0x1
  99. // Error indicates an error code is present, which is also used to indicate
  100. // success when the code is 0.
  101. Error HeaderType = 0x2
  102. // Done indicates the end of a multi-part message.
  103. Done HeaderType = 0x3
  104. // Overrun indicates that data was lost from this message.
  105. Overrun HeaderType = 0x4
  106. )
  107. // String returns the string representation of a HeaderType.
  108. func (t HeaderType) String() string {
  109. switch t {
  110. case Noop:
  111. return "noop"
  112. case Error:
  113. return "error"
  114. case Done:
  115. return "done"
  116. case Overrun:
  117. return "overrun"
  118. default:
  119. return fmt.Sprintf("unknown(%d)", t)
  120. }
  121. }
  122. // NB: the memory layout of Header and Linux's syscall.NlMsgHdr must be
  123. // exactly the same. Cannot reorder, change data type, add, or remove fields.
  124. // Named types of the same size (e.g. HeaderFlags is a uint16) are okay.
  125. // A Header is a netlink header. A Header is sent and received with each
  126. // Message to indicate metadata regarding a Message.
  127. type Header struct {
  128. // Length of a Message, including this Header.
  129. Length uint32
  130. // Contents of a Message.
  131. Type HeaderType
  132. // Flags which may be used to modify a request or response.
  133. Flags HeaderFlags
  134. // The sequence number of a Message.
  135. Sequence uint32
  136. // The process ID of the sending process.
  137. PID uint32
  138. }
  139. // A Message is a netlink message. It contains a Header and an arbitrary
  140. // byte payload, which may be decoded using information from the Header.
  141. //
  142. // Data is often populated with netlink attributes. For easy encoding and
  143. // decoding of attributes, see the AttributeDecoder and AttributeEncoder types.
  144. type Message struct {
  145. Header Header
  146. Data []byte
  147. }
  148. // MarshalBinary marshals a Message into a byte slice.
  149. func (m Message) MarshalBinary() ([]byte, error) {
  150. ml := nlmsgAlign(int(m.Header.Length))
  151. if ml < nlmsgHeaderLen || ml != int(m.Header.Length) {
  152. return nil, errIncorrectMessageLength
  153. }
  154. b := make([]byte, ml)
  155. nlenc.PutUint32(b[0:4], m.Header.Length)
  156. nlenc.PutUint16(b[4:6], uint16(m.Header.Type))
  157. nlenc.PutUint16(b[6:8], uint16(m.Header.Flags))
  158. nlenc.PutUint32(b[8:12], m.Header.Sequence)
  159. nlenc.PutUint32(b[12:16], m.Header.PID)
  160. copy(b[16:], m.Data)
  161. return b, nil
  162. }
  163. // UnmarshalBinary unmarshals the contents of a byte slice into a Message.
  164. func (m *Message) UnmarshalBinary(b []byte) error {
  165. if len(b) < nlmsgHeaderLen {
  166. return errShortMessage
  167. }
  168. if len(b) != nlmsgAlign(len(b)) {
  169. return errUnalignedMessage
  170. }
  171. // Don't allow misleading length
  172. m.Header.Length = nlenc.Uint32(b[0:4])
  173. if int(m.Header.Length) != len(b) {
  174. return errShortMessage
  175. }
  176. m.Header.Type = HeaderType(nlenc.Uint16(b[4:6]))
  177. m.Header.Flags = HeaderFlags(nlenc.Uint16(b[6:8]))
  178. m.Header.Sequence = nlenc.Uint32(b[8:12])
  179. m.Header.PID = nlenc.Uint32(b[12:16])
  180. m.Data = b[16:]
  181. return nil
  182. }
  183. // checkMessage checks a single Message for netlink errors.
  184. func checkMessage(m Message) error {
  185. // NB: All non-nil errors returned from this function *must* be of type
  186. // OpError in order to maintain the appropriate contract with callers of
  187. // this package.
  188. const success = 0
  189. // Per libnl documentation, only messages that indicate type error can
  190. // contain error codes:
  191. // https://www.infradead.org/~tgr/libnl/doc/core.html#core_errmsg.
  192. //
  193. // However, at one point, this package checked both done and error for
  194. // error codes. Because there was no issue associated with the change,
  195. // it is unknown whether this change was correct or not. If you run into
  196. // a problem with your application because of this change, please file
  197. // an issue.
  198. if m.Header.Type != Error {
  199. return nil
  200. }
  201. if len(m.Data) < 4 {
  202. return newOpError("receive", errShortErrorMessage)
  203. }
  204. if c := nlenc.Int32(m.Data[0:4]); c != success {
  205. // Error code is a negative integer, convert it into an OS-specific raw
  206. // system call error, but do not wrap with os.NewSyscallError to signify
  207. // that this error was produced by a netlink message; not a system call.
  208. return newOpError("receive", newError(-1*int(c)))
  209. }
  210. return nil
  211. }