ipset_linux.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. Revision uint8
  61. IPFrom net.IP
  62. IPTo net.IP
  63. PortFrom uint16
  64. PortTo uint16
  65. }
  66. // IpsetProtocol returns the ipset protocol version from the kernel
  67. func IpsetProtocol() (uint8, uint8, error) {
  68. return pkgHandle.IpsetProtocol()
  69. }
  70. // IpsetCreate creates a new ipset
  71. func IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  72. return pkgHandle.IpsetCreate(setname, typename, options)
  73. }
  74. // IpsetDestroy destroys an existing ipset
  75. func IpsetDestroy(setname string) error {
  76. return pkgHandle.IpsetDestroy(setname)
  77. }
  78. // IpsetFlush flushes an existing ipset
  79. func IpsetFlush(setname string) error {
  80. return pkgHandle.IpsetFlush(setname)
  81. }
  82. // IpsetList dumps an specific ipset.
  83. func IpsetList(setname string) (*IPSetResult, error) {
  84. return pkgHandle.IpsetList(setname)
  85. }
  86. // IpsetListAll dumps all ipsets.
  87. func IpsetListAll() ([]IPSetResult, error) {
  88. return pkgHandle.IpsetListAll()
  89. }
  90. // IpsetAdd adds an entry to an existing ipset.
  91. func IpsetAdd(setname string, entry *IPSetEntry) error {
  92. return pkgHandle.IpsetAdd(setname, entry)
  93. }
  94. // IpsetDel deletes an entry from an existing ipset.
  95. func IpsetDel(setname string, entry *IPSetEntry) error {
  96. return pkgHandle.IpsetDel(setname, entry)
  97. }
  98. func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
  99. req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
  100. msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
  101. if err != nil {
  102. return 0, 0, err
  103. }
  104. response := ipsetUnserialize(msgs)
  105. return response.Protocol, response.ProtocolMinVersion, nil
  106. }
  107. func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  108. req := h.newIpsetRequest(nl.IPSET_CMD_CREATE)
  109. if !options.Replace {
  110. req.Flags |= unix.NLM_F_EXCL
  111. }
  112. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  113. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
  114. revision := options.Revision
  115. if revision == 0 {
  116. revision = getIpsetDefaultWithTypeName(typename)
  117. }
  118. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision)))
  119. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  120. var family uint8
  121. switch typename {
  122. case "hash:mac":
  123. case "bitmap:port":
  124. buf := make([]byte, 4)
  125. binary.BigEndian.PutUint16(buf, options.PortFrom)
  126. binary.BigEndian.PutUint16(buf[2:], options.PortTo)
  127. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_FROM|int(nl.NLA_F_NET_BYTEORDER), buf[:2]))
  128. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_TO|int(nl.NLA_F_NET_BYTEORDER), buf[2:]))
  129. default:
  130. family = unix.AF_INET
  131. }
  132. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(family)))
  133. if timeout := options.Timeout; timeout != nil {
  134. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
  135. }
  136. var cadtFlags uint32
  137. if options.Comments {
  138. cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
  139. }
  140. if options.Counters {
  141. cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
  142. }
  143. if options.Skbinfo {
  144. cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
  145. }
  146. if cadtFlags != 0 {
  147. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
  148. }
  149. req.AddData(data)
  150. _, err := ipsetExecute(req)
  151. return err
  152. }
  153. func (h *Handle) IpsetDestroy(setname string) error {
  154. req := h.newIpsetRequest(nl.IPSET_CMD_DESTROY)
  155. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  156. _, err := ipsetExecute(req)
  157. return err
  158. }
  159. func (h *Handle) IpsetFlush(setname string) error {
  160. req := h.newIpsetRequest(nl.IPSET_CMD_FLUSH)
  161. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  162. _, err := ipsetExecute(req)
  163. return err
  164. }
  165. func (h *Handle) IpsetList(name string) (*IPSetResult, error) {
  166. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  167. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(name)))
  168. msgs, err := ipsetExecute(req)
  169. if err != nil {
  170. return nil, err
  171. }
  172. result := ipsetUnserialize(msgs)
  173. return &result, nil
  174. }
  175. func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
  176. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  177. msgs, err := ipsetExecute(req)
  178. if err != nil {
  179. return nil, err
  180. }
  181. result := make([]IPSetResult, len(msgs))
  182. for i, msg := range msgs {
  183. result[i].unserialize(msg)
  184. }
  185. return result, nil
  186. }
  187. // IpsetAdd adds an entry to an existing ipset.
  188. func (h *Handle) IpsetAdd(setname string, entry *IPSetEntry) error {
  189. return h.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
  190. }
  191. // IpsetDel deletes an entry from an existing ipset.
  192. func (h *Handle) IpsetDel(setname string, entry *IPSetEntry) error {
  193. return h.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
  194. }
  195. func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
  196. req := h.newIpsetRequest(nlCmd)
  197. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  198. if entry.Comment != "" {
  199. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
  200. }
  201. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  202. if !entry.Replace {
  203. req.Flags |= unix.NLM_F_EXCL
  204. }
  205. if entry.Timeout != nil {
  206. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
  207. }
  208. if entry.IP != nil {
  209. nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
  210. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  211. }
  212. if entry.MAC != nil {
  213. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC))
  214. }
  215. if entry.CIDR != 0 {
  216. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR, nl.Uint8Attr(entry.CIDR)))
  217. }
  218. if entry.IP2 != nil {
  219. nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP2)
  220. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP2|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  221. }
  222. if entry.CIDR2 != 0 {
  223. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR2, nl.Uint8Attr(entry.CIDR2)))
  224. }
  225. if entry.Port != nil {
  226. if entry.Protocol == nil {
  227. // use tcp protocol as default
  228. val := uint8(unix.IPPROTO_TCP)
  229. entry.Protocol = &val
  230. }
  231. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PROTO, nl.Uint8Attr(*entry.Protocol)))
  232. buf := make([]byte, 2)
  233. binary.BigEndian.PutUint16(buf, *entry.Port)
  234. data.AddChild(nl.NewRtAttr(int(nl.IPSET_ATTR_PORT|nl.NLA_F_NET_BYTEORDER), buf))
  235. }
  236. if entry.IFace != "" {
  237. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IFACE, nl.ZeroTerminated(entry.IFace)))
  238. }
  239. if entry.Mark != nil {
  240. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER, Value: *entry.Mark})
  241. }
  242. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
  243. req.AddData(data)
  244. _, err := ipsetExecute(req)
  245. return err
  246. }
  247. func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
  248. req := h.newNetlinkRequest(cmd|(unix.NFNL_SUBSYS_IPSET<<8), nl.GetIpsetFlags(cmd))
  249. // Add the netfilter header
  250. msg := &nl.Nfgenmsg{
  251. NfgenFamily: uint8(unix.AF_NETLINK),
  252. Version: nl.NFNETLINK_V0,
  253. ResId: 0,
  254. }
  255. req.AddData(msg)
  256. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_PROTOCOL, nl.Uint8Attr(nl.IPSET_PROTOCOL)))
  257. return req
  258. }
  259. func getIpsetDefaultWithTypeName(typename string) uint8 {
  260. switch typename {
  261. case "hash:ip,port",
  262. "hash:ip,port,ip",
  263. "hash:ip,port,net",
  264. "hash:net,port":
  265. return 1
  266. }
  267. return 0
  268. }
  269. func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
  270. msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
  271. if err != nil {
  272. if errno := int(err.(syscall.Errno)); errno >= nl.IPSET_ERR_PRIVATE {
  273. err = nl.IPSetError(uintptr(errno))
  274. }
  275. }
  276. return
  277. }
  278. func ipsetUnserialize(msgs [][]byte) (result IPSetResult) {
  279. for _, msg := range msgs {
  280. result.unserialize(msg)
  281. }
  282. return result
  283. }
  284. func (result *IPSetResult) unserialize(msg []byte) {
  285. result.Nfgenmsg = nl.DeserializeNfgenmsg(msg)
  286. for attr := range nl.ParseAttributes(msg[4:]) {
  287. switch attr.Type {
  288. case nl.IPSET_ATTR_PROTOCOL:
  289. result.Protocol = attr.Value[0]
  290. case nl.IPSET_ATTR_SETNAME:
  291. result.SetName = nl.BytesToString(attr.Value)
  292. case nl.IPSET_ATTR_COMMENT:
  293. result.Comment = nl.BytesToString(attr.Value)
  294. case nl.IPSET_ATTR_TYPENAME:
  295. result.TypeName = nl.BytesToString(attr.Value)
  296. case nl.IPSET_ATTR_REVISION:
  297. result.Revision = attr.Value[0]
  298. case nl.IPSET_ATTR_FAMILY:
  299. result.Family = attr.Value[0]
  300. case nl.IPSET_ATTR_FLAGS:
  301. result.Flags = attr.Value[0]
  302. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  303. result.parseAttrData(attr.Value)
  304. case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
  305. result.parseAttrADT(attr.Value)
  306. case nl.IPSET_ATTR_PROTOCOL_MIN:
  307. result.ProtocolMinVersion = attr.Value[0]
  308. case nl.IPSET_ATTR_MARKMASK:
  309. result.MarkMask = attr.Uint32()
  310. default:
  311. log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  312. }
  313. }
  314. }
  315. func (result *IPSetResult) parseAttrData(data []byte) {
  316. for attr := range nl.ParseAttributes(data) {
  317. switch attr.Type {
  318. case nl.IPSET_ATTR_HASHSIZE | nl.NLA_F_NET_BYTEORDER:
  319. result.HashSize = attr.Uint32()
  320. case nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER:
  321. result.MaxElements = attr.Uint32()
  322. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  323. val := attr.Uint32()
  324. result.Timeout = &val
  325. case nl.IPSET_ATTR_ELEMENTS | nl.NLA_F_NET_BYTEORDER:
  326. result.NumEntries = attr.Uint32()
  327. case nl.IPSET_ATTR_REFERENCES | nl.NLA_F_NET_BYTEORDER:
  328. result.References = attr.Uint32()
  329. case nl.IPSET_ATTR_MEMSIZE | nl.NLA_F_NET_BYTEORDER:
  330. result.SizeInMemory = attr.Uint32()
  331. case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
  332. result.CadtFlags = attr.Uint32()
  333. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  334. for nested := range nl.ParseAttributes(attr.Value) {
  335. switch nested.Type {
  336. case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
  337. result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
  338. case nl.IPSET_ATTR_IP:
  339. result.IPFrom = nested.Value
  340. default:
  341. log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
  342. }
  343. }
  344. case nl.IPSET_ATTR_IP_TO | nl.NLA_F_NESTED:
  345. for nested := range nl.ParseAttributes(attr.Value) {
  346. switch nested.Type {
  347. case nl.IPSET_ATTR_IP:
  348. result.IPTo = nested.Value
  349. default:
  350. log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
  351. }
  352. }
  353. case nl.IPSET_ATTR_PORT_FROM | nl.NLA_F_NET_BYTEORDER:
  354. result.PortFrom = networkOrder.Uint16(attr.Value)
  355. case nl.IPSET_ATTR_PORT_TO | nl.NLA_F_NET_BYTEORDER:
  356. result.PortTo = networkOrder.Uint16(attr.Value)
  357. case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
  358. result.LineNo = attr.Uint32()
  359. case nl.IPSET_ATTR_COMMENT:
  360. result.Comment = nl.BytesToString(attr.Value)
  361. case nl.IPSET_ATTR_MARKMASK:
  362. result.MarkMask = attr.Uint32()
  363. default:
  364. log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  365. }
  366. }
  367. }
  368. func (result *IPSetResult) parseAttrADT(data []byte) {
  369. for attr := range nl.ParseAttributes(data) {
  370. switch attr.Type {
  371. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  372. result.Entries = append(result.Entries, parseIPSetEntry(attr.Value))
  373. default:
  374. log.Printf("unknown ADT attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  375. }
  376. }
  377. }
  378. func parseIPSetEntry(data []byte) (entry IPSetEntry) {
  379. for attr := range nl.ParseAttributes(data) {
  380. switch attr.Type {
  381. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  382. val := attr.Uint32()
  383. entry.Timeout = &val
  384. case nl.IPSET_ATTR_BYTES | nl.NLA_F_NET_BYTEORDER:
  385. val := attr.Uint64()
  386. entry.Bytes = &val
  387. case nl.IPSET_ATTR_PACKETS | nl.NLA_F_NET_BYTEORDER:
  388. val := attr.Uint64()
  389. entry.Packets = &val
  390. case nl.IPSET_ATTR_ETHER:
  391. entry.MAC = net.HardwareAddr(attr.Value)
  392. case nl.IPSET_ATTR_IP:
  393. entry.IP = net.IP(attr.Value)
  394. case nl.IPSET_ATTR_COMMENT:
  395. entry.Comment = nl.BytesToString(attr.Value)
  396. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  397. for attr := range nl.ParseAttributes(attr.Value) {
  398. switch attr.Type {
  399. case nl.IPSET_ATTR_IP:
  400. entry.IP = net.IP(attr.Value)
  401. default:
  402. log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
  403. }
  404. }
  405. case nl.IPSET_ATTR_IP2 | nl.NLA_F_NESTED:
  406. for attr := range nl.ParseAttributes(attr.Value) {
  407. switch attr.Type {
  408. case nl.IPSET_ATTR_IP:
  409. entry.IP2 = net.IP(attr.Value)
  410. default:
  411. log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
  412. }
  413. }
  414. case nl.IPSET_ATTR_CIDR:
  415. entry.CIDR = attr.Value[0]
  416. case nl.IPSET_ATTR_CIDR2:
  417. entry.CIDR2 = attr.Value[0]
  418. case nl.IPSET_ATTR_PORT | nl.NLA_F_NET_BYTEORDER:
  419. val := networkOrder.Uint16(attr.Value)
  420. entry.Port = &val
  421. case nl.IPSET_ATTR_PROTO:
  422. val := attr.Value[0]
  423. entry.Protocol = &val
  424. case nl.IPSET_ATTR_IFACE:
  425. entry.IFace = nl.BytesToString(attr.Value)
  426. case nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER:
  427. val := attr.Uint32()
  428. entry.Mark = &val
  429. default:
  430. log.Printf("unknown ADT attribute from kernel: %+v", attr)
  431. }
  432. }
  433. return
  434. }