From 296dd39d2e1827c556e057b6b55555e31a587a80 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Tue, 5 Jul 2022 04:46:11 +0200 Subject: [PATCH] docs(meta): Describe settings --- README.md | 110 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e27b447..ed0b614 100644 --- a/README.md +++ b/README.md @@ -108,35 +108,109 @@ If a packet has traversed rules this far without being accepted it will be dropp In `[DEFAULT]` section the following settings are called globals. They're only valid in `[DEFAULT]` context. Adding them to a custom `[section]` (see [Locals](#locals) below) won't do anything, in a custom `[section]` the following settings are ignored. -* `do_config_check`, __*optional*__, defaults to `true`: Do a `firewall-cmd --check-config` once before changing `/etc/firewalld/direct.xml`. Abort if this initial check fails, inform the user. Obviously something's very wrong before we've even touched firewall configs. Otherwise back up `/etc/firewalld/direct.xml`, change it then do another check. If `firewall-cmd --check-config` finds a syntax error restore the backed up known good `/etc/firewalld/direct.xml`, delete the temporary backed up one and inform the user. - - If `restart_firewalld_after_change` is also `true` (default) restart the `firewalld` systemd service unit after the second config check. See steps __*a*__ through __*f*__ below at `restart_firewalld_after_change` for exact order. +* `firewalld_direct_file_abs`, __*optional*__, defaults to `/etc/firewalld/direct.xml`: Location of `firewalld`'s direct rules file. This is where new XML rule content is written. * `restart_firewalld_after_change`, __*optional*__, defaults to `true`: After putting a new `/etc/firewalld/direct.xml` file in place restart the `firewalld` systemd service unit. - * If `do_config_check` is also `true` (default) the exact order is: - 1. Config check, bail on error and inform user - 2. Back up `/etc/firewalld/direct.xml` to temporary location - 3. Write new `/etc/firewalld/direct.xml` content - 4. Perform config check, bail on error and restore backed up `/etc/firewalld/direct.xml` - 5. Delete backed up `/etc/firewalld/direct.xml` - 6. Restart `firewalld` systemd service unit - * If `do_config_check` is `false`: - 1. Write new `/etc/firewalld/direct.xml` content - 2. Restart `firewalld` systemd service unit ### Locals -A custom `[section]` has the following options. We're calling the locals all of which are optional. +A custom `[section]` has the following options. We're calling them locals most of which are optional. -* `target`, __*optional*__, defaults to `ACCEPT`: A string specifying the fate of a packet that matched this rule. By default matching packets are accepted. See "TARGETS" section in [iptables man page](https://ipset.netfilter.org/iptables.man.html). You'll most likely want to stick to either `ACCEPT` or `DROP`. +* `target`, __*mandatory*__, defaults to `ACCEPT`, can be any valid `iptables` target. Must not be empty nor unset. A string specifying the fate of a packet that matched this rule. See "TARGETS" section in [iptables man page](https://ipset.netfilter.org/iptables.man.html). You're most likely going to want to stick to either `ACCEPT` or `DROP`. By default matching packets are accepted. We do not do our own validation of what you write here. By default (see [Globals](#globals)) `do_config_check` equals to true in which case we let `firewalld` do a config check to catch nonsense rules. -* `addr`, __*optional*__: A comma-separated list of any combination of IPv4 addresses, IPv6 addresses and domain names. When `update-firewall-source.py` constructs `firewalld` rules these addresses are allowed to access the server. If left undefined `addr` defaults to an empty list meaning rules apply to any arbitrary source address. +* `addr`, __*optional*__, defaults to an empty string: A comma-separated list of any combination of IPv4 addresses, IPv6 addresses and domain names. When `update-firewall-source.py` constructs `firewalld` rules these addresses are allowed to access the server. If left undefined `addr` defaults to an empty list meaning rules apply to any and all source address. Subnets are unsupported, both as subnet masks (`142.251.36.195/255.255.255.248`) and in [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) notation (`142.251.36.195/29`). Do not single- nor double-quote list entries. Do feel free to separate entries with comma-space instead of just a comma. -* `ports`, __*optional*__, defaults to `80, 443`: A comma-separated list of ports that should be accessible from `addr`. If overwritten to an empty option `addr` may access all ports. +* `ports`, __*optional*__, defaults to `80, 443`: A comma-separated list of ports that should be accessible from `addr`. If empty `addr` may access all ports. See [iptables-extensions man page, section "multiport"](https://ipset.netfilter.org/iptables-extensions.man.html#lbBM) for syntax reference. All port-based rules use `iptables ... --match multiport` even if you're only allowing access to a single port. In essence construct your ports list with any combination of single ports (`80, 443, 8080`) and port ranges (`6660:7000, 61000:65535`). -* `proto`, __*optional*__, defaults to `tcp`: A protocol that should be allowed for `addr` on `ports`. If undefined this defaults to `tcp` being allowed. Since `firewalld` direct rules use `iptables` syntax the list of possible protocol names is largely identical to what the [iptables man page](https://ipset.netfilter.org/iptables.man.html) says about its `--protocol` argument: + ``` + # Valid example: + ports = 80, 443, 6660:7000, 8080 + ``` + +* `proto`, __*optional*__, defaults to `tcp`: A singular protocol that should be allowed for `addr` on `ports`. Can be set to an empty value in which case all protocols are allowed. Since `firewalld` direct rules use `iptables` syntax the list of possible protocol names is largely identical to what the [iptables man page](https://ipset.netfilter.org/iptables.man.html) says about its `--protocol` argument: > The specified protocol can be one of `tcp`, `udp`, `udplite`, `icmp`, `icmpv6`, `esp`, `ah`, `sctp`, `mh` or the special keyword `all`, or it can be a numeric value, representing one of these protocols or a different one. A protocol name from `/etc/protocols` is also allowed. A `!` argument before the protocol inverts the test. The number zero is equivalent to `all`. Your mileage may vary depending on which specific OS flavor and version you're running. + + **Implementation details:** + * `proto` is treated as a string, not a list. To for example allow access via both TCP and UDP create two `[sections]` like so: + ``` + [tcp-rule] + addr = 1.1.1.1 + ports = + proto = tcp + + [udp-rule] + addr = 1.1.1.1 + ports = + proto = udp + ``` + Since `proto = tcp` is default you can leave it out of the top section. Side note, in this specific example you would want to set the `[DEFAULT]` value `ports =` instead of repeating it in each `[section]`. Alternatively set `proto =` to allow all protocols in which case a single `[section]` is enough to cover that use case: + ``` + [permit-port-53-via-all-protocols] + addr = 1.1.1.1 + ports = + proto = + ``` + Make sure that when `proto` is unset you also unset `ports`. See next bullet point for details on that. + + * Unsetting `proto` while at the same time leaving at least one `ports` value in place (which is the default with `ports = 80, 443`) is an error. + + It will result in a rule that `firewalld` cannot load into `ip(6)tables`. It will report it as such in its systemd journal visible e.g. via `journalctl -fu firewalld.service`. This is because having at least one port configured will always result in adding a `--match multiport` which is only valid when also giving a `--protocol` such as `--protocol tcp`. + + ``` + [DEFAULT] + ports = 80, 443 + proto = tcp + + [valid] + addr = example.net + ports = 22, 80, 443 + + [invalid] + addr = example.com + proto = + + # Without 'ports' there will be no '--match multiport' + # and without /that/ you can safely unset 'proto': + [also-valid] + addr = example.org + ports = + proto = + ``` + +* `state`, __*optional*__, defaults to `NEW`: Comma-separated list of connection tracking states against which a packet is matched. Most of the time your rules will want to use the default `NEW`. The final `DROP` rule present in the example `config.ini` file at [examples/config.ini.example](examples/config.ini.example) is one occasion where you'll want to deviate and unset `state` to an empty value. See ["state" extension man page in iptables docs](https://ipset.netfilter.org/iptables-extensions.man.html#lbCC) for reference. + +* `do_ipv6`, __*optional*__, defaults to `false`: Decide if you want `firewalld` to generate `ip6tables` rules in addition to `iptables` rules. A default install of Docker Engine will have its IPv6 support disabled in `/etc/docker/daemon.json` in which case `ip6tables` will not have a `DOCKER-USER` or similar Docker-related chains. In this default setup having `update-firewall-source.py` generate an otherwise unused `DOCKER-USER` chain and adding rules to it clutters your rule set. Consider setting this to `true` if and when your Docker install uses IPv6. + + If this is `true` IPv6 addresses found or resolved in `addr` in a `[section]` will be discarded. + +# Development + +## Conventional Commits + +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary). + +### Scopes + +The following **_scopes_** are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none: + +* `config`: Structure or content of a `config.ini` file +* `dbus`: Deals with functionality to restart the `firewalld.service` unit +* `systemd`: Deals with lifecycle as a systemd unit +* `meta`: Affects the project's repo layout, readme content, file names etc. +* `dns`: Resolution of DNS records +* `xml`: XML content handling for `firewalld` direct rules, includes segues into `ip(6)tables` territory +* `netdev`: Network devices +* `debug`: Deals with debuggability, concise messages to end user + +### Types + +The following **_types_** are known for this project in addition to Conventional Commits default types `fix` and `feat`. A Conventional Commits commit message must use either one of the two default types or optionally a type from this list: + +* `build`: Project structure, directory layout, build instructions for roll-out +* `refactor`: Keeping functionality while streamlining or otherwise improving function flow +* `test`: Working on test coverage +* `docs`: Documentation for project or components