ipset_linux.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. package netlink
  2. import (
  3. "log"
  4. "net"
  5. "syscall"
  6. "github.com/vishvananda/netlink/nl"
  7. "golang.org/x/sys/unix"
  8. )
  9. // IPSetEntry is used for adding, updating, retreiving and deleting entries
  10. type IPSetEntry struct {
  11. Comment string
  12. MAC net.HardwareAddr
  13. IP net.IP
  14. Timeout *uint32
  15. Packets *uint64
  16. Bytes *uint64
  17. Replace bool // replace existing entry
  18. }
  19. // IPSetResult is the result of a dump request for a set
  20. type IPSetResult struct {
  21. Nfgenmsg *nl.Nfgenmsg
  22. Protocol uint8
  23. ProtocolMinVersion uint8
  24. Revision uint8
  25. Family uint8
  26. Flags uint8
  27. SetName string
  28. TypeName string
  29. Comment string
  30. HashSize uint32
  31. NumEntries uint32
  32. MaxElements uint32
  33. References uint32
  34. SizeInMemory uint32
  35. CadtFlags uint32
  36. Timeout *uint32
  37. LineNo uint32
  38. Entries []IPSetEntry
  39. }
  40. // IpsetCreateOptions is the options struct for creating a new ipset
  41. type IpsetCreateOptions struct {
  42. Replace bool // replace existing ipset
  43. Timeout *uint32
  44. Counters bool
  45. Comments bool
  46. Skbinfo bool
  47. }
  48. // IpsetProtocol returns the ipset protocol version from the kernel
  49. func IpsetProtocol() (uint8, uint8, error) {
  50. return pkgHandle.IpsetProtocol()
  51. }
  52. // IpsetCreate creates a new ipset
  53. func IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  54. return pkgHandle.IpsetCreate(setname, typename, options)
  55. }
  56. // IpsetDestroy destroys an existing ipset
  57. func IpsetDestroy(setname string) error {
  58. return pkgHandle.IpsetDestroy(setname)
  59. }
  60. // IpsetFlush flushes an existing ipset
  61. func IpsetFlush(setname string) error {
  62. return pkgHandle.IpsetFlush(setname)
  63. }
  64. // IpsetList dumps an specific ipset.
  65. func IpsetList(setname string) (*IPSetResult, error) {
  66. return pkgHandle.IpsetList(setname)
  67. }
  68. // IpsetListAll dumps all ipsets.
  69. func IpsetListAll() ([]IPSetResult, error) {
  70. return pkgHandle.IpsetListAll()
  71. }
  72. // IpsetAdd adds an entry to an existing ipset.
  73. func IpsetAdd(setname string, entry *IPSetEntry) error {
  74. return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
  75. }
  76. // IpsetDel deletes an entry from an existing ipset.
  77. func IpsetDel(setname string, entry *IPSetEntry) error {
  78. return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
  79. }
  80. func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
  81. req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
  82. msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
  83. if err != nil {
  84. return 0, 0, err
  85. }
  86. response := ipsetUnserialize(msgs)
  87. return response.Protocol, response.ProtocolMinVersion, nil
  88. }
  89. func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
  90. req := h.newIpsetRequest(nl.IPSET_CMD_CREATE)
  91. if !options.Replace {
  92. req.Flags |= unix.NLM_F_EXCL
  93. }
  94. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  95. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
  96. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
  97. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(2))) // 2 == inet
  98. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  99. if timeout := options.Timeout; timeout != nil {
  100. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
  101. }
  102. var cadtFlags uint32
  103. if options.Comments {
  104. cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
  105. }
  106. if options.Counters {
  107. cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
  108. }
  109. if options.Skbinfo {
  110. cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
  111. }
  112. if cadtFlags != 0 {
  113. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
  114. }
  115. req.AddData(data)
  116. _, err := ipsetExecute(req)
  117. return err
  118. }
  119. func (h *Handle) IpsetDestroy(setname string) error {
  120. req := h.newIpsetRequest(nl.IPSET_CMD_DESTROY)
  121. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  122. _, err := ipsetExecute(req)
  123. return err
  124. }
  125. func (h *Handle) IpsetFlush(setname string) error {
  126. req := h.newIpsetRequest(nl.IPSET_CMD_FLUSH)
  127. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  128. _, err := ipsetExecute(req)
  129. return err
  130. }
  131. func (h *Handle) IpsetList(name string) (*IPSetResult, error) {
  132. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  133. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(name)))
  134. msgs, err := ipsetExecute(req)
  135. if err != nil {
  136. return nil, err
  137. }
  138. result := ipsetUnserialize(msgs)
  139. return &result, nil
  140. }
  141. func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
  142. req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
  143. msgs, err := ipsetExecute(req)
  144. if err != nil {
  145. return nil, err
  146. }
  147. result := make([]IPSetResult, len(msgs))
  148. for i, msg := range msgs {
  149. result[i].unserialize(msg)
  150. }
  151. return result, nil
  152. }
  153. func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
  154. req := h.newIpsetRequest(nlCmd)
  155. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
  156. if entry.Comment != "" {
  157. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
  158. }
  159. data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
  160. if !entry.Replace {
  161. req.Flags |= unix.NLM_F_EXCL
  162. }
  163. if entry.Timeout != nil {
  164. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
  165. }
  166. if entry.MAC != nil {
  167. nestedData := nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NET_BYTEORDER), entry.MAC)
  168. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  169. }
  170. if entry.IP != nil {
  171. nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
  172. data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
  173. }
  174. data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
  175. req.AddData(data)
  176. _, err := ipsetExecute(req)
  177. return err
  178. }
  179. func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
  180. req := h.newNetlinkRequest(cmd|(unix.NFNL_SUBSYS_IPSET<<8), nl.GetIpsetFlags(cmd))
  181. // Add the netfilter header
  182. msg := &nl.Nfgenmsg{
  183. NfgenFamily: uint8(unix.AF_NETLINK),
  184. Version: nl.NFNETLINK_V0,
  185. ResId: 0,
  186. }
  187. req.AddData(msg)
  188. req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_PROTOCOL, nl.Uint8Attr(nl.IPSET_PROTOCOL)))
  189. return req
  190. }
  191. func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
  192. msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
  193. if err != nil {
  194. if errno := int(err.(syscall.Errno)); errno >= nl.IPSET_ERR_PRIVATE {
  195. err = nl.IPSetError(uintptr(errno))
  196. }
  197. }
  198. return
  199. }
  200. func ipsetUnserialize(msgs [][]byte) (result IPSetResult) {
  201. for _, msg := range msgs {
  202. result.unserialize(msg)
  203. }
  204. return result
  205. }
  206. func (result *IPSetResult) unserialize(msg []byte) {
  207. result.Nfgenmsg = nl.DeserializeNfgenmsg(msg)
  208. for attr := range nl.ParseAttributes(msg[4:]) {
  209. switch attr.Type {
  210. case nl.IPSET_ATTR_PROTOCOL:
  211. result.Protocol = attr.Value[0]
  212. case nl.IPSET_ATTR_SETNAME:
  213. result.SetName = nl.BytesToString(attr.Value)
  214. case nl.IPSET_ATTR_COMMENT:
  215. result.Comment = nl.BytesToString(attr.Value)
  216. case nl.IPSET_ATTR_TYPENAME:
  217. result.TypeName = nl.BytesToString(attr.Value)
  218. case nl.IPSET_ATTR_REVISION:
  219. result.Revision = attr.Value[0]
  220. case nl.IPSET_ATTR_FAMILY:
  221. result.Family = attr.Value[0]
  222. case nl.IPSET_ATTR_FLAGS:
  223. result.Flags = attr.Value[0]
  224. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  225. result.parseAttrData(attr.Value)
  226. case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
  227. result.parseAttrADT(attr.Value)
  228. case nl.IPSET_ATTR_PROTOCOL_MIN:
  229. result.ProtocolMinVersion = attr.Value[0]
  230. default:
  231. log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  232. }
  233. }
  234. }
  235. func (result *IPSetResult) parseAttrData(data []byte) {
  236. for attr := range nl.ParseAttributes(data) {
  237. switch attr.Type {
  238. case nl.IPSET_ATTR_HASHSIZE | nl.NLA_F_NET_BYTEORDER:
  239. result.HashSize = attr.Uint32()
  240. case nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER:
  241. result.MaxElements = attr.Uint32()
  242. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  243. val := attr.Uint32()
  244. result.Timeout = &val
  245. case nl.IPSET_ATTR_ELEMENTS | nl.NLA_F_NET_BYTEORDER:
  246. result.NumEntries = attr.Uint32()
  247. case nl.IPSET_ATTR_REFERENCES | nl.NLA_F_NET_BYTEORDER:
  248. result.References = attr.Uint32()
  249. case nl.IPSET_ATTR_MEMSIZE | nl.NLA_F_NET_BYTEORDER:
  250. result.SizeInMemory = attr.Uint32()
  251. case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
  252. result.CadtFlags = attr.Uint32()
  253. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  254. for nested := range nl.ParseAttributes(attr.Value) {
  255. switch nested.Type {
  256. case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
  257. result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
  258. }
  259. }
  260. case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
  261. result.LineNo = attr.Uint32()
  262. case nl.IPSET_ATTR_COMMENT:
  263. result.Comment = nl.BytesToString(attr.Value)
  264. default:
  265. log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  266. }
  267. }
  268. }
  269. func (result *IPSetResult) parseAttrADT(data []byte) {
  270. for attr := range nl.ParseAttributes(data) {
  271. switch attr.Type {
  272. case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
  273. result.Entries = append(result.Entries, parseIPSetEntry(attr.Value))
  274. default:
  275. log.Printf("unknown ADT attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
  276. }
  277. }
  278. }
  279. func parseIPSetEntry(data []byte) (entry IPSetEntry) {
  280. for attr := range nl.ParseAttributes(data) {
  281. switch attr.Type {
  282. case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
  283. val := attr.Uint32()
  284. entry.Timeout = &val
  285. case nl.IPSET_ATTR_BYTES | nl.NLA_F_NET_BYTEORDER:
  286. val := attr.Uint64()
  287. entry.Bytes = &val
  288. case nl.IPSET_ATTR_PACKETS | nl.NLA_F_NET_BYTEORDER:
  289. val := attr.Uint64()
  290. entry.Packets = &val
  291. case nl.IPSET_ATTR_ETHER:
  292. entry.MAC = net.HardwareAddr(attr.Value)
  293. case nl.IPSET_ATTR_IP:
  294. entry.IP = net.IP(attr.Value)
  295. case nl.IPSET_ATTR_COMMENT:
  296. entry.Comment = nl.BytesToString(attr.Value)
  297. case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
  298. for attr := range nl.ParseAttributes(attr.Value) {
  299. switch attr.Type {
  300. case nl.IPSET_ATTR_IP:
  301. entry.IP = net.IP(attr.Value)
  302. default:
  303. log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
  304. }
  305. }
  306. default:
  307. log.Printf("unknown ADT attribute from kernel: %+v", attr)
  308. }
  309. }
  310. return
  311. }