commit adfc309ecfc5dba21968f487a6c389fd94987060
Author: Jelmer Vernooĳ <jelmer@jelmer.uk>
Date:   Sun May 21 18:46:53 2023 +0100

    Move files used in tests to crates/erbium-core

Index: erbium-core/erbium.conf.example
===================================================================
--- /dev/null
+++ erbium-core/erbium.conf.example
@@ -0,0 +1,133 @@
+##   Copyright 2021 Perry Lorier
+##
+##  Licensed under the Apache License, Version 2.0 (the "License");
+##  you may not use this file except in compliance with the License.
+##  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+##  Unless required by applicable law or agreed to in writing, software
+##  distributed under the License is distributed on an "AS IS" BASIS,
+##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+##  See the License for the specific language governing permissions and
+##  limitations under the License.
+##
+##  SPDX-License-Identifier: Apache-2.0
+##
+##
+## Example configuration for erbium
+##
+## See erbium.conf(5) for more details.
+
+### Minimal required to get running.
+
+## The addresses you want to hand out.
+## This becomes the default addresses for Router Advertisements (for v6) and DHCP (for v4).
+## Addresses will be assigned on interfaces that have an address that is included within the range.
+addresses: [192.0.2.0/24, 2001:db8::/64]
+
+## DNS routing for where to relay DNS queries.
+dns-routes:
+  # An empty domain suffix matches all.
+  - domain-suffixes: [""]
+    # Domains with this suffix should be forwarded
+    type: forward
+    # Forward to Google Public DNS.  Change this to relay elsewhere.
+    # Currently only one address is supported here, despite it being a list.
+    dns-servers: [8.8.8.8]
+  # Other routes are possible, the most specific suffix is used.
+  - domain-suffixes: ["invalid"]
+    # forge-nxdomain forges a "does not exist" for this and all subdomains.
+    type: forge-nxdomain
+
+### DNS search path
+## This is included in DHCP (for v4) and Router Advertisments DNSSL (for v6) by default.
+## This defaults to the empty list.
+# dns-search: [example.com, example.org]
+
+### DNS servers
+## This is the DNS servers included in DHCP (for v4) and Router Advertisements RDNSS (for v6) by default.
+## $self4 and $self6 are the v4 and v6 receiving addresses respectively.
+## This defaults to [$self4, $self6]
+# dns-servers: [$self4, $self6]
+
+### Listener addresses
+# api-listeners: ["/var/lib/erbium/control", "@erbium", "[::]:9968"]
+# dns-listeners: ["[::]:53"]
+## This lets you configure the default bind style.  Set this to "bind-interfaces-addresses" if you're having
+## problems with address already in use.
+# default-listen-style: bind-unspecified
+
+### ACLs
+## ACLs are a list of match rules, and permissions to apply if the match rule
+## succeeds.  First match wins.  If nothing matches, no permissions are granted.
+## See erbium.conf(5) for descriptions of the permissions.  If any ACLs are
+## specified, the defaults are overridden, so remember to include the other
+## entries if you want to change just one.
+#
+# acls:
+#  # Allow addresses we hand out to use our services (dns, http api)
+#  - match-subnets: [the-contents-of-the-top-level-addresses-field]
+#    apply-access: ["dns-recursion", "http-ro"]
+#  # Allow localhost/ip6-localhost to use our services
+#  - match-subnets: [127.0.0.0/8, ::1/128]
+#    apply-access: ["dns-recursion", "http-ro"]
+#  # Allow readonly access to the API server over the unix domain socket.
+#  - match-unix: true
+#    apply-access: ["http-ro"]
+
+### Router Advertisements
+## This lets you override the defaults for router advertisements.
+## You can use "null" to unset a default.
+# router-advertisements:
+#  # This is a list of interface names
+#  eth0:
+#    hop-limit: 64 # The hop limit to use on this interface
+#    managed: false # Should the client get an address from DHCPv6
+#    other: false # Should the client get other configuration from DHCPv6
+#    lifetime: 1h  # How long this router should be considered a viable default route
+#    reachable: 5m # How long a neighbour is considered reachable after comfirmation.
+#    mtu: 1480 # The Maximum Transfer Unit for this interface.
+#    dns-servers:
+#     addresses: [2001:4860:4860::8888]
+#     lifetime: 1h
+#    dns-search:
+#     domains: [custom.example.com]
+#     lifetime: 1h
+#    pref64:
+#     prefix: 64:ff9b::/96
+#     lifetime: 10m
+#    prefixes:
+#     - prefix: 2001:db8:0:1::/64
+#       on-link: true    # Can other hosts with this prefix be talked to
+#                        # directly, or should they go through the default gateway
+#       autonomous: true # Should hosts allocate themselves an address from this prefix.
+#       valid: 30d       # How long this prefix is valid for.
+#       preferred: 7d    # How long this prefix should be used as a preferred prefix.
+
+### DHCP policy
+## This lets you override and customise the DHCP configuration
+## First match wins.
+# dhcp-policies:
+#   - apply-ntp-servers: [192.0.2.123]
+#     policies:
+#       - match-subnet: 198.51.100.0/24
+#         apply-range:
+#           start: 198.51.100.100
+#           end: 198.51.100.199
+#         apply-routes:
+#           - prefix: 203.0.113.0/24
+#             next-hop: $self4
+#         policies:
+#         # This is an example of how to provide configuration per host, including static IPs
+#           - { match-hardware-address: 00:00:5E:00:53:01, apply-address: 198.51.100.110 }
+#           # This doesn't have a match, so won't apply to anything, but will reserve the address.
+#           # This is useful to reserve addresses for hosts that have static IP configuration.
+#           - { apply-address: 198.51.100.120 }
+#
+#       # This has no match block, so noone will be allocated this by default
+#       - apply-subnet: 203.0.113.0/24
+#         policies:
+#           # This policy has a match, but no addresses, so it will allocate an address out of the parent.
+#           - { match-hardware-address: 00:00:5E:00:53:F0 }
+
Index: erbium-core/man/erbium.conf.5
===================================================================
--- /dev/null
+++ erbium-core/man/erbium.conf.5
@@ -0,0 +1,538 @@
+.\"   Copyright 2023 Perry Lorier
+.\"
+.\"  Licensed under the Apache License, Version 2.0 (the "License");
+.\"  you may not use this file except in compliance with the License.
+.\"  You may obtain a copy of the License at
+.\"
+.\"      http://www.apache.org/licenses/LICENSE-2.0
+.\"
+.\"  Unless required by applicable law or agreed to in writing, software
+.\"  distributed under the License is distributed on an "AS IS" BASIS,
+.\"  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\"  See the License for the specific language governing permissions and
+.\"  limitations under the License.
+.\"
+.\"  SPDX-License-Identifier: Apache-2.0
+.TH erbium.conf 5 2022-05-30 Linux "File formats and configuration files"
+.SH NAME
+erbium.conf \- Configuration for erbium
+.SH DESCRIPTION
+erbium is a daemon that provides network services for small/home networks.
+erbium.conf provides configuration for \fBerbium\fP\fR(8)\fP.
+.PP
+erbium.conf is in YAML format, and involves multiple sections.
+
+.SS Executable Configuration
+If erbium.conf is not executable, then erbium will read the file directly for
+configuration.
+
+If erbium.conf is executable, then erbium will execute the configuration file,
+and expect a valid erbium configuration on standard output.  This allows for
+generating erbium configurations at runtime via whatever custom tooling is
+appropriate for your environment (eg shellscript, python script, ELF binary
+etc).  This tooling could provide templating or whatever functionality is
+needed for the local environment.
+
+.SS Configuration wide options
+IP addresses can be specified as the string $self4 or $self6 which will use the
+local IPv4 or IPv6 address of the interface the request arrived on
+respectively.
+
+.SS Top level Configuration
+The top level configuration provides defaults for the other protocol
+implementations in erbium.
+For most networks, only the top level configuration is necessary, but for more
+advanced users per protocol configuration can be used to override these
+defaults (or disable them by setting their value to \fBnull\fP.
+Top level configuration is not required, you can instead configure each
+protocol individually, it is provided as a convenience measure.
+
+.IP "\fBaddresses:\fP \fIlist-of-subnets\fP"
+(defaults to no value)
+This provides both the list of interfaces to configure for router
+advertisements and DHCP, and the IP ranges to give out.
+The subnets must match exactly the subnets on the inteface (including the prefix length),
+and the network address.
+For DHCP this will give out addresses on this interface except for the network
+address, broadcast address, and the local interface IPv4 address.
+DHCP will also exclude any address given in a normal policy, in the same way
+that sub policies work below.
+For router advertisements, this will configure the IPv6 prefix for SLAAC
+addressing.
+
+.IP "\fBdns-servers:\fP \fIlist-of-ip-addresses\fP"
+(defaults to no value)
+This sets the default dns servers to be handed out by DHCP and Router
+Advertisements.
+DHCP is limited by the design of the protocol to only support
+handing out IPv4 addresses.
+Similarly router advertisements are limited by design to only support handing
+out IPv6 addresses.
+
+.IP "\fBdns-search:\fP \fIlist-of-domain-names\fP"
+(defaults to no value)
+This sets the default DNS search path.
+This is supported by both the DHCP and router advertisements protocols.
+
+.IP "\fBcaptive\-portal:\fP \fIurl\fP"
+(defaults to no value)
+This sets the URL to the captive portal, as specified in RFC8910.
+This is used by both DHCP and router advertisements.
+
+.IP "\fBdefault-listen-style\fP \fBbind-unspecified\fP|\fBbind-addresses-interfaces\fP"
+(defaults to bind-unspecified)
+This sets the default bind style for DNS and DHCP requests.
+.RS
+.IP \fBbind-unspecified\fP
+This binds to the unspecified address (0.0.0.0 or [::]).
+This means that interfaces do not need to be fully operational when erbium
+starts.
+Erbium will discard packets that have no matching configuration.
+This is the default.
+.IP \fBbind-addresses-interfaces\fP
+This binds to addresses that are configured on interfaces that are within the prefixes listed in the "addresses" field.
+This allows erbium to share a machine with systemd-resolved or other DNS/DHCP servers that are used for other
+interfaces.
+This however has the downside that the interfaces must be up and fully configured before erbium can start, which can
+cause race conditions with dynamic addressing systems and duplicate address detection.
+.RE
+.IP "\fBapi\-listeners:\fP \fIlist\-of\-socket\-addresses\fP"
+(defaults to [/var/lib/erbium/control])
+This sets the addresses that the API HTTP server will listen on.
+By default this is only a unix domain socket, which can be easily secured.
+IPv4 (ip:port) and IPv6 ([ip]:port) are also supported.
+You may wish to use ["/var/lib/erbium/control", "[::1]:9968"] to allow scraping
+prometheus metrics from ip6-localhost.
+
+.IP "\fBacls:\fP \fIarray-of-acls\fP"
+(default see the ACLs section below)
+This introduces the array of ACLs.
+
+.SS DHCP Configuration
+
+DHCP configuration for erbium is under a \fBdhcp-policies\fP heading.
+\fBdhcp-policies\fP is a a list of policies to apply to incoming
+DHCP packets.
+Each policy is considered in turn, with the first policy that successfully
+matches being the policy that is applied.
+.PP
+A policy section contains 0 or more \fBmatch\-\fP\fIcondition\fP fields, and 0
+or more \fBapply\-\fP\fIoption\fP fields.
+.SS DHCP Matches
+All match conditions in a policy must match (the conditions are AND'd together).
+A policy section that contains no matches only matches if one of it's
+subpolicies matches.  (See below for information about subpolicies).
+.\"
+.IP "\fBmatch\-subnet:\fP \fIcidr4\-prefix/len\fP"
+\fBmatch\-subnet\fP is how the DHCP standards expect you to match incoming
+packets.  When a DHCP packet from a client is received, then the IP address of
+the interface where it is received is noted, and can be matched with
+\fBmatch-subnet\fP.  This works even for packets that are relayed, in which
+case the IP address of the relay is used.
+
+An example is: \fBmatch-subnet: 192.168.0.0/24\fP.
+.IP "\fBmatch\-hardware\-address:\fP \fIhardware\-address\fP"
+Clients send a "client hardware address" (chaddr) in DHCP request packets.
+This allows matching on that address.
+This is most useful when matching on individual hosts to assign them a static address.
+.\"
+.IP "\fBmatch\-\fP\fIdhcpoption\fP\fB:\fP \fIoption\-value\fP"
+For every DHCP option supported by erbium, you can match on it by prefixing
+its name with \fBmatch-\fP.  Note that most DHCP clients do not send many
+options, so in practise there isn't much you can match on here.  Some obvious
+and useful options for matching on are \fBmatch-host-name\fP and
+\fBmatch-class-id\fP.
+
+erbium will log options received from each client to make finding useful
+options to match on easier.
+If you specify \fBnull\fP as the value to match on, then it will only match
+if the client \fIdoes not\fP provide that option.
+.SS Applying DHCP Options
+Each policy contains a list of option values to apply to a client (assuming the
+client requested the option).  For nested subpolicies (see below), options
+are applied for the outer policies first, then the subpolicies can choose to
+override those values.
+.IP "\fBapply\-address:\fP \fIip4addr\fP"
+This adds one IP address to the pool for the policy.
+This can be provided multiple times to add multiple individual IP addresses to
+a pool, and then the client will be assigned one.
+.IP "\fBapply\-subnet:\fP \fIcidr4\-prefix/len\fP"
+This adds an entire subnet worth of addresses to the address pool for the
+policy.
+This can be provided multiple times to add multiple subnets.
+The first and last addresses of the subnet are not applied, as these are the
+network and broadcast addresses respectively.
+.IP "\fBapply\-range: { start:\fP \fIstart-ip4\fP\fB, end:\fP \fIlast-ip4\fP\fB}\fR"
+This applies a range of IP addresses, from \fIstart-ip4\fP to \fIlast-ip4\fP inclusive.
+This is a YAML hash type, with the keys "start" and "end".
+The text above shows this using YAML's single line syntax, but it can be in any
+of YAML's formats for a hash.
+.IP "\fBapply\-\fP\fIoption\fP\fB:\fP \fIvalue\fP"
+This lets you apply an arbitrary value for a DHCP option.
+The syntax for the values varies based on the option.
+(See a list of options and their types below).
+You can also set an option to \fBnull\fP to unset it (if, for example, the
+value was inherited in a sub policy, or to override erbium's internal defaults
+for a value).
+.\"
+.SS Subpolicies
+As well as having match and apply rules for each policy, a policy can also
+contain subpolicies.
+A subpolicy is only attempted to be matched if all the enclosing policies
+matched.
+Sub\-policies have their own DHCP IP pools.
+If you add an IP address to a policy then it will be excluded from all parent
+pools.
+Thus you can have an outer policy that contains a "apply\-subnet:
+192.0.2.0/24", then have a subpolicy for
+that matches an individual host that contains only "apply\-address: 192.0.2.53",
+and that address will only be given to the individual host.
+(See the example below).
+A policy that does not specify an new addresses will continue to use the
+addresses for it's parent pool.
+(Again, see example below).
+Sub\-policies are introduced by adding a \fBpolicies:\fP section to a policy.
+.\"
+.SH DHCP Options
+.TS
+allbox tab(,);
+nllll.
+Num,Option name,Type,Ref,Description
+1,netmask,ip4,RFC2131,The netmask for this network.
+2,time-offset,seconds,RFC2131,The current timezone offset in seconds.
+3,routers,ip4 list,RFC2131,List of default gateways.
+4,time-servers,ip4 list,RFC2131,List of time servers.
+5,name-servers,ip4 list,RFC2131,List of IEN-116 name servers.
+6,dns-servers,ip4 list,RFC2131,List of DNS servers for recursive resolution.
+7,log-servers,ip4 list,RFC2131,List of MIT-LCS UDP log servers (obsolete).
+8,quote-servers,ip4 list,RFC2131,List of quote of the day servers (RFC865).
+9,lpr-servers,ip4 list,RFC2131,List of LPR print servers.
+12,hostname,string,RFC2131,Hostname of the client.
+15,domain-name,string,RFC2131,Domain name of the client.
+19,forward,boolean,RFC2131,If the client should enable IP forwarding.
+22,max-reassembly,seconds,RFC2131,How long to wait for IP fragment reassembly.
+23,default-ttl,integer,RFC2131,The default TTL.
+24,mtu-timeout,integer,RFC2131,How long to cache MTU path discovery for.
+26,mtu,integer,RFC2131,The MTU the client should use.
+27,mtu-subnet,integer,RFC2131,The MTU for the local subnet.
+28,broadcast,ip4,RFC2131,The broadcast address of the local subnet.
+35,arp-timeout,integer,RFC2131,ARP cache timeout.
+42,ntp-servers,ip4 list,RFC2131,A list of NTP servers to use.
+69,smtp-servers,ip4 list,RFC2131,A list of SMTP servers to use.
+70,pop3-servers,ip4 list,RFC2131,A list of POP3 servers to use.
+71,nntp-servers,ip4 list,RFC2131,A list of NNTP servers to use.
+77,user-class,string,RFC2131,A user configurable class.
+80,fqdn,string,RFC2131,The fully qualified domain name of the client.
+100,tz-rule,string,RFC4833,The POSIX complaint timezone rule specification.
+101,tz-name,string,RFC4833,A tzdata timezone name.
+114,captive-portal,string,RFC8910,The URL for a captive portal.
+121,routes,routes,RFC3442,A list of static routes.
+.TE
+.PP
+(Note more options than this exist, but I ran out of time writing these docs.
+Patches updating and extending this list based on src/dhcp/dhcppkt.rs
+appreciated)
+.PP
+The different types are expected to be:
+.IP \fIstring\fP
+A simple string in any of YAMLs string formats.
+.IP \fIinteger\fP
+An integer, in any of YAMLs integer formats.
+.IP \fIip4\fP
+An IPv4 address.  eg: 192.0.2.0
+This can also be the keyword $self4.
+.IP "\fIip4 list\fP"
+A YAML list of IPv4 addresses.
+This list can also contain the keyword $self4.
+eg: [$self4, 192.0.2.1, 192.0.2.2].
+.IP \fIseconds\fP
+This can be an integer number of seconds (in any of YAMLs integer formats), or it can be a string with numbers
+suffixed with "s" (for seconds), "m" (for minutes), "h" (for hours), or "d" (for days).
+Multiple units can be combined, and if the unit is left off it is assumed to be
+seconds.
+For example "4h20m5" is considered to be 4 hours, 20 minutes, and 5 seconds
+(which is the same as the number 15605).
+.IP "\fIhardware address\fP"
+This is specified as a colon (:) separated list of hexadecimal octets.  For example: 00:00:5E:00:53:00.
+.IP "\fIroutes\fP"
+Routes are specified with a prefix and nexthop. eg: { prefix: 192.0.2.0/24, next-hop: 192.0.2.254 }
+.\"
+.SH Router Advertisement Configuration
+Router Advertisements can be configured in erbium under a \fBrouter-advertisements\fP section.
+This should be a yaml hash of interfaces, keyed by the interface name, and the
+value being a a yaml hash with some keywords configuring the announcements for
+an interface.
+.IP "\fBhop-limit:\fP \fIinteger\fP"
+(default 0)
+Set the hop limit for hosts on this network.
+If set to 0 or null, then it will not set that information.
+.IP "\fBmanaged:\fP \fIboolean\fP"
+(default false)
+Configures the "Managed address configuration" bit, configuring
+if hosts on this network should use DHCPv6 to get an address.
+(Hosts ignore this if the "Other" bit is set)
+.IP "\fBother:\fP \fIboolean\fP"
+(default false)
+Configures the "Other configuration" bit.
+This tells the hosts on this network that there is more configuration available
+via DHCPv6.
+(Hosts ignore this if the "managed" bit is set)
+.IP "\fBlifetime:\fP \fIduration\fP"
+(default 0s if there is no default route or if the default route points back
+out the same interface, 1h otherwise)
+This configures the "Router Lifetime".
+This configures how long this host should be considered a default router.
+Setting this to 0 means that the erbium host is not a default router.
+.IP "\fBreachable:\fP \fIduration\fP"
+(default 0ms)
+This configures the "Reachable Time" for hosts on the network.
+This is how long a host on the local network should consider a host reachable
+after having confirmation of reachability.
+Setting this to 0 means that this is not specified by this router.
+.IP "\fBretransmit:\fP \fIduration\fP"
+(default 0ms)
+This configures the "Retrans Timer" for hosts on the network.
+The time between retransmitted Neighbor Solicitation messages.
+Setting this to 0 means that this is not specified by this router.
+.IP "\fBmtu:\fP \fImtu\fP"
+(defaults to the MTU of the interface)
+This configures the MTU of the link.
+This can be set to \fBnull\fP so that this router will not specify this.
+.IP "\fBcaptive-portal:\fP \fIurl\fP"
+(defaults to \fBcaptive-portal\fP in the top level configuration)
+This configures a URL to the captive portal (RFC7710).
+This can be set to \fBnull\fP so that this router will not specify this.
+.IP "\fBdns-servers:\fP"
+(defaults based on \fBdns-servers\fP in the top level configuration)
+hash configuring the recusive DNS servers,
+.RS
+.IP "\fBaddresses:\fP \fIlist-of-ipv6-addresses\fP"
+(defaults to the IPv6 addresses listed in the \fBdns-servers\fP top level
+configuration)
+This sets the IPv6 addresses for the router addresses.
+It is possible to use $self6 here to refer to the local interface address.
+.IP "\fBlifetime:\fP \fIduration\fP"
+(defaults to the setting of the interface lifetime)
+This sets the amount of time that the recursive DNS servers addresses are
+valid.
+.RE
+.\"
+.IP "\fBdns-search:\fP"
+(hash configuring the DNS search list)
+.RS
+.IP "\fBdomains:\fP \fIlist-of-domain-suffixes\fP"
+(defaults to the domains listed in the top level \fBdns-search\fI
+configuration)
+This sets the ordered list of domain suffixes that should be tried.
+.IP "\fBlifetime:\fP \fIduration\fP"
+(defaults to the setting of the interface lifetime)
+This sets the amount of time that the DNS search list domain suffixes are
+valid.
+.RE
+.\"
+.IP "\fBpref64:\fP"
+(a hash configuring the NAT64 prefix range used by this network)
+.RS
+.IP "\fBprefix:\fP \fIip6-prefix\fP"
+(defaults to none)
+This configures the NAT64 prefix used by this network.
+.IP "\fBlifetime:\fP \fIduration\fP"
+(defaults to 10 minutes)
+This configures how long the NAT64 prefix is valid for.
+.RE
+.\"
+.IP "\fBprefixes:\fP"
+(list of hash configuring addresses)
+.RS
+.IP "\fBprefix:\fP \fIcidr6-prefix/len\fP"
+(defaults to no prefix)
+This configures a prefix to be announced in router advertisement.
+.IP "\fBon-link:\fP \fIboolean\fP"
+(defaults to true)
+This configures if all addresses in this prefix are considered "on link".
+.IP "\fBautonomous:\fP \fIboolean\fP"
+(defaults to true)
+This configures if hosts should autonomously configure one or more addresses
+from this prefix.
+.IP "\fBvalid:\fP \fIduration\fP"
+(defaults to 30 days)
+This configures how long this prefix is considered valid and usable.
+.IP "\fBpreferred:\fP \fIduration\fP"
+(defaults to 7 days)
+The duration that addresses generated from the prefix via stateless address
+autoconfiguration remain preferred, and should be used for new connections.
+.RE
+.SH DNS Configuration
+.IP "\fBdns\-listeners:\fP \fIlist-of-socket-addresses\fP"
+(defaults to [::]:53 if default-listen-style is bind-unspecified, otherwise the interface addresses listed in addresses)
+This configures which addresses the DNS server will listen on.
+.IP "\fBdns\-routes:\fP \fIlist-of-dns-routes\fP"
+(defaults to the empty list)
+This is a list of DNS routes.
+.RS
+.IP "\fBdomain\-suffixes:\fP \fIlist-of-domain-suffixes\fP"
+(defaults to the empty list)
+This is the list of domain suffixes that this route should apply to.
+This will match this domain, and all sub\-domains.
+For example "example.com" matches "foo.example.com" and "example.com" but not "example.net".
+The longest suffix match wins.
+Use the empty string "" to use this as a default match.
+.IP "\fBtype:\fP \fIforward\fP|\fIforge-nxdomain\fP"
+(defaults to forward)
+This configures what to do with domain names that end in this suffix.
+.RS
+.IP forward
+This is used to forward queries that desire recursion to another set of nameservers.
+.IP forge-nxdomain
+This will forge a NXDOMAIN reply for this, and all subdomains.
+.RE
+.IP "\fBdns-servers:\fP \fIlist-of-socket-addresses\fP"
+(defaults to the empty list)
+Only used by type "forward".
+This specifies the nameservers that the queries should be forwarded to.
+.RE
+.SH ACLs (Access Control Lists)
+To change which clients can do what, erbium has a customisable ACL system.
+ACLs are defined under the heading "acls:" at the top level, and are an ordered list of rules of which clients this
+particular ACL applies to, and what access this client has.
+ACLs are applied in a strict first-match basis.
+Any client that does not match any ACL will not be granted any access.
+
+.IP "\fBmatch-subnets:\fP \fIarray-of-subnets\fP"
+If specified, this requires that the access granted by this ACL applies only to clients that have a source
+address that matches one of subnets provided.
+If not specified, then the source address is not matched.
+.IP "\fBmatch-unix:\fP \fIboolean\fP"
+If specified, this requires that the access granted by this ACL applies only to clients over a unix domain socket (if
+true), otherwise must not be a unix domain socket (if false).
+If not specified, then if the client arrives over a unix domain socket is not matched.
+.IP "\fBapply-access:\fP \fIarray-of-access-strings\fP"
+(default: empty list)
+This specifies which accesses the matched clients are permitted.
+.RS
+.IP "\fBdhcp-client\fP"
+Permissions required for DHCP clients with default settings.
+This is used to support future versions that may add additional protocols for DHCP clients.
+Currently an alias for "dns-recursion".
+.IP "\fBdns-recursion\fP"
+Allows DNS recursion.
+.IP "\fBhttp\fP"
+Allows access to the non-API parts of the HTTP server.
+.IP "\fBhttp-metrics\fP"
+Allows access to the /metrics endpoint of the HTTP server.
+.IP "\fBhttp-leases\fP"
+Allows access to the list of active leases over HTTP.
+.IP "\fBhttp-ro\fP"
+An alias for "http-metrics" and "http-leases".
+This is used to support future versions that may add additional read only HTTP end points that users can use
+to collect information.
+By using "http-ro" instead of "http-metrics" and "http-leases" independently, as new accesses are added then
+this configuration will include them.
+.RE
+
+If you specify any ACLs then all the defaults are overridden and need to be specified.
+The defaults for ACLs are as follows:
+.EX
+acls:
+ # Allow DHCP clients to perform DNS queries, and talk to the HTTP API server (if enabled)
+ - match-subnets: [\fIthe-contents-of-the-top-level-addresses-field\fP]
+   apply-access: ["dns-recursion", "http-ro"]
+ # Allow localhost to perform DNS queries, any talk to the HTTP API server (if enabled)
+ - match-subnets: [127.0.0.0/8, ::1/128]
+   apply-access: ["dns-recursion", "http-ro"]
+ # Allow all users via Unix domain sockets to talk to the HTTP API server (if enabled)
+ - match-unix: true
+   apply-access: ["http-ro"]
+.EE
+
+.SH EXAMPLE
+.EX
+dns-servers: [$self4, $self6, 8.8.8.8, 2001:4860:4860::8888]
+dns-search: [example.com, example.org]
+addresses: [192.0.2.0/24, 2001:db8::/64]
+dhcp-policies:
+  - apply-ntp-servers: [192.0.2.123]
+
+    policies:
+     - match-subnet: 198.51.100.0/24
+       apply-range:
+         start: 198.51.100.100
+         end: 198.51.100.199
+       apply-routes:
+        - prefix: 203.0.113.0/24
+          next-hop: $self4
+       policies:
+        - { match-hardware-address: 00:00:5E:00:53:01, apply-address: 198.51.100.110, apply-dns-servers: null }
+        - { match-hardware-address: 00:00:5E:00:53:02, apply-address: 198.51.100.111, apply-dns-servers: [8.8.8.8] }
+
+     - apply-subnet: 203.0.113.0/24
+       policies:
+        - { match-hardware-address: 00:00:5E:00:53:F0 }
+        - { match-hardware-address: 00:00:5E:00:53:F1 }
+
+router-advertisements:
+ eth1:
+   lifetime: 30m
+   prefixes:
+    - prefix: 2001:db8:0:1::/64
+   dns-servers:
+    addresses: [2001:db8::53]
+
+dns-routes:
+  - domain-suffixes: [""]
+    type: forward
+    dns-servers: [2001:4860:4860::8888]
+.EE
+.PP
+Imagine a router with 3 interfaces.
+.IP eth0
+This has the addresses 192.0.2.254/24, and 2001:db8::1/64.
+.IP eth1
+This has the addresses 198.51.100.254/24, and 2001:db8:0:1::1/64.
+.IP eth2
+This has the address 203.0.113.254/24.
+.PP
+A client on eth0 will be assigned an IP out of the range 192.0.2.1 to 192.0.2.253
+(192.0.2.0 being the network address, 192.0.2.254 being in use by the local
+interface, and 192.0.2.255 being the broadcast address, all are excluded).
+.PP
+A client on eth1 with the mac address 00:00:5E:00:53:01 on eth1 will
+get given the IP address 198.51.100.110 (and no other).
+It will not be given any DNS servers (overriding the top level configuration),
+.PP
+A client on eth1 with the mac address 00:00:5E:00:53:02 on will get given the
+IP address 198.51.100.111.
+It will get assigned only 8.8.8.8 as the DNS server address.
+.PP
+Other clients on eth1 will get assigned an IPv4 address between 198.51.100.100
+and 198.51.100.200, but not 198.51.100.110 or 198.51.100.111, as these are
+reserved in a subpolicy.
+Other clients will get 192.0.2.254 and 8.8.8.8 as IPv4 DNS servers (Inherited
+from the top level configuration, IPv6 addresses filtered out).
+.PP
+On eth2, only the two hosts 00:00:5E:00:53:F0 and 00:00:5E:00:53:F1 will be
+allocated addresses between 203.0.113.1 and 203.0.113.254 (as the default
+allocated addresses is calculated from the match-address directive).
+.PP
+All IPv4 clients on all interfaces will get assigned the NTP server
+192.0.2.123.
+.PP
+Despite there being no explicit router configuration section for eth0, clients
+with IPv6 on eth0 will allocate themselves an address in 2001:db8::/64, due to
+addresses matching this interface being configured at the top level.
+They will have 2001:db8::1 and 2001:4860:4860::8888 as their DNS servers (again
+inherited from the top level), and a dns search path of example.com and example.org.
+.PP
+Clients with IPv6 on eth1 will allocate themselves an address in 2001:db8:0:1:/64, and
+will use the DNS server 2001:db8::53.
+.SH FILES
+erbium.conf
+.SH BUGS
+erbium is currently under active development, and many important features and protocols are not yet complete, or even
+implemented yet.
+.SH SEE ALSO
+.BR erbium.conf (5),
+.BR erbium-dns (8),
+.BR erbium-dhcp (8),
+.BR erbium-conftest (8)
+
Index: erbium-core/src/test_man_configs.rs
===================================================================
--- erbium-core.orig/src/test_man_configs.rs
+++ erbium-core/src/test_man_configs.rs
@@ -5,7 +5,7 @@ use tokio;
  * run the config parser over them to make sure they're valid.
  */
 async fn man_page_example_configs() {
-    let contents = include_str!("../../../man/erbium.conf.5");
+    let contents = include_str!("../man/erbium.conf.5");
     let mut example: String = Default::default();
     let mut in_example = false;
     let mut examples = 0;
@@ -33,7 +33,7 @@ async fn man_page_example_configs() {
 
 #[tokio::test]
 async fn validate_example_config() {
-    let mut contents = include_str!("../../../erbium.conf.example").to_string();
+    let mut contents = include_str!("../erbium.conf.example").to_string();
     // If the line is indented, replace the "#" with a " ", keeping the indentation.
     contents = contents.replace("\n#  ", "\n  ");
     // If the line is not indented, then strip the leading "# "
