88 lines
2.7 KiB
Go
88 lines
2.7 KiB
Go
package firewalld
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Capability names a version-gated feature of the firewalld D-Bus surface.
|
|
// Callers test support with Conn.Supports; internal code version-gates transports
|
|
// (tuple vs dict) on these flags.
|
|
type Capability int
|
|
|
|
const (
|
|
// DictZoneSettings gates the a{sv} zone-settings path (getSettings2/update2 on
|
|
// config.zone, getZoneSettings2/setZoneSettings2 on the runtime .zone). Added
|
|
// in firewalld 0.9. Absent on EL7 0.6.3, which uses the v1 tuple only.
|
|
DictZoneSettings Capability = iota
|
|
// Policies gates zone-to-zone policy objects (config listPolicies/addPolicy,
|
|
// runtime getPolicySettings/getActivePolicies). Added in 0.9. Absent on EL7.
|
|
Policies
|
|
// ServiceSettings2 gates getServiceSettings2/addService2 (a{sv} services).
|
|
// Present on 1.3.4, absent on 0.6.3.
|
|
ServiceSettings2
|
|
// AddZone2 gates config.addZone2/addService2 (dict-based creation). Added 0.9.
|
|
AddZone2
|
|
// ResetToDefaults gates the main resetToDefaults method. Present on 1.x.
|
|
ResetToDefaults
|
|
)
|
|
|
|
// Version is a parsed firewalld version. Missing components read as zero, so a
|
|
// server reporting "1" compares equal to "1.0.0".
|
|
type Version struct {
|
|
Major, Minor, Patch int
|
|
Raw string
|
|
}
|
|
|
|
// parseVersion parses a "X.Y.Z" firewalld version string. Trailing non-numeric
|
|
// suffixes on a component (e.g. a distro tag) are tolerated by reading the leading
|
|
// digits. Unparseable components read as zero rather than failing the connection.
|
|
func parseVersion(raw string) Version {
|
|
v := Version{Raw: raw}
|
|
parts := strings.SplitN(raw, ".", 3)
|
|
dst := []*int{&v.Major, &v.Minor, &v.Patch}
|
|
for i := 0; i < len(parts) && i < 3; i++ {
|
|
*dst[i] = leadingInt(parts[i])
|
|
}
|
|
return v
|
|
}
|
|
|
|
// leadingInt reads the leading base-10 digits of s, ignoring any suffix.
|
|
func leadingInt(s string) int {
|
|
end := 0
|
|
for end < len(s) && s[end] >= '0' && s[end] <= '9' {
|
|
end++
|
|
}
|
|
if end == 0 {
|
|
return 0
|
|
}
|
|
n, err := strconv.Atoi(s[:end])
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return n
|
|
}
|
|
|
|
// atLeast reports whether v is >= the given major.minor.
|
|
func (v Version) atLeast(major, minor int) bool {
|
|
if v.Major != major {
|
|
return v.Major > major
|
|
}
|
|
return v.Minor >= minor
|
|
}
|
|
|
|
// String returns the raw version string as reported by the server.
|
|
func (v Version) String() string { return v.Raw }
|
|
|
|
// capsFor derives the capability set from a parsed version. Gates follow the
|
|
// introspection findings: dict settings and policies land at 0.9; the *2 service
|
|
// APIs and resetToDefaults are 1.x.
|
|
func capsFor(v Version) map[Capability]bool {
|
|
return map[Capability]bool{
|
|
DictZoneSettings: v.atLeast(0, 9),
|
|
Policies: v.atLeast(0, 9),
|
|
AddZone2: v.atLeast(0, 9),
|
|
ServiceSettings2: v.atLeast(1, 0),
|
|
ResetToDefaults: v.atLeast(1, 0),
|
|
}
|
|
}
|