8cadff2b79
* CNI: bump to 1.0.1 This commit bumps the declared version of CNI in the Kilo manifests to 1.0.1. This is possible with no changes to the configuration lists because our simple configuration is not affected by any of the deprecations, and there was effectively no change between 0.4.0 and 1.0.0, other than the declaration of a stable API. Similarly, this commit also bumps the version of the CNI library and the plugins package. Bumping to CNI 1.0.0 will help ensure that Kilo stays compatible with container runtimes in the future. Signed-off-by: Lucas Servén Marín <lserven@gmail.com> * vendor: revendor Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
366 lines
10 KiB
Go
366 lines
10 KiB
Go
package netlink
|
|
|
|
import (
|
|
"log"
|
|
"net"
|
|
"syscall"
|
|
|
|
"github.com/vishvananda/netlink/nl"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// IPSetEntry is used for adding, updating, retreiving and deleting entries
|
|
type IPSetEntry struct {
|
|
Comment string
|
|
MAC net.HardwareAddr
|
|
IP net.IP
|
|
Timeout *uint32
|
|
Packets *uint64
|
|
Bytes *uint64
|
|
|
|
Replace bool // replace existing entry
|
|
}
|
|
|
|
// IPSetResult is the result of a dump request for a set
|
|
type IPSetResult struct {
|
|
Nfgenmsg *nl.Nfgenmsg
|
|
Protocol uint8
|
|
ProtocolMinVersion uint8
|
|
Revision uint8
|
|
Family uint8
|
|
Flags uint8
|
|
SetName string
|
|
TypeName string
|
|
Comment string
|
|
|
|
HashSize uint32
|
|
NumEntries uint32
|
|
MaxElements uint32
|
|
References uint32
|
|
SizeInMemory uint32
|
|
CadtFlags uint32
|
|
Timeout *uint32
|
|
LineNo uint32
|
|
|
|
Entries []IPSetEntry
|
|
}
|
|
|
|
// IpsetCreateOptions is the options struct for creating a new ipset
|
|
type IpsetCreateOptions struct {
|
|
Replace bool // replace existing ipset
|
|
Timeout *uint32
|
|
Counters bool
|
|
Comments bool
|
|
Skbinfo bool
|
|
}
|
|
|
|
// IpsetProtocol returns the ipset protocol version from the kernel
|
|
func IpsetProtocol() (uint8, uint8, error) {
|
|
return pkgHandle.IpsetProtocol()
|
|
}
|
|
|
|
// IpsetCreate creates a new ipset
|
|
func IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
|
|
return pkgHandle.IpsetCreate(setname, typename, options)
|
|
}
|
|
|
|
// IpsetDestroy destroys an existing ipset
|
|
func IpsetDestroy(setname string) error {
|
|
return pkgHandle.IpsetDestroy(setname)
|
|
}
|
|
|
|
// IpsetFlush flushes an existing ipset
|
|
func IpsetFlush(setname string) error {
|
|
return pkgHandle.IpsetFlush(setname)
|
|
}
|
|
|
|
// IpsetList dumps an specific ipset.
|
|
func IpsetList(setname string) (*IPSetResult, error) {
|
|
return pkgHandle.IpsetList(setname)
|
|
}
|
|
|
|
// IpsetListAll dumps all ipsets.
|
|
func IpsetListAll() ([]IPSetResult, error) {
|
|
return pkgHandle.IpsetListAll()
|
|
}
|
|
|
|
// IpsetAdd adds an entry to an existing ipset.
|
|
func IpsetAdd(setname string, entry *IPSetEntry) error {
|
|
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
|
|
}
|
|
|
|
// IpsetDel deletes an entry from an existing ipset.
|
|
func IpsetDel(setname string, entry *IPSetEntry) error {
|
|
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
|
|
}
|
|
|
|
func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
|
|
msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
|
|
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
response := ipsetUnserialize(msgs)
|
|
return response.Protocol, response.ProtocolMinVersion, nil
|
|
}
|
|
|
|
func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_CREATE)
|
|
|
|
if !options.Replace {
|
|
req.Flags |= unix.NLM_F_EXCL
|
|
}
|
|
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(2))) // 2 == inet
|
|
|
|
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
|
|
|
|
if timeout := options.Timeout; timeout != nil {
|
|
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
|
|
}
|
|
|
|
var cadtFlags uint32
|
|
|
|
if options.Comments {
|
|
cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
|
|
}
|
|
if options.Counters {
|
|
cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
|
|
}
|
|
if options.Skbinfo {
|
|
cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
|
|
}
|
|
|
|
if cadtFlags != 0 {
|
|
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
|
|
}
|
|
|
|
req.AddData(data)
|
|
_, err := ipsetExecute(req)
|
|
return err
|
|
}
|
|
|
|
func (h *Handle) IpsetDestroy(setname string) error {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_DESTROY)
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
|
|
_, err := ipsetExecute(req)
|
|
return err
|
|
}
|
|
|
|
func (h *Handle) IpsetFlush(setname string) error {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_FLUSH)
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
|
|
_, err := ipsetExecute(req)
|
|
return err
|
|
}
|
|
|
|
func (h *Handle) IpsetList(name string) (*IPSetResult, error) {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(name)))
|
|
|
|
msgs, err := ipsetExecute(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := ipsetUnserialize(msgs)
|
|
return &result, nil
|
|
}
|
|
|
|
func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
|
|
req := h.newIpsetRequest(nl.IPSET_CMD_LIST)
|
|
|
|
msgs, err := ipsetExecute(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]IPSetResult, len(msgs))
|
|
for i, msg := range msgs {
|
|
result[i].unserialize(msg)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
|
|
req := h.newIpsetRequest(nlCmd)
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
|
|
|
|
if entry.Comment != "" {
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
|
|
}
|
|
|
|
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
|
|
|
|
if !entry.Replace {
|
|
req.Flags |= unix.NLM_F_EXCL
|
|
}
|
|
|
|
if entry.Timeout != nil {
|
|
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
|
|
}
|
|
if entry.MAC != nil {
|
|
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NET_BYTEORDER), entry.MAC)
|
|
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NESTED), nestedData.Serialize()))
|
|
}
|
|
if entry.IP != nil {
|
|
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
|
|
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
|
|
}
|
|
|
|
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
|
|
req.AddData(data)
|
|
|
|
_, err := ipsetExecute(req)
|
|
return err
|
|
}
|
|
|
|
func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
|
|
req := h.newNetlinkRequest(cmd|(unix.NFNL_SUBSYS_IPSET<<8), nl.GetIpsetFlags(cmd))
|
|
|
|
// Add the netfilter header
|
|
msg := &nl.Nfgenmsg{
|
|
NfgenFamily: uint8(unix.AF_NETLINK),
|
|
Version: nl.NFNETLINK_V0,
|
|
ResId: 0,
|
|
}
|
|
req.AddData(msg)
|
|
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_PROTOCOL, nl.Uint8Attr(nl.IPSET_PROTOCOL)))
|
|
|
|
return req
|
|
}
|
|
|
|
func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
|
|
msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
|
|
|
|
if err != nil {
|
|
if errno := int(err.(syscall.Errno)); errno >= nl.IPSET_ERR_PRIVATE {
|
|
err = nl.IPSetError(uintptr(errno))
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func ipsetUnserialize(msgs [][]byte) (result IPSetResult) {
|
|
for _, msg := range msgs {
|
|
result.unserialize(msg)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (result *IPSetResult) unserialize(msg []byte) {
|
|
result.Nfgenmsg = nl.DeserializeNfgenmsg(msg)
|
|
|
|
for attr := range nl.ParseAttributes(msg[4:]) {
|
|
switch attr.Type {
|
|
case nl.IPSET_ATTR_PROTOCOL:
|
|
result.Protocol = attr.Value[0]
|
|
case nl.IPSET_ATTR_SETNAME:
|
|
result.SetName = nl.BytesToString(attr.Value)
|
|
case nl.IPSET_ATTR_COMMENT:
|
|
result.Comment = nl.BytesToString(attr.Value)
|
|
case nl.IPSET_ATTR_TYPENAME:
|
|
result.TypeName = nl.BytesToString(attr.Value)
|
|
case nl.IPSET_ATTR_REVISION:
|
|
result.Revision = attr.Value[0]
|
|
case nl.IPSET_ATTR_FAMILY:
|
|
result.Family = attr.Value[0]
|
|
case nl.IPSET_ATTR_FLAGS:
|
|
result.Flags = attr.Value[0]
|
|
case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
|
|
result.parseAttrData(attr.Value)
|
|
case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
|
|
result.parseAttrADT(attr.Value)
|
|
case nl.IPSET_ATTR_PROTOCOL_MIN:
|
|
result.ProtocolMinVersion = attr.Value[0]
|
|
default:
|
|
log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (result *IPSetResult) parseAttrData(data []byte) {
|
|
for attr := range nl.ParseAttributes(data) {
|
|
switch attr.Type {
|
|
case nl.IPSET_ATTR_HASHSIZE | nl.NLA_F_NET_BYTEORDER:
|
|
result.HashSize = attr.Uint32()
|
|
case nl.IPSET_ATTR_MAXELEM | nl.NLA_F_NET_BYTEORDER:
|
|
result.MaxElements = attr.Uint32()
|
|
case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
|
|
val := attr.Uint32()
|
|
result.Timeout = &val
|
|
case nl.IPSET_ATTR_ELEMENTS | nl.NLA_F_NET_BYTEORDER:
|
|
result.NumEntries = attr.Uint32()
|
|
case nl.IPSET_ATTR_REFERENCES | nl.NLA_F_NET_BYTEORDER:
|
|
result.References = attr.Uint32()
|
|
case nl.IPSET_ATTR_MEMSIZE | nl.NLA_F_NET_BYTEORDER:
|
|
result.SizeInMemory = attr.Uint32()
|
|
case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
|
|
result.CadtFlags = attr.Uint32()
|
|
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
|
|
for nested := range nl.ParseAttributes(attr.Value) {
|
|
switch nested.Type {
|
|
case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
|
|
result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
|
|
}
|
|
}
|
|
case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
|
|
result.LineNo = attr.Uint32()
|
|
case nl.IPSET_ATTR_COMMENT:
|
|
result.Comment = nl.BytesToString(attr.Value)
|
|
default:
|
|
log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (result *IPSetResult) parseAttrADT(data []byte) {
|
|
for attr := range nl.ParseAttributes(data) {
|
|
switch attr.Type {
|
|
case nl.IPSET_ATTR_DATA | nl.NLA_F_NESTED:
|
|
result.Entries = append(result.Entries, parseIPSetEntry(attr.Value))
|
|
default:
|
|
log.Printf("unknown ADT attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
|
|
}
|
|
}
|
|
}
|
|
|
|
func parseIPSetEntry(data []byte) (entry IPSetEntry) {
|
|
for attr := range nl.ParseAttributes(data) {
|
|
switch attr.Type {
|
|
case nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER:
|
|
val := attr.Uint32()
|
|
entry.Timeout = &val
|
|
case nl.IPSET_ATTR_BYTES | nl.NLA_F_NET_BYTEORDER:
|
|
val := attr.Uint64()
|
|
entry.Bytes = &val
|
|
case nl.IPSET_ATTR_PACKETS | nl.NLA_F_NET_BYTEORDER:
|
|
val := attr.Uint64()
|
|
entry.Packets = &val
|
|
case nl.IPSET_ATTR_ETHER:
|
|
entry.MAC = net.HardwareAddr(attr.Value)
|
|
case nl.IPSET_ATTR_IP:
|
|
entry.IP = net.IP(attr.Value)
|
|
case nl.IPSET_ATTR_COMMENT:
|
|
entry.Comment = nl.BytesToString(attr.Value)
|
|
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
|
|
for attr := range nl.ParseAttributes(attr.Value) {
|
|
switch attr.Type {
|
|
case nl.IPSET_ATTR_IP:
|
|
entry.IP = net.IP(attr.Value)
|
|
default:
|
|
log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
|
|
}
|
|
}
|
|
default:
|
|
log.Printf("unknown ADT attribute from kernel: %+v", attr)
|
|
}
|
|
}
|
|
return
|
|
}
|