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