target.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package expr
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "github.com/google/nftables/binaryutil"
  6. "github.com/google/nftables/xt"
  7. "github.com/mdlayher/netlink"
  8. "golang.org/x/sys/unix"
  9. )
  10. // See https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n28
  11. const XTablesExtensionNameMaxLen = 29
  12. // See https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n30
  13. type Target struct {
  14. Name string
  15. Rev uint32
  16. Info xt.InfoAny
  17. }
  18. func (e *Target) marshal(fam byte) ([]byte, error) {
  19. // Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n38
  20. name := e.Name
  21. // limit the extension name as (some) user-space tools do and leave room for
  22. // trailing \x00
  23. if len(name) >= /* sic! */ XTablesExtensionNameMaxLen {
  24. name = name[:XTablesExtensionNameMaxLen-1] // leave room for trailing \x00.
  25. }
  26. // Marshalling assumes that the correct Info type for the particular table
  27. // family and Match revision has been set.
  28. info, err := xt.Marshal(xt.TableFamily(fam), e.Rev, e.Info)
  29. if err != nil {
  30. return nil, err
  31. }
  32. attrs := []netlink.Attribute{
  33. {Type: unix.NFTA_TARGET_NAME, Data: []byte(name + "\x00")},
  34. {Type: unix.NFTA_TARGET_REV, Data: binaryutil.BigEndian.PutUint32(e.Rev)},
  35. {Type: unix.NFTA_TARGET_INFO, Data: info},
  36. }
  37. data, err := netlink.MarshalAttributes(attrs)
  38. if err != nil {
  39. return nil, err
  40. }
  41. return netlink.MarshalAttributes([]netlink.Attribute{
  42. {Type: unix.NFTA_EXPR_NAME, Data: []byte("target\x00")},
  43. {Type: unix.NLA_F_NESTED | unix.NFTA_EXPR_DATA, Data: data},
  44. })
  45. }
  46. func (e *Target) unmarshal(fam byte, data []byte) error {
  47. // Per https://git.netfilter.org/libnftnl/tree/src/expr/target.c?id=09456c720e9c00eecc08e41ac6b7c291b3821ee5#n65
  48. ad, err := netlink.NewAttributeDecoder(data)
  49. if err != nil {
  50. return err
  51. }
  52. var info []byte
  53. ad.ByteOrder = binary.BigEndian
  54. for ad.Next() {
  55. switch ad.Type() {
  56. case unix.NFTA_TARGET_NAME:
  57. // We are forgiving here, accepting any length and even missing terminating \x00.
  58. e.Name = string(bytes.TrimRight(ad.Bytes(), "\x00"))
  59. case unix.NFTA_TARGET_REV:
  60. e.Rev = ad.Uint32()
  61. case unix.NFTA_TARGET_INFO:
  62. info = ad.Bytes()
  63. }
  64. }
  65. if err = ad.Err(); err != nil {
  66. return err
  67. }
  68. e.Info, err = xt.Unmarshal(e.Name, xt.TableFamily(fam), e.Rev, info)
  69. return err
  70. }