When the firewall key wasn't present in the network device
configuration of a guest, the firewall defaulted to on instead of off.
Since the UI omitted the firewall setting in the API calls when it is
unchecked, there was no way for the firewall to be turned off for a
specific network device of a guest with the firewall enabled.
Since the whole section didn't even properly parse the property string
via the existing proxmox-schema facilities, also refactor the whole
property string parsing logic while we're at it. This is done by
splitting the network configuration structs into different ones for
LXC and QEMU and then using those to deserialize the PropertyString.
There is also a slight breakage for callers utilizing NetworkDevice,
since it now returns owned values instead of references, which makes
life easier and is okay since the values all implement Copy.
At this time pve-api-types isn't packaged yet, but as soon as it is we
can use the API schemas generated from pve-api-types instead of
manually creating our own subset schema.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Tested-by: Hannes Laimer <h.laimer@proxmox.com>
Reviewed-by: Hannes Laimer <h.laimer@proxmox.com>
Some macros only contained rules for ICMP echo requests, but not their
ICMPv6 counterparts. Add them, so they work properly with IPv6 setups.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Tested-by: Hannes Laimer <h.laimer@proxmox.com>
Link: https://lore.proxmox.com/20250204095733.55146-2-s.hanreich@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Macros containing rules for the ICMP protocol used dport instead of
icmp-type for specifying the type of ICMP messages. This is how
pve-firewall used to specify them, but the nftables firewall uses a
separate key for this in the macros. This caused all ICMP types to be
allowed instead of restricting them to the types specified in the
macro.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Tested-by: Hannes Laimer <h.laimer@proxmox.com>
Link: https://lore.proxmox.com/20250204095733.55146-1-s.hanreich@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
.. as newly introduced with 1.84.
Namely `elided_named_lifetimes` for the change of `SdnConfig` and
`clippy::needless_lifetimes` for the rest.
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Alias and AliasName represent two different parts inside a firewall
configuration. Document the respective structs better to make the
differences between them clearer.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
pve-firewall lowercases the names of aliases when reading from the
configuration as well as when comparing source / destination entries
with the entries in the parsed aliases. In order to stay
backwards-compatible we also need to lowercase any parsed alias name.
I decided to this in the constructor and switch all call sites to the
new constructor, so there's only one place where we have to handle
lowercasing the string.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Add tests for validating the directions in the guest firewall
configuration. While I'm at it, I also added tests for validating
interface names, since this functionality did not get tested before.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
We introduce a new type of firewall config file that can be used for
defining rules on bridge-level, similar to the existing
cluster/host/vm configuration files.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Tested-by: Hannes Dürr <h.duerr@proxmox.com>
This direction will be used for specifying rules on bridge-level
firewalls as well as rules on the cluster / host level that are for
forwarded network packets.
Since with the introduction of this direction not every type of
firewall configuration can contain all types of directions, we
additionally add validation logic to the parser, so rules with an
invalid direction get rejected by the parser.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Tested-by: Hannes Dürr <h.duerr@proxmox.com>
We generate the following ipsets for every vnet in the running sdn
configuration:
* {vnet}-all: contains all subnets of the vnet
* {vnet}-no-gateway: contains all subnets of the vnet except for all
gateways
* {vnet}-gateway: contains all gateways in the vnet
* {vnet}-dhcp: contains all dhcp ranges configured in the vnet
All of them are in the new SDN scope, so the fully qualified name
would look something like this: `+sdn/{vnet-all}`.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Similar to how the IPAM module works, we separate the internal
representation from the concrete schema of the configuration file.
We provide structs for parsing the running SDN configuration and a
struct that is used internally for representing an SDN configuration,
as well as a method for converting the running configuration to the
internal representation.
This is necessary because there are two possible sources for the SDN
configuration: The running configuration as well as the SectionConfig
that contains possible changes from the UI, that have not yet been
applied.
Simlarly to the IPAM, enforcing the invariants the way we currently do
adds some runtime complexity when building the object, but we get the
upside of never being able to construct an invalid struct. For the
amount of entries the sdn config usually has, this should be fine.
Should it turn out to be not performant enough we could always add a
HashSet for looking up values and speeding up the validation. For now,
I wanted to avoid the additional complexity.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
For every guest that has at least one entry in the IPAM we generate an
ipset with the name `+sdn/guest-ipam-{vmid}`. The ipset contains all
IPs from all zones for a guest with {vmid}.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
This module includes structs for representing the JSON schema from the
PVE ipam. Those can be used to parse the current IPAM state.
We also include a general Ipam struct, and provide a method for
converting the PVE IPAM to the general struct. The idea behind this
is that we have multiple IPAM plugins in PVE and will likely add
support for importing them in the future. With the split, we can have
our dedicated structs for representing the different data formats from
the different IPAM plugins and then convert them into a common
representation that can then be used internally, decoupling the
concrete plugin from the code using the IPAM configuration.
Enforcing the invariants the way we currently do adds a bit of runtime
complexity when building the object, but we get the upside of never
being able to construct an invalid struct. For the amount of entries
the ipam usually has, this should be fine. Should it turn out to be
not performant enough we could always add a HashSet for looking up
values and speeding up the validation. For now, I wanted to avoid the
additional complexity.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Almost every type should implement them anyway, and many of them are
required for those types to be used in BTreeMaps, which the nftables
firewall uses for generating stable output.
Additionally, we derive Serialize and Deserialize for a few types that
occur in the sdn configuration. The following patches will use those
for (de-)serialization.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
This is mainly used in proxmox-perl-rs, so the generated ipsets can be
used in pve-firewall where only CIDRs are supported.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
A range can be used to store multiple IP addresses in an ipset that do
not neatly fit into a single CIDR.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Currently we are using tuples to represent IP ranges which is
suboptimal. Validation logic and invariant checking needs to happen at
every site using the IP range rather than having a unified struct for
enforcing those invariants.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Since we now have a standalone repository for Proxmox VE related
crates, add the required files for packaging the crates contained in
this repository.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
We support any as wildcard for matching all icmp types. Implement
parsing logic for parsing the any value and support converting the any
value into an nftables expression.
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Max Carrara <m.carrara@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Since the basic format of cluster, host and guest firewall
configurations is the same, we create a generic parser that can handle
the common config format. The main difference is in the available
options, which can be passed via a generic parameter.
Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Max Carrara <m.carrara@proxmox.com>
Additionally we implement FromStr for all rule types and parts, which
can be used for parsing firewall config rules. Initial rule parsing
works by parsing the different options into a HashMap and only then
de-serializing a struct from the parsed options.
This intermediate step makes rule parsing a lot easier, since we can
reuse the deserialization logic from serde. Also, we can split the
parsing/deserialization logic from the validation logic.
Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Max Carrara <m.carrara@proxmox.com>
Currently this is parsing the config files via the filesystem. In the
future we could also get this information from pmxcfs directly via
IPC which should be more performant, particularly for a large number
of VMs.
Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Max Carrara <m.carrara@proxmox.com>
Currently the helpers for obtaining the host network configuration
panic on error, which could be avoided by the use of
OnceLock::get_or_init, but this method is currently only available in
nightly versions.
Generally, if there is a problem with obtaining the network config for
the node I would deem it acceptable for now, since that would usually
mean something is amiss with the network configuration and a firewall
won't really do anything then anyway.
Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Max Carrara <m.carrara@proxmox.com>