nfqueue.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package nfqueue
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "log"
  6. "github.com/florianl/go-nfqueue/internal/unix"
  7. "github.com/mdlayher/netlink"
  8. "github.com/pkg/errors"
  9. )
  10. // devNull satisfies io.Writer, in case *log.Logger is not provided
  11. type devNull struct{}
  12. func (devNull) Write(p []byte) (int, error) {
  13. return 0, nil
  14. }
  15. // Close the connection to the netfilter queue subsystem
  16. func (nfqueue *Nfqueue) Close() error {
  17. return nfqueue.Con.Close()
  18. }
  19. // SetVerdictWithMark signals the kernel the next action and the mark for a specified package id
  20. func (nfqueue *Nfqueue) SetVerdictWithMark(id uint32, verdict, mark int) error {
  21. buf := make([]byte, 4)
  22. binary.BigEndian.PutUint32(buf, uint32(mark))
  23. attributes, err := netlink.MarshalAttributes([]netlink.Attribute{{
  24. Type: nfQaMark,
  25. Data: buf,
  26. }})
  27. if err != nil {
  28. return err
  29. }
  30. return nfqueue.setVerdict(id, verdict, false, attributes)
  31. }
  32. // SetVerdictModPacket signals the kernel the next action for an altered packet
  33. func (nfqueue *Nfqueue) SetVerdictModPacket(id uint32, verdict int, packet []byte) error {
  34. data, err := netlink.MarshalAttributes([]netlink.Attribute{{
  35. Type: nfQaPayload,
  36. Data: packet,
  37. }})
  38. if err != nil {
  39. return err
  40. }
  41. return nfqueue.setVerdict(id, verdict, false, data)
  42. }
  43. // SetVerdictModPacketWithMark signals the kernel the next action and mark for an altered packet
  44. func (nfqueue *Nfqueue) SetVerdictModPacketWithMark(id uint32, verdict, mark int, packet []byte) error {
  45. buf := make([]byte, 4)
  46. binary.BigEndian.PutUint32(buf, uint32(mark))
  47. data, err := netlink.MarshalAttributes([]netlink.Attribute{{
  48. Type: nfQaPayload,
  49. Data: packet,
  50. },
  51. {Type: nfQaMark,
  52. Data: buf}})
  53. if err != nil {
  54. return err
  55. }
  56. return nfqueue.setVerdict(id, verdict, false, data)
  57. }
  58. // SetVerdict signals the kernel the next action for a specified package id
  59. func (nfqueue *Nfqueue) SetVerdict(id uint32, verdict int) error {
  60. return nfqueue.setVerdict(id, verdict, false, []byte{})
  61. }
  62. // SetVerdictBatch signals the kernel the next action for a batch of packages till id
  63. func (nfqueue *Nfqueue) SetVerdictBatch(id uint32, verdict int) error {
  64. return nfqueue.setVerdict(id, verdict, true, []byte{})
  65. }
  66. // Register your own function as callback for a netfilter queue
  67. func (nfqueue *Nfqueue) Register(ctx context.Context, fn HookFunc) error {
  68. return nfqueue.RegisterWithErrorFunc(ctx, fn, func(err error) int {
  69. if opError, ok := err.(*netlink.OpError); ok {
  70. if opError.Timeout() || opError.Temporary() {
  71. return 0
  72. }
  73. }
  74. nfqueue.logger.Printf("Could not receive message: %v\n", err)
  75. return 1
  76. })
  77. }
  78. // RegisterWithErrorFunc is like Register but allows custom error handling
  79. // for errors encountered when reading from the underlying netlink socket.
  80. func (nfqueue *Nfqueue) RegisterWithErrorFunc(ctx context.Context, fn HookFunc, errfn ErrorFunc) error {
  81. // unbinding existing handler (if any)
  82. seq, err := nfqueue.setConfig(unix.AF_UNSPEC, 0, 0, []netlink.Attribute{
  83. {Type: nfQaCfgCmd, Data: []byte{nfUlnlCfgCmdPfUnbind, 0x0, 0x0, byte(nfqueue.family)}},
  84. })
  85. if err != nil {
  86. return errors.Wrapf(err, "Could not unbind existing handlers (if any)")
  87. }
  88. // binding to family
  89. _, err = nfqueue.setConfig(unix.AF_UNSPEC, seq, 0, []netlink.Attribute{
  90. {Type: nfQaCfgCmd, Data: []byte{nfUlnlCfgCmdPfBind, 0x0, 0x0, byte(nfqueue.family)}},
  91. })
  92. if err != nil {
  93. return errors.Wrapf(err, "Could not bind to family %d", nfqueue.family)
  94. }
  95. // binding to the requested queue
  96. _, err = nfqueue.setConfig(uint8(unix.AF_UNSPEC), seq, nfqueue.queue, []netlink.Attribute{
  97. {Type: nfQaCfgCmd, Data: []byte{nfUlnlCfgCmdBind, 0x0, 0x0, byte(nfqueue.family)}},
  98. })
  99. if err != nil {
  100. return errors.Wrapf(err, "Could not bind to requested queue %d", nfqueue.queue)
  101. }
  102. // set copy mode and buffer size
  103. data := append(nfqueue.maxPacketLen, nfqueue.copymode)
  104. _, err = nfqueue.setConfig(uint8(unix.AF_UNSPEC), seq, nfqueue.queue, []netlink.Attribute{
  105. {Type: nfQaCfgParams, Data: data},
  106. })
  107. if err != nil {
  108. return err
  109. }
  110. var attrs []netlink.Attribute
  111. if nfqueue.flags[0] != 0 || nfqueue.flags[1] != 0 || nfqueue.flags[2] != 0 || nfqueue.flags[3] != 0 {
  112. // set flags
  113. attrs = append(attrs, netlink.Attribute{Type: nfQaCfgFlags, Data: nfqueue.flags})
  114. attrs = append(attrs, netlink.Attribute{Type: nfQaCfgMask, Data: nfqueue.flags})
  115. }
  116. attrs = append(attrs, netlink.Attribute{Type: nfQaCfgQueueMaxLen, Data: nfqueue.maxQueueLen})
  117. _, err = nfqueue.setConfig(uint8(unix.AF_UNSPEC), seq, nfqueue.queue, attrs)
  118. if err != nil {
  119. return err
  120. }
  121. go nfqueue.socketCallback(ctx, fn, errfn, seq)
  122. return nil
  123. }
  124. // /include/uapi/linux/netfilter/nfnetlink.h:struct nfgenmsg{} res_id is Big Endian
  125. func putExtraHeader(familiy, version uint8, resid uint16) []byte {
  126. buf := make([]byte, 2)
  127. binary.BigEndian.PutUint16(buf, resid)
  128. return append([]byte{familiy, version}, buf...)
  129. }
  130. func (nfqueue *Nfqueue) setConfig(afFamily uint8, oseq uint32, resid uint16, attrs []netlink.Attribute) (uint32, error) {
  131. cmd, err := netlink.MarshalAttributes(attrs)
  132. if err != nil {
  133. return 0, err
  134. }
  135. data := putExtraHeader(afFamily, unix.NFNETLINK_V0, resid)
  136. data = append(data, cmd...)
  137. req := netlink.Message{
  138. Header: netlink.Header{
  139. Type: netlink.HeaderType((nfnlSubSysQueue << 8) | nfQnlMsgConfig),
  140. Flags: netlink.Request | netlink.Acknowledge,
  141. Sequence: oseq,
  142. },
  143. Data: data,
  144. }
  145. return nfqueue.execute(req)
  146. }
  147. func (nfqueue *Nfqueue) execute(req netlink.Message) (uint32, error) {
  148. var seq uint32
  149. reply, e := nfqueue.Con.Execute(req)
  150. if e != nil {
  151. return 0, e
  152. }
  153. if e := netlink.Validate(req, reply); e != nil {
  154. return 0, e
  155. }
  156. for _, msg := range reply {
  157. if seq != 0 {
  158. return 0, errors.Wrapf(ErrUnexpMsg, "Number of received messages: %d", len(reply))
  159. }
  160. seq = msg.Header.Sequence
  161. }
  162. return seq, nil
  163. }
  164. func parseMsg(log *log.Logger, msg netlink.Message) (Attribute, error) {
  165. a, err := extractAttributes(log, msg.Data)
  166. if err != nil {
  167. return a, err
  168. }
  169. return a, nil
  170. }