diff --git a/DHCP.md b/DHCP.md
index 4df18f1..b12d424 100644
--- a/DHCP.md
+++ b/DHCP.md
@@ -38,101 +38,159 @@ below.
### The `dhcp.dhcpv4.options` Array Field
-The `options` field accepts four types of values: `hex`, `ip`, `ips`, and
-`text`. They all start with the `CODE`, which MUST be an integer in the [1,
-255] range. See also [RFC 2132, sec. 3][rfc-2132].
-
-In accordance with [RFC 2131, sec. 4.3.1][rfc-2131], these options override the
-default options' values set by Adguard Home and requested by a client. Which
-means that if you want to set DNS server addresses using option `6`, you should
+The `options` field is used to explicitly specify the values for DHCP options
+and modify the response. In accordance with *Section 4.3.1* of [RFC
+2131][rfc-2131], these options override the default options' values set by
+Adguard Home and requested by a client. Which means that if you want to set
+custom DNS server addresses using option `6` (Domain Name Server), you may want
also add Adguard Home's own addresses there. Otherwise, AdGuard Home's
filtering won't work for the DHCP clients who receive these DNS server
addresses.
-Option `del` has been added in **v0.107.12**. It is used to unconditionally
-remove options from the server's responses, which may lead to weird behaviors.
-Use with caution. On example where this option is useful is when a client
-doesn't accept a lease because of an option, see [issue 4337].
+Any option begins with an option *code* written as decimal integer. See [RFC
+2132][rfc-2132] for the actual DHCP option codes and allowed lengths. The code
+is followed by an option's *type* and *value*. Currently the following *types*
+are supported:
- * The `hex` format is:
+ * `bool` (since **v0.107.12**) accepts a human-readable form of a boolean
+ value, and has the length of 1 octet.
- ```
- CODE hex HEX_VALUE
- ```
-
- For example, to set option `6`, the DNS server, to two IP addresses,
- `1.2.3.4` and `1.2.3.5`, use:
+ For example:
```yaml
- # …
- 'dhcp':
- # …
- 'dhcpv4':
- # …
- 'options':
- - '6 hex 0102030401020305'
+ 'options':
+ - '19 bool 0' # Disable IP forwarding for hosts.
+ - '20 bool t' # Enable non-local source routing for hosts.
+ - '27 bool F' # Disable ahoming for hosts.
+ - '30 bool true' # Enable mask supplying for supporting hosts.
+ - '36 bool False' # Make the hosts use RFC 894 for ethernet encapsulation.
```
- * The `ip` format is:
+ * `del` (since **v0.107.12**) is a no-value option and is used to
+ unconditionally remove options from the server's responses (which may lead
+ to weird behaviors, use with caution).
- ```
- CODE ip IPV4_VALUE
- ```
-
- For example, to set option `6`, the DNS server, to one IP address,
- `1.2.3.4`, use:
+ Since the list of options is interpreted sequentially from first to last,
+ the subsequent option may override the previous ones. So this:
```yaml
- # …
- 'dhcp':
- # …
- 'dhcpv4':
- # …
- 'options':
- - '6 ip 1.2.3.4'
+ 'options':
+ - '19 bool T'
+ - '19 del'
+ - '20 del'
+ - '20 bool F'
```
- * The `ips` format (since **v0.106.0**) is the same, but with comma-separated
- IP-addresses:
+ instructs to remove the option `19`, and to set the option `20` to `false`.
+
+ * `dur` (since **v0.107.12**) accepts a human-readable form of a duration in
+ range [0 – 4294967296 seconds (about 136 days)] and has a length of *4*
+ octets, just like a 32-bit unsigned integer.
+
+ Here is the example of setting the MTU aging timeout to 10 minutes:
```yaml
- # …
- 'dhcp':
- # …
- 'dhcpv4':
- # …
- 'options':
- - '6 ips 1.2.3.4,5.6.7.8'
+ 'options':
+ - '24 dur 10m'
```
- * The `text` format (since **v0.106.0**) allows you to put arbitrary UTF-8
- text as the option data. For example:
+ * `hex` accepts a sequence of hexadecimal numbers of an arbitrary length.
+
+ Here is the example of setting the plateau table for path MTU timeouts:
```yaml
- # …
- 'dhcp':
- # …
- 'dhcpv4':
- # …
- 'options':
- - '252 text http://example.com'
+ 'options':
+ - '25 hex 0044012801FC03EE05D407D211001FE645FA'
```
- * The `del` format (since **v0.107.12**) allows you to remove an option. For
- example:
+ * `ip` accepts an IPv4 address and has a length of *4* octets, just like an
+ IPv4 itself.
+
+ Here is the example of setting a broadcast address option:
```yaml
- # …
- 'dhcp':
- # …
- 'dhcpv4':
- # …
- 'options':
- - '61 del'
+ 'options':
+ - '28 ip 192.168.0.255'
```
-[issue 4337]: https://github.com/adguardTeam/adGuardHome/issues/4337
+ * `ips` (since **v0.106.0**) accepts a comma-separated list if IPv4 addresses.
+ It has an arbitrary length, but is always a multiple of *4* octets.
+ Here is the example of setting the domain name servers to `1.2.3.4` and
+ `1.2.3.5`:
+
+ ```yaml
+ 'options':
+ - '6 ips 1.2.3.4,1.2.3.5'
+ ```
+
+ * `text` (since **v0.106.0**) accepts an arbitrary UTF-8 encoded string and
+ has a length of encoded text.
+
+ Here is the example of setting the path to configuration file for WPAD:
+
+ ```yaml
+ 'options':
+ - '252 text http://server.domain/proxyconfig.pac'
+ ```
+
+ * `u8` (since **v0.107.12**) accepts a decimal number in range [0 – 255] and
+ takes *1* octet, just like an unsigned 8-bit integer.
+
+ Here is the example of setting the TTL for Internet Protocol:
+
+ ```yaml
+ 'options':
+ - '23 u8 64'
+ ```
+
+ * `u16` (since **v0.107.12**) accepts a decimal number in range [0 – 65535]
+ and takes *2* octets, just like an unsigned 16-bit integer.
+
+ Here is the example of setting the maximum datagram reassembly size to 576
+ bytes:
+
+ ```yaml
+ 'options':
+ - '22 u16 576'
+ ```
+
+**NOTE:** Thoroughly check that the option format and value are valid for the
+chosen type in accordance with [RFC 2132][rfc-2132] or others. AdGuard Home does
+not perform any option-specific validations.
+
+Currently there is a set of options listed in *Appendix A* of [RFC
+2131][rfc-2131] with the default values chosen according to the documents
+mentioned there:
+
+| Option | Value |
+| -------------------------------- | --------------------------------------------- |
+| IP Forwarding | Disabled |
+| Non-Local Source Routing | Disabled |
+| Maximum Datagram Reassembly Size | 576 bytes |
+| Default IP Time-to-live | 64 seconds |
+| Path MTU Aging Timeout Option | 10 minutes |
+| Path MTU Plateau Table | See [Table 7.1 in RFC 1191][rfc-1191-tbl-7.1] |
+| Interface MTU | 576 bytes |
+| All subnets are local | False |
+| Perform Mask Discovery | False |
+| Mask Supplier | False |
+| Perform Router Discovery | True |
+| Router Solicitation Address | 224.0.0.2 |
+| Broadcast Address | 255.255.255.255 |
+| Use Trailer Encapsulation | False |
+| ARP Cache Timeout | 1 minute |
+| Ethernet Encapsulation version | RFC 894 |
+| Default TCP TTL | 60 seconds |
+| TCP Keepalive Interval | 2 hours |
+| Put TCP Keepalive Garbage | True |
+| Routers | `gateway_ip` from configuration |
+| Subnet Mask | `subnet_mask` from configuration |
+
+Some of these values may appear obsolete or may cause issues with some DHCP
+client implementations among the many existing. In accordance with [RFC
+2131][rfc-2131] the options, when not explicitly configured, are only returned
+if requested by client within the option `55` (Parameter Request List).
### DHCPv6 Options
@@ -143,9 +201,10 @@ clients to use SLAAC. The DHCPv6 server won't be started in this case.
The option `dhcp.dhcpv6.ra_allow_slaac`, if `true`, sends RA packets allowing
the clients to choose between SLAAC and DHCPv6.
-[configuration]: https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration
-[rfc-2131]: https://tools.ietf.org/html/rfc2131#page-29
-[rfc-2132]: https://tools.ietf.org/html/rfc2132#section-3
+[configuration]: https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration
+[rfc-1191-tbl-7.1]: https://datatracker.ietf.org/doc/html/rfc1191#section-7.1
+[rfc-2131]: https://datatracker.ietf.org/doc/html/rfc2131
+[rfc-2132]: https://datatracker.ietf.org/doc/html/rfc2132