DHCPv6 Server
Sub-menu: /ipv6/dhcp-server
Standards: RFC 8415
The DHCPv6 server delegates IPv6 prefixes (DHCPv6-PD) and assigns IPv6 addresses to clients. It is typically used by a router that hands out prefixes to downstream routers, for example to the customer routers of an ISP. The server takes prefixes from the IPv6 pool set in prefix-pool, and addresses from the IPv6 pool set in address-pool, which must have a prefix length of 128. Bindings can also be static, or assigned by a RADIUS server.
Each binding is identified by the client's DUID and IAID. When a client is bound to a prefix, the server adds a dynamic route to that prefix through the client (route-distance), so traffic for the delegated prefix reaches the client router.
Most hosts only request addresses with DHCPv6 when the router advertisements on their network have the managed flag set, as shown in the address delegation example that follows. RouterOS uses the same DUID for its DHCPv6 server and client. For how DHCPv6 works, see DHCP concepts.
Configuration Example
Enabling IPv6 Prefix delegation
Let's consider that we already have a running DHCP server.
To enable IPv6 prefix delegation, first, we need to create an address pool:
/ipv6/pool/add name=myPool prefix=2001:db8:7501::/60 prefix-length=62
Notice that prefix-length is 62 bits, which means that clients will receive /62 prefixes from the /60 pool.
The next step is to enable DHCP-PD:
/ipv6/dhcp-server/add name=myServer prefix-pool=myPool interface=local
To test our server we will set up wide-dhcpv6 on an Ubuntu machine:
- Install wide-dhcpv6-client.
- Edit "/etc/wide-dhcpv6/dhcp6c.conf" as above.
You can also use RouterOS as a DHCP-PD client.
interface eth2{
send ia-pd 0;
};
id-assoc pd {
prefix-interface eth3{
sla-id 1;
sla-len 2;
};
};
- Run DHCP-PD client.
sudo dhcp6c -d -D -f eth2
- Verify that the prefix was added to the:
mrz@bumba:/media/aaa$ ip -6 addr
...
2: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2001:db8:7501:1:200:ff:fe00:0/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::224:1dff:fe17:81f7/64 scope link
valid_lft forever preferred_lft forever
- You can make the binding to a specific client static so that it always receives the same prefix.
[admin@RB493G] /ipv6/dhcp-server/binding> print
Flags: X - disabled, D - dynamic
# ADDRESS DU IAID SER.. STATUS
0 D 2001:db8:7501::/62 16 0 loc.. bound
[admin@RB493G] /ipv6/dhcp-server/binding> make-static 0
- DHCP-PD also installs a route to the assigned prefix into the IPv6 routing table:
[admin@RB493G] /ipv6/route> print
Flags: X - disabled, A - active, D - dynamic, C - connect, S - static, r - rip, o - ospf, b - bgp, U - unreachable
# DST-ADDRESS GATEWAY DISTANCE
...
2 ADS 2001:db8:7501::/62 fe80::224:1dff:fe17:8... 1
Enabling IPv6 Address delegation
Address delegation on the DHCPv6 server side works almost in the exact same way as when you configure a prefix server. The only difference is that you must specify in the configuration address-pool instead of prefix-pool and the pool used for this server must be defined to use /128 prefix-length. Of course, you can create a server which only assigns static addresses and skip using the pool.
[admin@MikroTik] > /ipv6/pool/print detail
Flags: D - dynamic
0 name="myAddressPool" prefix=2001:db8:7501::/120 prefix-length=128
[admin@MikroTik] > /ipv6/dhcp-server/print detail
Flags: D - dynamic; X - disabled, I - invalid
0 name="myDHCP" interface=ether2 prefix-pool=static-only
address-pool=myAddressPool lease-time=3d rapid-commit=yes use-radius=no
preference=255 dhcp-option="" route-distance=1 use-reconfigure=no
address-lists="" duid="0x00030001b813f4840556"
This configuration is already enough to work with DHCPv6 clients such as, for example, a RouterOS client.
[admin@MikroTik] > /ipv6/dhcp-client/print detail
Flags: D - dynamic; X - disabled, I - invalid
0 interface=ether2 status=bound duid="0x00030001b123f48407f0"
dhcp-server-v6=fe80::ba69:f4af:fe14:558 request=
add-default-route=no use-peer-dns=yes allow-reconfigure=no
dhcp-options="" pool-name="" pool-prefix-length=64 prefix-hint=::/0
prefix-address-lists="" dhcp-options=""
address=2001:db8:7501::, 2d23h59m51s
However, usually end-devices such as computers do not know if their network is managed by a DHCP server or not. That is why DHCPv6 server configuration is combined with SLAAC functionality. You can even avoid using SLAAC in order to advertise a prefix for local network devices, all you need to do is advertise the "managed-address-configuration" option to your network devices.
[admin@MikroTik] > /ipv6/nd/print detail
Flags: X - disabled, I - invalid; * - default
0 interface=ether2 ra-interval=3m20s-10m ra-delay=3s mtu=unspecified
reachable-time=unspecified retransmit-interval=unspecified
ra-lifetime=30m ra-preference=medium hop-limit=unspecified
advertise-mac-address=yes advertise-dns=yes
managed-address-configuration=yes other-configuration=no
[admin@MikroTik] > /ipv6/nd/prefix/print detail
Flags: X - disabled, I - invalid; D - dynamic
0 prefix=::/64 6to4-interface=none interface=ether2 on-link=yes
autonomous=yes valid-lifetime=4w2d preferred-lifetime=1w
Now, for example, your computer which will be connected to the router ether2 interface will receive an advertisement message from RouterOS ND configuration stating that this network is using "managed-address-configuration" which normally on end user devices will enable a DHCPv6 client requesting an IPv6 address.
Full configuration backup from the server with several comments is provided here.
#Address pool to be used for 'bridge', must have prefix-length 128
/ipv6/pool
add name=myLocalLan prefix=2001:db8::/100 prefix-length=128
#DHCPv6 server with spcified 'address' pool
/ipv6/dhcp-server
add address-pool=myLocalLan interface= name=myLocalServer prefix-pool=""
#We must 'advertise' that this is managed network so LAN devices use DHCPv6 clients
#RFC 4861, RFC 4862, RFC 8415 'M - Managed address configuration'
/ipv6/nd
add interface= managed-address-configuration=yes
#We must enable advertising on our 'bridge' interface
#We can even add interface without specified prefix, because we here need only
#to advertise 'option' that tells this is managed network
/ipv6/nd/prefix
add interface=
Server configuration might vary based on operating systems used by clients. For example, macOS will get an address on initialisation with such configuration but might not renew the lease after sleep, if the prefix is set to "none", since macOS does not use DHCPv6 client without a SLAAC address. Other clients might also need the "autonomous" option to be set to "no" in order to trigger DHCPv6 client usage. This is just a configuration example - settings might need adjustments depending on client devices.
DHCPv6 Server Properties
| Property | Description |
|---|---|
| address-pool (enum | static-only; Default: static-only) | IPv6 pool, from which to take an IPv6 address for the clients, pool prefix-length must be specified as /128. |
| prefix-pool (enum | static-only; Default: static-only) | IPv6 pool, from which to take IPv6 prefixes for the clients. |
| add-dns-entries (yes | no; Default: no) | When set to yes, the DHCPv6 server creates dynamic DNS entries for its bindings, using the hostname the client sends in the Client FQDN option (option 39). If add-dns-entries-suffix is set, it is appended to the hostname. |
| add-dns-entries-suffix (string; Default: "") | Suffix appended to the client hostname when creating dynamic DNS entries. Used only when add-dns-entries is set to yes. For example, if set to example.lan and the client hostname is laptop, the DNS entry laptop.example.lan will be created. When set, the server also includes the Client FQDN option (option 39) in its replies. |
| allow-dual-stack-queue (yes | no; Default: yes) | Creates a single simple queue entry for both IPv4 and IPv6 addresses, and uses the MAC address and DUID for identification. Requires IPv6 DHCP Server to have this option enabled as well to work properly. |
| address-lists (string; Default: ) | Comma-separated list of address lists. The address or prefix issued by the server will be added to these lists. A binding's own address-lists setting overrides this. |
| binding-script (string; Default: ) | A script that will be executed after binding is assigned or de-assigned. Internal "global" variables that can be used in the script:
|
| dhcp-option (string; Default: none) | Adds additional DHCPv6 options from the DHCPv6 option list (/ipv6/dhcp-server/option). |
| insert-queue-before (bottom | first | name; Default: first) | Specifies where to place dynamic simple queue entries for static DHCP leases with a rate-limit parameter set. |
| parent-queue (string | none; Default: none) | A dynamically created queue for this lease will be configured as a child queue of the specified parent queue. |
| preference (integer [0..255]; Default: 255) | Defines the server priority level in client selection when multiple servers respond. |
| disabled (yes | no; Default: no) | Whether the DHCP-PD server participates in the prefix assignment process. |
| interface (string; Default: ) | The interface on which the server will be running. |
| lease-time (time; Default: 3d) | The time that a client may use the assigned address. The client will try to renew this address after half of this time and will request a new address after the time limit expires. |
| rapid-commit (yes | no; Default: yes) | Enables a two-message exchange (Solicit and Reply) for quicker client configuration by skipping the standard four-message process. |
| route-distance (integer [0..255]; Default: 1) | Specifies the distance to set for dynamically installed routes towards DHCPv6 clients. |
| use-radius (yes | no | accounting; Default: no) | Whether to use a RADIUS server:
|
| use-reconfigure (yes | no; Default: no) | Allows the server to send Reconfigure messages to clients, prompting them to renew or update their configuration without waiting for their lease to expire. |
| name (string; Default: ) | Reference name |
| ignore-ia-na-bindings (yes | no; Default: no) | Does not reply to DHCPv6 address requests and processes only prefixes. Without this setting, even if the server does not have address-pool configured, it has to respond to the client that there is no address available for the client. That can lead to the situation when DHCPv6 client requests address and prefix in a loop. |
Read-only Properties
| Property | Description |
|---|---|
| dynamic (yes | no) | Whether the server was created dynamically. |
| invalid (yes | no) | Shows whether the configuration is invalid. |
Bindings
Sub-menu: /ipv6/dhcp-server/binding
DUID is used only for dynamic bindings, so if it changes then the client will receive a different prefix than previously.
| Property | Description |
|---|---|
| address (IPv6 prefix; Default: ) | IPv6 prefix that will be assigned to the client |
| allow-dual-stack-queue (yes | no; Default: yes) | Creates a single simple queue entry for both IPv4 and IPv6 addresses, uses the MAC address and DUID for identification. Requires IPv4 DHCP Server to have this option enabled as well to work properly. |
| comment (string; Default: ) | Short description of an item. |
| disabled (yes | no; Default: no) | Whether an item is disabled |
| dhcp-option (string; Default: ) | Adds additional DHCP options from the option list. |
| life-time (time; Default: 3d) | The time period after which binding expires. |
| duid (hex string; Default: ) | DUID value. Should be specified only in hexadecimal format. |
| iaid (integer [0..4294967295]; Default: ) | Identity Association Identifier, part of the Client ID. |
| prefix-pool (string; Default: ) | Prefix pool that is being advertised to the DHCPv6 Client. |
| rate-limit (integer[/integer] [integer[/integer] [integer[/integer] [integer[/integer]]]]; Default: ) | Adds a dynamic simple queue to limit IP's bandwidth to a specified rate. Requires the lease to be static. Format is: rx-rate[/tx-rate] [rx-burst-rate[/tx-burst-rate] [rx-burst-threshold[/tx-burst-threshold] [rx-burst-time[/tx-burst-time]]]]. All rates should be numbers with optional 'k' (1,000s) or 'M' (1,000,000s). If tx-rate is not specified, rx-rate is used as tx-rate too. Same goes for tx-burst-rate and tx-burst-threshold and tx-burst-time. If both rx-burst-threshold and tx-burst-threshold are not specified (but burst-rate is specified), rx-rate and tx-rate are used as burst thresholds. If both rx-burst-time and tx-burst-time are not specified, 1s is used as default. |
| server (string | all; Default: all) | Name of the server. If set to all, then binding applies to all created DHCP-PD servers. |
| ia-type (na | pd; Default: ) | Type of the identity association:
|
| address-lists (string; Default: ) | Address lists to which the bound address or prefix will be added. Overrides the address-lists setting of the server. |
| insert-queue-before (bottom | first | name; Default: first) | Specifies where to place the dynamic simple queue entry created for this binding when rate-limit is set. |
| parent-queue (string | none; Default: none) | A dynamically created queue for this binding will be configured as a child queue of the specified parent queue. |
| queue-type (string; Default: ) | Queue type used for the dynamic simple queue created for this binding. |
Read-only properties
| Property | Description |
|---|---|
| dynamic (yes | no) | Whether an item is dynamically created. |
| expires-after (time) | The time period after which binding expires. |
| last-seen (time) | Time period since the client was last seen. |
| status (waiting | offered | bound) | Three status values are possible:
|
| reconfigure-key (string) | Reconfiguration authentication key |
| reconfigure-last-sent (integer) | Count of sent Reconfigure (forcerenew) messages |
| reconfigure-status (string) | Status of the Reconfigure exchange with the client. |
| active-server (string) | Name of the server that is serving this binding. |
| client-address (IPv6 address) | IPv6 address of the client, the source address of its DHCPv6 messages. |
For example, dynamically assigned /62 prefix
[admin@RB493G] /ipv6/dhcp-server/binding> print detail
Flags: X - disabled, D - dynamic
0 D address=2001:db8:7501:ff00::/62 duid="1605fcb400241d1781f7" iaid=0
server=local-dhcp life-time=3d status=bound expires-after=2d23h40m10s
last-seen=19m50s
1 D address=2001:db8:7501:ff04::/62 duid="0019d1393535" iaid=2
server=local-dhcp life-time=3d status=bound expires-after=2d23h43m47s
last-seen=16m13s
Menu specific commands
| Property | Description |
|---|---|
| make-static (id) | Set dynamic binding as static. |
| send-reconfigure (id) | Send a Reconfigure (forcerenew) message |
Rate limiting
It is possible to set the bandwidth to a specific IPv6 address by using DHCPv6 bindings. This can be done by setting a rate limit on the DHCPv6 binding itself, by doing this, a dynamic simple queue rule will be added for the IPv6 address that corresponds to the DHCPv6 binding. By using the rate-limit parameter you can conveniently limit a user's bandwidth.
For any queues to work properly, the traffic must not be FastTracked, make sure your Firewall does not FastTrack traffic that you want to limit.
First, make the DHCPv6 binding static; otherwise, it will not be possible to set a rate limit to a DHCPv6 binding:
[admin@MikroTik] > /ipv6/dhcp-server/binding/print
Flags: X - disabled, D - dynamic
# ADDRESS DUID SERVER STATUS
0 D fdb4:4de7:a3f8:418c::/66 0x6c3b6b7c413e DHCPv6_Server bound
[admin@MikroTik] > /ipv6/dhcp-server/binding/make-static 0
[admin@MikroTik] > /ipv6/dhcp-server/binding/print
Flags: X - disabled, D - dynamic
# ADDRESS DUID SERVER STATUS
0 fdb4:4de7:a3f8:418c::/66 0x6c3b6b7c413e DHCPv6_Server bound
Then you can set a rate to a DHCPv6 binding that will create a new dynamic simple queue entry:
[admin@MikroTik] > /ipv6/dhcp-server/binding/set 0 rate-limit=10M/10M
[admin@MikroTik] > /queue/simple/print
Flags: X - disabled, I - invalid, D - dynamic
0 D name="dhcp<6c3b6b7c413e fdb4:4de7:a3f8:418c::/66>" target=fdb4:4de7:a3f8:418c::/66 parent=none packet-marks="" priority=8/8
queue=default-small/default-small limit-at=10M/10M max-limit=10M/10M burst-limit=0/0 burst-threshold=0/0 burst-time=0s/0s
bucket-size=0.1/0.1
By default allow-dual-stack-queue is enabled; this will add a single dynamic simple queue entry for both DHCPv6 binding and DHCPv4 lease. Without this option enabled, separate dynamic simple queue entries will be added for IPv6 and IPv4.
If allow-dual-stack-queue is enabled, then a single dynamic simple queue entry will be created containing both IPv4 and IPv6 addresses:
[admin@MikroTik] > /queue/simple/print
Flags: X - disabled, I - invalid, D - dynamic
0 D name="dhcp-ds<6C:3B:6B:7C:41:3E>" target=192.168.1.200/32,fdb4:4de7:a3f8:418c::/66 parent=none packet-marks="" priority=8/8
queue=default-small/default-small limit-at=10M/10M max-limit=10M/10M burst-limit=0/0 burst-threshold=0/0 burst-time=0s/0s
bucket-size=0.1/0.1
RADIUS Support
Since RouterOS v6.43 it is possible to use RADIUS to assign a rate-limit per DHCPv6 binding. To do so you need to pass the Mikrotik-Rate-Limit attribute from your RADIUS Server for your DHCPv6 binding. To achieve this you first need to set your DHCPv6 Server to use RADIUS for assigning bindings. Below is an example of how to set it up:
/radius
add address=10.0.0.1 secret=VERYsecret123 service=dhcp
/ipv6/dhcp-server
set dhcp1 use-radius=yes
After that, you need to tell your RADIUS Server to pass the Mikrotik-Rate-Limit attribute. In case you are using FreeRADIUS with MySQL, then you need to add appropriate entries into radcheck and radreply tables for a MAC address that is being used for your DHCPv6 Client. Below is an example for table entries:
INSERT INTO `radcheck` (`username`, `attribute`, `op`, `value`) VALUES
('000c4200d464', 'Auth-Type', ':=', 'Accept');
INSERT INTO `radreply` (`username`, `attribute`, `op`, `value`) VALUES
('000c4200d464', 'Delegated-IPv6-Prefix', '=', 'fdb4:4de7:a3f8:418c::/66'),
('000c4200d464', 'Mikrotik-Rate-Limit', '=', '10M');
By default allow-dual-stack-queue is enabled and will add a single dynamic queue entry if the MAC address from the IPv4 lease (or DUID, if the DHCPv4 Client supports Node-specific Client Identifiers from RFC4361), but DUID from DHCPv6 Client is not always based on the MAC address from the interface on which the DHCPv6 client is running, DUID is generated on a per-device basis. For this reason, a single dynamic queue entry might not be created, separate dynamic queue entries might be created instead.