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