You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.5 KiB

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