252 lines
8.2 KiB
Go
252 lines
8.2 KiB
Go
package firewalld
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
)
|
|
|
|
// IPSetSettings is the transport-neutral representation of an ipset. It maps to
|
|
// the D-Bus tuple "(ssssa{ss}as)": version, name, description, type, options,
|
|
// entries. ipsets have no dict form; the tuple is used on every server.
|
|
type IPSetSettings struct {
|
|
Version string
|
|
Name string
|
|
Description string
|
|
Type string // e.g. "hash:ip", "hash:net"
|
|
Options map[string]string // e.g. {"family": "inet"}
|
|
Entries []string
|
|
}
|
|
|
|
// ipsetTuple is the concrete struct godbus encodes to "(ssssa{ss}as)". Field
|
|
// order matches firewalld's ipset settings tuple exactly.
|
|
type ipsetTuple struct {
|
|
Version string
|
|
Name string
|
|
Description string
|
|
Type string
|
|
Options map[string]string
|
|
Entries []string
|
|
}
|
|
|
|
// toTuple builds the wire tuple, defaulting nil maps/slices to empty.
|
|
func (s *IPSetSettings) toTuple() ipsetTuple {
|
|
opts := s.Options
|
|
if opts == nil {
|
|
opts = map[string]string{}
|
|
}
|
|
entries := s.Entries
|
|
if entries == nil {
|
|
entries = []string{}
|
|
}
|
|
return ipsetTuple{
|
|
Version: s.Version,
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Type: s.Type,
|
|
Options: opts,
|
|
Entries: entries,
|
|
}
|
|
}
|
|
|
|
// ipsetSettingsFromTuple decodes a raw ipset tuple, length-tolerant throughout.
|
|
func ipsetSettingsFromTuple(raw []any) IPSetSettings {
|
|
return IPSetSettings{
|
|
Version: asString(tupleField(raw, 0)),
|
|
Name: asString(tupleField(raw, 1)),
|
|
Description: asString(tupleField(raw, 2)),
|
|
Type: asString(tupleField(raw, 3)),
|
|
Options: asStringMap(tupleField(raw, 4)),
|
|
Entries: asStrings(tupleField(raw, 5)),
|
|
}
|
|
}
|
|
|
|
// IPSetNames lists the names of all permanent ipsets.
|
|
func (p *Permanent) IPSetNames(ctx context.Context) ([]string, error) {
|
|
var names []string
|
|
err := p.c.call(ctx, configPath, ifaceConfig, "getIPSetNames", []any{&names})
|
|
return names, err
|
|
}
|
|
|
|
// AddIPSet creates a new permanent ipset from the given settings and returns its
|
|
// config object path.
|
|
func (p *Permanent) AddIPSet(ctx context.Context, name string, settings IPSetSettings) (dbus.ObjectPath, error) {
|
|
var path dbus.ObjectPath
|
|
err := p.c.call(ctx, configPath, ifaceConfig, "addIPSet", []any{&path}, name, settings.toTuple())
|
|
return path, err
|
|
}
|
|
|
|
// IPSet returns a handle for permanent operations on the named ipset.
|
|
func (p *Permanent) IPSet(name string) *PermIPSet {
|
|
return &PermIPSet{c: p.c, name: name}
|
|
}
|
|
|
|
// IPSets lists the names of ipsets known to the runtime.
|
|
func (r *Runtime) IPSets(ctx context.Context) ([]string, error) {
|
|
var names []string
|
|
err := r.c.call(ctx, basePath, ifaceIPSet, "getIPSets", []any{&names})
|
|
return names, err
|
|
}
|
|
|
|
// IPSetExists reports whether an ipset of the given name exists at runtime.
|
|
func (r *Runtime) IPSetExists(ctx context.Context, name string) (bool, error) {
|
|
var ok bool
|
|
err := r.c.call(ctx, basePath, ifaceIPSet, "queryIPSet", []any{&ok}, name)
|
|
return ok, err
|
|
}
|
|
|
|
// IPSetPaths lists the config object paths of all permanent ipsets (listIPSets).
|
|
func (p *Permanent) IPSetPaths(ctx context.Context) ([]dbus.ObjectPath, error) {
|
|
var paths []dbus.ObjectPath
|
|
err := p.c.call(ctx, configPath, ifaceConfig, "listIPSets", []any{&paths})
|
|
return paths, err
|
|
}
|
|
|
|
// IPSet returns a handle for runtime operations on the named ipset.
|
|
func (r *Runtime) IPSet(name string) *RuntimeIPSet {
|
|
return &RuntimeIPSet{c: r.c, name: name}
|
|
}
|
|
|
|
// RuntimeIPSet is a handle for transient ipset entry operations on the running
|
|
// firewall. ipset runtime methods live on the main object's .ipset interface.
|
|
type RuntimeIPSet struct {
|
|
c *Conn
|
|
name string
|
|
}
|
|
|
|
// Settings reads the runtime settings of the ipset.
|
|
func (s *RuntimeIPSet) Settings(ctx context.Context) (IPSetSettings, error) {
|
|
var raw []any
|
|
if err := s.c.call(ctx, basePath, ifaceIPSet, "getIPSetSettings", []any{&raw}, s.name); err != nil {
|
|
return IPSetSettings{}, err
|
|
}
|
|
return ipsetSettingsFromTuple(raw), nil
|
|
}
|
|
|
|
// AddEntry adds a single entry to the ipset at runtime.
|
|
func (s *RuntimeIPSet) AddEntry(ctx context.Context, entry string) error {
|
|
return s.c.call(ctx, basePath, ifaceIPSet, "addEntry", nil, s.name, entry)
|
|
}
|
|
|
|
// RemoveEntry removes a single entry from the ipset at runtime.
|
|
func (s *RuntimeIPSet) RemoveEntry(ctx context.Context, entry string) error {
|
|
return s.c.call(ctx, basePath, ifaceIPSet, "removeEntry", nil, s.name, entry)
|
|
}
|
|
|
|
// QueryEntry reports whether an entry is present at runtime.
|
|
func (s *RuntimeIPSet) QueryEntry(ctx context.Context, entry string) (bool, error) {
|
|
var ok bool
|
|
err := s.c.call(ctx, basePath, ifaceIPSet, "queryEntry", []any{&ok}, s.name, entry)
|
|
return ok, err
|
|
}
|
|
|
|
// Entries returns all entries of the ipset at runtime.
|
|
func (s *RuntimeIPSet) Entries(ctx context.Context) ([]string, error) {
|
|
var entries []string
|
|
err := s.c.call(ctx, basePath, ifaceIPSet, "getEntries", []any{&entries}, s.name)
|
|
return entries, err
|
|
}
|
|
|
|
// SetEntries replaces all entries of the ipset at runtime.
|
|
func (s *RuntimeIPSet) SetEntries(ctx context.Context, entries []string) error {
|
|
if entries == nil {
|
|
entries = []string{}
|
|
}
|
|
return s.c.call(ctx, basePath, ifaceIPSet, "setEntries", nil, s.name, entries)
|
|
}
|
|
|
|
// PermIPSet is a handle for permanent edits to a single ipset, operating on the
|
|
// ipset's config child object (/config/ipset/N).
|
|
type PermIPSet struct {
|
|
c *Conn
|
|
name string
|
|
path dbus.ObjectPath
|
|
}
|
|
|
|
// resolve looks up and caches the config object path for the ipset.
|
|
func (s *PermIPSet) resolve(ctx context.Context) (dbus.ObjectPath, error) {
|
|
if s.path != "" {
|
|
return s.path, nil
|
|
}
|
|
var path dbus.ObjectPath
|
|
if err := s.c.call(ctx, configPath, ifaceConfig, "getIPSetByName", []any{&path}, s.name); err != nil {
|
|
return "", err
|
|
}
|
|
s.path = path
|
|
return path, nil
|
|
}
|
|
|
|
// callOn resolves the ipset path and invokes a config.ipset method.
|
|
func (s *PermIPSet) callOn(ctx context.Context, method string, rets []any, args ...any) error {
|
|
path, err := s.resolve(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.c.call(ctx, path, ifaceConfigIPSet, method, rets, args...)
|
|
}
|
|
|
|
// Settings reads the ipset's permanent settings.
|
|
func (s *PermIPSet) Settings(ctx context.Context) (IPSetSettings, error) {
|
|
var raw []any
|
|
if err := s.callOn(ctx, "getSettings", []any{&raw}); err != nil {
|
|
return IPSetSettings{}, err
|
|
}
|
|
return ipsetSettingsFromTuple(raw), nil
|
|
}
|
|
|
|
// Update replaces the ipset's permanent settings wholesale.
|
|
func (s *PermIPSet) Update(ctx context.Context, settings IPSetSettings) error {
|
|
return s.callOn(ctx, "update", nil, settings.toTuple())
|
|
}
|
|
|
|
// AddEntry adds an entry to the permanent ipset.
|
|
func (s *PermIPSet) AddEntry(ctx context.Context, entry string) error {
|
|
return s.callOn(ctx, "addEntry", nil, entry)
|
|
}
|
|
|
|
// RemoveEntry removes an entry from the permanent ipset.
|
|
func (s *PermIPSet) RemoveEntry(ctx context.Context, entry string) error {
|
|
return s.callOn(ctx, "removeEntry", nil, entry)
|
|
}
|
|
|
|
// QueryEntry reports whether an entry is present in the permanent ipset.
|
|
func (s *PermIPSet) QueryEntry(ctx context.Context, entry string) (bool, error) {
|
|
var ok bool
|
|
err := s.callOn(ctx, "queryEntry", []any{&ok}, entry)
|
|
return ok, err
|
|
}
|
|
|
|
// Entries returns all entries of the permanent ipset.
|
|
func (s *PermIPSet) Entries(ctx context.Context) ([]string, error) {
|
|
var entries []string
|
|
err := s.callOn(ctx, "getEntries", []any{&entries})
|
|
return entries, err
|
|
}
|
|
|
|
// SetEntries replaces all entries of the permanent ipset.
|
|
func (s *PermIPSet) SetEntries(ctx context.Context, entries []string) error {
|
|
if entries == nil {
|
|
entries = []string{}
|
|
}
|
|
return s.callOn(ctx, "setEntries", nil, entries)
|
|
}
|
|
|
|
// AddOption sets an option (key/value) on the permanent ipset.
|
|
func (s *PermIPSet) AddOption(ctx context.Context, key, value string) error {
|
|
return s.callOn(ctx, "addOption", nil, key, value)
|
|
}
|
|
|
|
// RemoveOption removes an option from the permanent ipset.
|
|
func (s *PermIPSet) RemoveOption(ctx context.Context, key string) error {
|
|
return s.callOn(ctx, "removeOption", nil, key)
|
|
}
|
|
|
|
// SetDescription sets the permanent ipset description.
|
|
func (s *PermIPSet) SetDescription(ctx context.Context, description string) error {
|
|
return s.callOn(ctx, "setDescription", nil, description)
|
|
}
|
|
|
|
// Remove deletes the ipset from the permanent configuration.
|
|
func (s *PermIPSet) Remove(ctx context.Context) error {
|
|
return s.callOn(ctx, "remove", nil)
|
|
}
|