github.com/vishvananda/netlink@v1.3.0/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 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 // IpsetAdd adds an entry to an existing ipset. 257 func (h *Handle) IpsetAdd(setname string, entry *IPSetEntry) error { 258 return h.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry) 259 } 260 261 // IpsetDel deletes an entry from an existing ipset. 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 // use tcp protocol as default 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 // not exist 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 // Add the netfilter header 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 }