ipset_linux.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. package netlink
  2. import (
  3. "encoding/binary"
  4. "log"
  5. "net"
  6. "syscall"
  7. "github.com/vishvananda/netlink/nl"
  8. "golang.org/x/sys/unix"
  9. )
  10. // IPSetEntry is used for adding, updating, retreiving and deleting entries
  11. type IPSetEntry struct {
  12. Comment string
  13. MAC net.HardwareAddr
  14. IP net.IP
  15. CIDR uint8
  16. Timeout *uint32
  17. Packets *uint64
  18. Bytes *uint64
  19. Protocol *uint8
  20. Port *uint16
  21. IP2 net.IP
  22. CIDR2 uint8
  23. IFace string
  24. Mark *uint32
  25. Replace bool // replace existing entry
  26. }
  27. // IPSetResult is the result of a dump request for a set
  28. type IPSetResult struct {
  29. Nfgenmsg *nl.Nfgenmsg
  30. Protocol uint8
  31. ProtocolMinVersion uint8
  32. Revision uint8
  33. Family uint8
  34. Flags uint8
  35. SetName string
  36. TypeName string
  37. Comment string
  38. MarkMask uint32
  39. IPFrom net.IP
  40. IPTo net.IP
  41. PortFrom uint16
  42. PortTo uint16
  43. HashSize uint32
  44. NumEntries uint32
  45. MaxElements uint32
  46. References uint32
  47. SizeInMemory uint32
  48. CadtFlags uint32
  49. Timeout *uint32
  50. LineNo uint32
  51. Entries []IPSetEntry
  52. }
  53. // IpsetCreateOptions is the options struct for creating a new ipset
  54. type IpsetCreateOptions struct {
  55. Replace bool // replace existing ipset
  56. Timeout *uint32
  57. Counters bool
  58. Comments bool
  59. Skbinfo bool
  60. Family uint8
  61. Revision uint8
  62. IPFrom net.IP
  63. IPTo net.IP
  64. PortFrom uint16
  65. PortTo uint16
  66. MaxElements uint32
  67. }
  68. // IpsetProtocol returns the ipset protocol version from the kernel
  69. func IpsetProtocol() (uint8, uint8, error) {
  70. return pkgHandle.IpsetProtocol()
  71. }
  72. // IpsetCreate creates a new ipset
  73. func IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  74. return pkgHandle.IpsetCreate(setname, typename, options)
  75. }
  76. // IpsetDestroy destroys an existing ipset
  77. func IpsetDestroy(setname string) error {
  78. return pkgHandle.IpsetDestroy(setname)
  79. }
  80. // IpsetFlush flushes an existing ipset
  81. func IpsetFlush(setname string) error {
  82. return pkgHandle.IpsetFlush(setname)
  83. }
  84. // IpsetSwap swaps two ipsets.
  85. func IpsetSwap(setname, othersetname string) error {
  86. return pkgHandle.IpsetSwap(setname, othersetname)
  87. }
  88. // IpsetList dumps an specific ipset.
  89. func IpsetList(setname string) (*IPSetResult, error) {
  90. return pkgHandle.IpsetList(setname)
  91. }
  92. // IpsetListAll dumps all ipsets.
  93. func IpsetListAll() ([]IPSetResult, error) {
  94. return pkgHandle.IpsetListAll()
  95. }
  96. // IpsetAdd adds an entry to an existing ipset.
  97. func IpsetAdd(setname string, entry *IPSetEntry) error {
  98. return pkgHandle.IpsetAdd(setname, entry)
  99. }
  100. // IpsetDel deletes an entry from an existing ipset.
  101. func IpsetDel(setname string, entry *IPSetEntry) error {
  102. return pkgHandle.IpsetDel(setname, entry)
  103. }
  104. // IpsetTest tests whether an entry is in a set or not.
  105. func IpsetTest(setname string, entry *IPSetEntry) (bool, error) {
  106. return pkgHandle.IpsetTest(setname, entry)
  107. }
  108. func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
  109. req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
  110. msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
  111. if err != nil {
  112. return 0, 0, err
  113. }
  114. response := ipsetUnserialize(msgs)
  115. return response.Protocol, response.ProtocolMinVersion, nil
  116. }
  117. func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  118. req := h.newIpsetRequest(nl.IPSET_CMD_CREATE)
  119. if !options.Replace {
  120. req.Flags |= unix.NLM_F_EXCL
  121. }
  122. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  123. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
  124. cadtFlags := optionsToBitflag(options)
  125. revision := options.Revision
  126. if revision == 0 {
  127. revision = getIpsetDefaultRevision(typename, cadtFlags)
  128. }
  129. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision)))
  130. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  131. var family uint8
  132. switch typename {
  133. case "hash:mac":
  134. case "bitmap:port":
  135. buf := make([]byte, 4)
  136. binary.BigEndian.PutUint16(buf, options.PortFrom)
  137. binary.BigEndian.PutUint16(buf[2:], options.PortTo)
  138. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_FROM|int(nl.NLA_F_NET_BYTEORDER), buf[:2]))
  139. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_TO|int(nl.NLA_F_NET_BYTEORDER), buf[2:]))
  140. default:
  141. family = options.Family
  142. if family == 0 {
  143. family = unix.AF_INET
  144. }
  145. }
  146. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(family)))
  147. if options.MaxElements != 0 {
  148. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER, Value: options.MaxElements})
  149. }
  150. if timeout := options.Timeout; timeout != nil {
  151. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
  152. }
  153. if cadtFlags != 0 {
  154. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
  155. }
  156. req.AddData(data)
  157. _, err := ipsetExecute(req)
  158. return err
  159. }
  160. func (h *Handle) IpsetDestroy(setname string) error {
  161. req := h.newIpsetRequest(nl.IPSET_CMD_DESTROY)
  162. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  163. _, err := ipsetExecute(req)
  164. return err
  165. }
  166. func (h *Handle) IpsetFlush(setname string) error {
  167. req := h.newIpsetRequest(nl.IPSET_CMD_FLUSH)
  168. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  169. _, err := ipsetExecute(req)
  170. return err
  171. }
  172. func (h *Handle) IpsetSwap(setname, othersetname string) error {
  173. req := h.newIpsetRequest(nl.IPSET_CMD_SWAP)
  174. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  175. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(othersetname)))
  176. _, err := ipsetExecute(req)
  177. return err
  178. }
  179. func (h *Handle) IpsetList(name string) (*IPSetResult, error) {
  180. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  181. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(name)))
  182. msgs, err := ipsetExecute(req)
  183. if err != nil {
  184. return nil, err
  185. }
  186. result := ipsetUnserialize(msgs)
  187. return &result, nil
  188. }
  189. func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
  190. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  191. msgs, err := ipsetExecute(req)
  192. if err != nil {
  193. return nil, err
  194. }
  195. result := make([]IPSetResult, len(msgs))
  196. for i, msg := range msgs {
  197. result[i].unserialize(msg)
  198. }
  199. return result, nil
  200. }
  201. // IpsetAdd adds an entry to an existing ipset.
  202. func (h *Handle) IpsetAdd(setname string, entry *IPSetEntry) error {
  203. return h.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
  204. }
  205. // IpsetDel deletes an entry from an existing ipset.
  206. func (h *Handle) IpsetDel(setname string, entry *IPSetEntry) error {
  207. return h.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
  208. }
  209. func encodeIP(ip net.IP) (*nl.RtAttr, error) {
  210. typ := int(nl.NLA_F_NET_BYTEORDER)
  211. if ip4 := ip.To4(); ip4 != nil {
  212. typ |= nl.IPSET_ATTR_IPADDR_IPV4
  213. ip = ip4
  214. } else {
  215. typ |= nl.IPSET_ATTR_IPADDR_IPV6
  216. }
  217. return nl.NewRtAttr(typ, ip), nil
  218. }
  219. func buildEntryData(entry *IPSetEntry) (*nl.RtAttr, error) {
  220. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  221. if entry.Comment != "" {
  222. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
  223. }
  224. if entry.Timeout != nil {
  225. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
  226. }
  227. if entry.IP != nil {
  228. nestedData, err := encodeIP(entry.IP)
  229. if err != nil {
  230. return nil, err
  231. }
  232. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  233. }
  234. if entry.MAC != nil {
  235. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC))
  236. }
  237. if entry.CIDR != 0 {
  238. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR, nl.Uint8Attr(entry.CIDR)))
  239. }
  240. if entry.IP2 != nil {
  241. nestedData, err := encodeIP(entry.IP2)
  242. if err != nil {
  243. return nil, err
  244. }
  245. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP2|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  246. }
  247. if entry.CIDR2 != 0 {
  248. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR2, nl.Uint8Attr(entry.CIDR2)))
  249. }
  250. if entry.Port != nil {
  251. if entry.Protocol == nil {
  252. // use tcp protocol as default
  253. val := uint8(unix.IPPROTO_TCP)
  254. entry.Protocol = &val
  255. }
  256. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PROTO, nl.Uint8Attr(*entry.Protocol)))
  257. buf := make([]byte, 2)
  258. binary.BigEndian.PutUint16(buf, *entry.Port)
  259. data.AddChild(nl.NewRtAttr(int(nl.IPSET_ATTR_PORT|nl.NLA_F_NET_BYTEORDER), buf))
  260. }
  261. if entry.IFace != "" {
  262. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IFACE, nl.ZeroTerminated(entry.IFace)))
  263. }
  264. if entry.Mark != nil {
  265. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER, Value: *entry.Mark})
  266. }
  267. return data, nil
  268. }
  269. func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
  270. req := h.newIpsetRequest(nlCmd)
  271. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  272. if !entry.Replace {
  273. req.Flags |= unix.NLM_F_EXCL
  274. }
  275. data, err := buildEntryData(entry)
  276. if err != nil {
  277. return err
  278. }
  279. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
  280. req.AddData(data)
  281. _, err = ipsetExecute(req)
  282. return err
  283. }
  284. func (h *Handle) IpsetTest(setname string, entry *IPSetEntry) (bool, error) {
  285. req := h.newIpsetRequest(nl.IPSET_CMD_TEST)
  286. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  287. if !entry.Replace {
  288. req.Flags |= unix.NLM_F_EXCL
  289. }
  290. data, err := buildEntryData(entry)
  291. if err != nil {
  292. return false, err
  293. }
  294. req.AddData(data)
  295. _, err = ipsetExecute(req)
  296. if err != nil {
  297. if err == nl.IPSetError(nl.IPSET_ERR_EXIST) {
  298. // not exist
  299. return false, nil
  300. }
  301. return false, err
  302. }
  303. return true, nil
  304. }
  305. func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
  306. req := h.newNetlinkRequest(cmd|(unix.NFNL_SUBSYS_IPSET<<8), nl.GetIpsetFlags(cmd))
  307. // Add the netfilter header
  308. msg := &nl.Nfgenmsg{
  309. NfgenFamily: uint8(unix.AF_NETLINK),
  310. Version: nl.NFNETLINK_V0,
  311. ResId: 0,
  312. }
  313. req.AddData(msg)
  314. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_PROTOCOL, nl.Uint8Attr(nl.IPSET_PROTOCOL)))
  315. return req
  316. }
  317. // NOTE: This can't just take typename into account, it also has to take desired
  318. // feature support into account, on a per-set-type basis, to return the correct revision, see e.g.
  319. // https://github.com/Olipro/ipset/blob/9f145b49100104d6570fe5c31a5236816ebb4f8f/kernel/net/netfilter/ipset/ip_set_hash_ipport.c#L30
  320. //
  321. // This means that whenever a new "type" of ipset is added, returning the "correct" default revision
  322. // requires adding a new case here for that type, and consulting the ipset C code to figure out the correct
  323. // combination of type name, feature bit flags, and revision ranges.
  324. //
  325. // Care should be taken as some types share the same revision ranges for the same features, and others do not.
  326. // When in doubt, mimic the C code.
  327. func getIpsetDefaultRevision(typename string, featureFlags uint32) uint8 {
  328. switch typename {
  329. case "hash:ip,port",
  330. "hash:ip,port,ip":
  331. // Taken from
  332. // - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
  333. // - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c
  334. if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
  335. return 5
  336. }
  337. if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
  338. return 4
  339. }
  340. if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
  341. return 3
  342. }
  343. if (featureFlags & nl.IPSET_FLAG_WITH_COUNTERS) != 0 {
  344. return 2
  345. }
  346. // the min revision this library supports for this type
  347. return 1
  348. case "hash:ip,port,net",
  349. "hash:net,port":
  350. // Taken from
  351. // - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
  352. // - ipset/kernel/net/netfilter/ipset/ip_set_hash_netport.c
  353. if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
  354. return 7
  355. }
  356. if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
  357. return 6
  358. }
  359. if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
  360. return 5
  361. }
  362. if (featureFlags & nl.IPSET_FLAG_WITH_COUNTERS) != 0 {
  363. return 4
  364. }
  365. if (featureFlags & nl.IPSET_FLAG_NOMATCH) != 0 {
  366. return 3
  367. }
  368. // the min revision this library supports for this type
  369. return 2
  370. case "hash:ip":
  371. // Taken from
  372. // - ipset/kernel/net/netfilter/ipset/ip_set_hash_ip.c
  373. if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
  374. return 4
  375. }
  376. if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
  377. return 3
  378. }
  379. if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
  380. return 2
  381. }
  382. // the min revision this library supports for this type
  383. return 1
  384. }
  385. // can't map the correct revision for this type.
  386. return 0
  387. }
  388. func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
  389. msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
  390. if err != nil {
  391. if errno := int(err.(syscall.Errno)); errno >= nl.IPSET_ERR_PRIVATE {
  392. err = nl.IPSetError(uintptr(errno))
  393. }
  394. }
  395. return
  396. }
  397. func ipsetUnserialize(msgs [][]byte) (result IPSetResult) {
  398. for _, msg := range msgs {
  399. result.unserialize(msg)
  400. }
  401. return result
  402. }
  403. func (result *IPSetResult) unserialize(msg []byte) {
  404. result.Nfgenmsg = nl.DeserializeNfgenmsg(msg)
  405. for attr := range nl.ParseAttributes(msg[4:]) {
  406. switch attr.Type {
  407. case nl.IPSET_ATTR_PROTOCOL:
  408. result.Protocol = attr.Value[0]
  409. case nl.IPSET_ATTR_SETNAME:
  410. result.SetName = nl.BytesToString(attr.Value)
  411. case nl.IPSET_ATTR_COMMENT:
  412. result.Comment = nl.BytesToString(attr.Value)
  413. case nl.IPSET_ATTR_TYPENAME:
  414. result.TypeName = nl.BytesToString(attr.Value)
  415. case nl.IPSET_ATTR_REVISION:
  416. result.Revision = attr.Value[0]
  417. case nl.IPSET_ATTR_FAMILY:
  418. result.Family = attr.Value[0]
  419. case nl.IPSET_ATTR_FLAGS:
  420. result.Flags = attr.Value[0]
  421. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  422. result.parseAttrData(attr.Value)
  423. case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
  424. result.parseAttrADT(attr.Value)
  425. case nl.IPSET_ATTR_PROTOCOL_MIN:
  426. result.ProtocolMinVersion = attr.Value[0]
  427. case nl.IPSET_ATTR_MARKMASK:
  428. result.MarkMask = attr.Uint32()
  429. default:
  430. log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  431. }
  432. }
  433. }
  434. func (result *IPSetResult) parseAttrData(data []byte) {
  435. for attr := range nl.ParseAttributes(data) {
  436. switch attr.Type {
  437. case nl.IPSET_ATTR_HASHSIZE | nl.NLA_F_NET_BYTEORDER:
  438. result.HashSize = attr.Uint32()
  439. case nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER:
  440. result.MaxElements = attr.Uint32()
  441. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  442. val := attr.Uint32()
  443. result.Timeout = &val
  444. case nl.IPSET_ATTR_ELEMENTS | nl.NLA_F_NET_BYTEORDER:
  445. result.NumEntries = attr.Uint32()
  446. case nl.IPSET_ATTR_REFERENCES | nl.NLA_F_NET_BYTEORDER:
  447. result.References = attr.Uint32()
  448. case nl.IPSET_ATTR_MEMSIZE | nl.NLA_F_NET_BYTEORDER:
  449. result.SizeInMemory = attr.Uint32()
  450. case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
  451. result.CadtFlags = attr.Uint32()
  452. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  453. for nested := range nl.ParseAttributes(attr.Value) {
  454. switch nested.Type {
  455. case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
  456. result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
  457. case nl.IPSET_ATTR_IP:
  458. result.IPFrom = nested.Value
  459. default:
  460. log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
  461. }
  462. }
  463. case nl.IPSET_ATTR_IP_TO | nl.NLA_F_NESTED:
  464. for nested := range nl.ParseAttributes(attr.Value) {
  465. switch nested.Type {
  466. case nl.IPSET_ATTR_IP:
  467. result.IPTo = nested.Value
  468. default:
  469. log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
  470. }
  471. }
  472. case nl.IPSET_ATTR_PORT_FROM | nl.NLA_F_NET_BYTEORDER:
  473. result.PortFrom = networkOrder.Uint16(attr.Value)
  474. case nl.IPSET_ATTR_PORT_TO | nl.NLA_F_NET_BYTEORDER:
  475. result.PortTo = networkOrder.Uint16(attr.Value)
  476. case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
  477. result.LineNo = attr.Uint32()
  478. case nl.IPSET_ATTR_COMMENT:
  479. result.Comment = nl.BytesToString(attr.Value)
  480. case nl.IPSET_ATTR_MARKMASK:
  481. result.MarkMask = attr.Uint32()
  482. default:
  483. log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  484. }
  485. }
  486. }
  487. func (result *IPSetResult) parseAttrADT(data []byte) {
  488. for attr := range nl.ParseAttributes(data) {
  489. switch attr.Type {
  490. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  491. result.Entries = append(result.Entries, parseIPSetEntry(attr.Value))
  492. default:
  493. log.Printf("unknown ADT attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  494. }
  495. }
  496. }
  497. func parseIPSetEntry(data []byte) (entry IPSetEntry) {
  498. for attr := range nl.ParseAttributes(data) {
  499. switch attr.Type {
  500. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  501. val := attr.Uint32()
  502. entry.Timeout = &val
  503. case nl.IPSET_ATTR_BYTES | nl.NLA_F_NET_BYTEORDER:
  504. val := attr.Uint64()
  505. entry.Bytes = &val
  506. case nl.IPSET_ATTR_PACKETS | nl.NLA_F_NET_BYTEORDER:
  507. val := attr.Uint64()
  508. entry.Packets = &val
  509. case nl.IPSET_ATTR_ETHER:
  510. entry.MAC = net.HardwareAddr(attr.Value)
  511. case nl.IPSET_ATTR_IP:
  512. entry.IP = net.IP(attr.Value)
  513. case nl.IPSET_ATTR_COMMENT:
  514. entry.Comment = nl.BytesToString(attr.Value)
  515. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  516. for attr := range nl.ParseAttributes(attr.Value) {
  517. switch attr.Type {
  518. case nl.IPSET_ATTR_IPADDR_IPV4, nl.IPSET_ATTR_IPADDR_IPV6:
  519. entry.IP = net.IP(attr.Value)
  520. default:
  521. log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
  522. }
  523. }
  524. case nl.IPSET_ATTR_IP2 | nl.NLA_F_NESTED:
  525. for attr := range nl.ParseAttributes(attr.Value) {
  526. switch attr.Type {
  527. case nl.IPSET_ATTR_IPADDR_IPV4, nl.IPSET_ATTR_IPADDR_IPV6:
  528. entry.IP2 = net.IP(attr.Value)
  529. default:
  530. log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
  531. }
  532. }
  533. case nl.IPSET_ATTR_CIDR:
  534. entry.CIDR = attr.Value[0]
  535. case nl.IPSET_ATTR_CIDR2:
  536. entry.CIDR2 = attr.Value[0]
  537. case nl.IPSET_ATTR_PORT | nl.NLA_F_NET_BYTEORDER:
  538. val := networkOrder.Uint16(attr.Value)
  539. entry.Port = &val
  540. case nl.IPSET_ATTR_PROTO:
  541. val := attr.Value[0]
  542. entry.Protocol = &val
  543. case nl.IPSET_ATTR_IFACE:
  544. entry.IFace = nl.BytesToString(attr.Value)
  545. case nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER:
  546. val := attr.Uint32()
  547. entry.Mark = &val
  548. default:
  549. log.Printf("unknown ADT attribute from kernel: %+v", attr)
  550. }
  551. }
  552. return
  553. }
  554. func optionsToBitflag(options IpsetCreateOptions) uint32 {
  555. var cadtFlags uint32
  556. if options.Comments {
  557. cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
  558. }
  559. if options.Counters {
  560. cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
  561. }
  562. if options.Skbinfo {
  563. cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
  564. }
  565. return cadtFlags
  566. }