DHCP Server Scripts, BOOTP Support, and Lease Logging
DHCP Server Scripts, BOOTP Support, and Lease Logging
Section titled “DHCP Server Scripts, BOOTP Support, and Lease Logging”RouterOS DHCP server can run a script on every lease event, enabling automation such as dynamic queue creation, firewall address-list management, and external webhook notifications. This guide also covers BOOTP client support, lease event logging, and integrating DHCP lease data with network discovery.
For custom DHCP option definitions, option sets, vendor-class matchers, and PXE boot configuration, see Custom DHCP Options, PXE Boot, and Vendor Option Sets.
DHCP Lease Scripts
Section titled “DHCP Lease Scripts”How Lease Scripts Work
Section titled “How Lease Scripts Work”The lease-script property on a DHCP server names a RouterOS script (or inline
code) that runs after each lease is assigned or de-assigned. RouterOS injects
a set of read-only environment variables into the script scope that describe the
event.
Attach a script to a DHCP server:
/ip dhcp-server set [find name=dhcp1] lease-script=my-lease-scriptOr set inline code directly:
/ip dhcp-server set [find name=dhcp1] \ lease-script=":log info (\"bound=\".\$leaseBound.\" ip=\".\$leaseActIP)"Script Variables
Section titled “Script Variables”| Variable | Type | Description |
|---|---|---|
$leaseBound | "1" / "0" | "1" when lease is being assigned; "0" on release or expiry |
$leaseServerName | string | Name of the DHCP server that fired the event |
$leaseActIP | string | IP address assigned to the client |
$leaseActMAC | string | Client MAC address |
$lease-hostname | string | Client-provided hostname (option 12), empty if not sent |
$lease-options | array | Array of option codes received from the client |
$lease-agent-circuit-id | string | Option 82 circuit-id (set by relay agent, empty otherwise) |
$lease-agent-remote-id | string | Option 82 remote-id (set by relay agent, empty otherwise) |
Variable names with hyphens: Variables like
$lease-hostnamerequire the$"lease-hostname"syntax in RouterOS scripting when referenced in expressions. Use$leaseActIPand$leaseActMACdirectly (no quotes needed).
The $leaseBound variable is always "1" or "0" as a string, not an
integer. Compare it with "1" or "0" accordingly.
Example: Logging Lease Events
Section titled “Example: Logging Lease Events”The simplest lease script logs every bind and release to the system log:
# /system script/system script add name=dhcp-log-events source={ :local ip $leaseActIP :local mac $leaseActMAC :local host $"lease-hostname" :if ($leaseBound = "1") do={ :log info ("DHCP bound ip=" . $ip . " mac=" . $mac . " host=" . $host) } else={ :log warning ("DHCP released ip=" . $ip . " mac=" . $mac . " host=" . $host) }}
/ip dhcp-server set [find name=dhcp1] lease-script=dhcp-log-eventsWatch events in real time:
/log print follow where topics~"dhcp"Example: Dynamic Queue per Client
Section titled “Example: Dynamic Queue per Client”Create a simple queue when a client connects, and remove it on disconnect.
This approach is suitable for per-host rate limiting when static lease
rate-limit is not sufficient (for example, when limits vary based on external
logic).
Note: For static per-host rate limiting, the built-in
rate-limitfield on a static DHCP lease is simpler and does not require a script.
/system script add name=dhcp-queue-manager source={ :local qname ("client-" . $leaseActMAC) :if ($leaseBound = "1") do={ # Create queue on first bind; skip if already exists :if ([:len [/queue simple find where name=$qname]] = 0) do={ /queue simple add \ name=$qname \ target=($leaseActIP . "/32") \ max-limit=10M/10M \ comment=$leaseActMAC } } else={ /queue simple remove [find where name=$qname] }}
/ip dhcp-server set [find name=dhcp1] lease-script=dhcp-queue-managerExample: Firewall Address-List Management
Section titled “Example: Firewall Address-List Management”Automatically populate a firewall address list with active DHCP clients:
/system script add name=dhcp-address-list source={ :if ($leaseBound = "1") do={ /ip firewall address-list add \ list=dhcp-active \ address=$leaseActIP \ comment=$leaseActMAC } else={ /ip firewall address-list remove \ [find where list=dhcp-active and address=$leaseActIP] }}
/ip dhcp-server set [find name=dhcp1] lease-script=dhcp-address-listUse the address list in firewall rules to, for example, allow internet access only to DHCP-bound clients:
/ip firewall filter add chain=forward action=accept \ src-address-list=dhcp-active comment="Allow DHCP clients"Example: Webhook on Lease Event
Section titled “Example: Webhook on Lease Event”Notify an external system via HTTP when a client binds. The fetch command
runs asynchronously from the script context:
/system script add name=dhcp-webhook source={ :if ($leaseBound = "1") do={ /tool fetch \ url=("https://nms.example.net/dhcp?" \ . "ip=" . $leaseActIP \ . "&mac=" . $leaseActMAC \ . "&host=" . $"lease-hostname") \ keep-result=no }}
/ip dhcp-server set [find name=dhcp1] lease-script=dhcp-webhookExample: Using Option 82 Variables
Section titled “Example: Using Option 82 Variables”When DHCP relay inserts Option 82, the circuit-id and remote-id are available in scripts. This is useful in carrier or ISP environments to identify the subscriber’s physical port:
/system script add name=dhcp-option82-log source={ :local circuit $"lease-agent-circuit-id" :local remote $"lease-agent-remote-id" :if ($leaseBound = "1") do={ :log info ("DHCP bound ip=" . $leaseActIP \ . " circuit=" . $circuit \ . " remote=" . $remote) }}Debugging Lease Scripts
Section titled “Debugging Lease Scripts”If a lease script silently fails, add a :log warning at the top and monitor
the system log. Script errors (syntax, missing variables) appear in the log
under the script topic:
# Temporarily increase log verbosity for scripts/system logging add topics=script action=memory
# Watch for script errors/log print follow where topics~"script"
# Also watch DHCP topic/log print follow where topics~"dhcp"Test your script manually by creating a temporary scheduler trigger or running
it via /system script run with variables set in the script itself for
validation.
BOOTP Support
Section titled “BOOTP Support”BOOTP (Bootstrap Protocol) is the predecessor to DHCP. Some legacy devices (embedded controllers, older network printers, some PXE clients) send BOOTP requests instead of DHCP DISCOVER messages. RouterOS handles both protocols on the same UDP port 67.
Configuration
Section titled “Configuration”Two server properties control BOOTP behavior:
| Property | Default | Description |
|---|---|---|
bootp-support | static | Which BOOTP clients receive responses |
bootp-lease-time | forever | Lease duration offered to BOOTP clients |
bootp-support values:
| Value | Behavior |
|---|---|
none | Ignore all BOOTP requests |
static | Respond only if a static lease matches the client MAC |
dynamic | Respond with both static and dynamic address assignments |
bootp-lease-time values:
| Value | Behavior |
|---|---|
forever | Lease never expires (BOOTP semantics) |
lease-time | Use the server’s configured lease-time |
<time> | Fixed duration (e.g., 1d, 12h) |
Disable BOOTP
Section titled “Disable BOOTP”To reject all BOOTP clients and serve only DHCP:
/ip dhcp-server set [find name=dhcp1] bootp-support=noneStatic-Only BOOTP
Section titled “Static-Only BOOTP”Allow BOOTP only for pre-mapped devices. Create a static lease for each BOOTP
device’s MAC address, then set bootp-support=static:
# Static lease for a BOOTP device/ip dhcp-server lease add \ mac-address=00:11:22:33:44:55 \ address=192.168.88.50 \ comment="Legacy BOOTP printer"
# Restrict BOOTP to static mappings only/ip dhcp-server set [find name=dhcp1] \ bootp-support=static \ bootp-lease-time=foreverWith bootp-lease-time=forever, the device retains its address indefinitely
without renewal. This matches traditional BOOTP behavior where there is no
lease refresh mechanism.
Dynamic BOOTP
Section titled “Dynamic BOOTP”Allow unrecognized BOOTP clients to receive an address from the pool:
/ip dhcp-server set [find name=dhcp1] \ bootp-support=dynamic \ bootp-lease-time=lease-timeUsing bootp-lease-time=lease-time causes BOOTP clients to receive the same
expiry time as DHCP clients, but since BOOTP has no renewal mechanism, the
address will remain assigned as long as no other client claims it.
Lease Logging
Section titled “Lease Logging”System Log Topics
Section titled “System Log Topics”RouterOS DHCP server emits log messages under the dhcp topic for normal
operation. Debug-level messages (option parsing errors, packet details) appear
under dhcp,debug.
View active DHCP log messages:
/log print where topics~"dhcp"Follow lease events in real time:
/log print follow where topics~"dhcp"Send DHCP Logs to Remote Syslog
Section titled “Send DHCP Logs to Remote Syslog”Create a logging action targeting your syslog server, then attach it to the
dhcp topic:
/system logging actionadd name=dhcp-syslog \ target=remote \ remote=192.0.2.10 \ remote-port=514 \ bsd-syslog=yes \ syslog-facility=daemon \ syslog-severity=info
/system loggingadd topics=dhcp action=dhcp-syslogadd topics=dhcp,debug action=dhcp-syslogLog DHCP Events to a File
Section titled “Log DHCP Events to a File”For local retention and post-processing, log DHCP events to a rotating file:
/system logging actionadd name=dhcp-file \ target=disk \ disk-file-name=dhcp-leases \ disk-lines-per-file=10000 \ disk-file-count=5
/system loggingadd topics=dhcp action=dhcp-fileFiles are written to the router’s flash storage and are accessible via
/file print or FTP/SCP export.
Structured Lease History via Script
Section titled “Structured Lease History via Script”The DHCP lease table shows current state but does not maintain history. For
persistent, structured lease history, write events from the lease-script:
/system script add name=dhcp-history source={ :local ts [/system clock get time] :local dt [/system clock get date] :local event :if ($leaseBound = "1") do={ :set event "BOUND" } else={ :set event "RELEASED" } :local line ($dt . " " . $ts . " " . $event \ . " ip=" . $leaseActIP \ . " mac=" . $leaseActMAC \ . " host=" . $"lease-hostname" \ . " srv=" . $leaseServerName) :log info $line # Optionally append to a file (requires /file manipulation or export)}Tip: For high-volume environments (hundreds of leases/hour), prefer remote syslog with a dedicated log management system over file-based logging on the router.
Network Discovery Integration
Section titled “Network Discovery Integration”ARP-Based Client Visibility (add-arp)
Section titled “ARP-Based Client Visibility (add-arp)”By default, DHCP leases do not automatically create ARP entries. Enable
add-arp on the DHCP server to create dynamic ARP entries for each active
lease:
/ip dhcp-server set [find name=dhcp1] add-arp=yesWith add-arp=yes, each bound lease appears in /ip arp:
/ip arp print# Example output:# Flags: X - disabled, I - invalid, H - DHCP, D - dynamic# # ADDRESS MAC-ADDRESS INTERFACE# 0 DH 192.168.88.10 AA:BB:CC:DD:EE:FF bridgeThe H flag identifies ARP entries created by DHCP. These entries allow the
router to forward traffic to newly assigned clients immediately without waiting
for ARP resolution.
Correlating Leases with Bridge Host Table
Section titled “Correlating Leases with Bridge Host Table”For environments using a bridge interface, the bridge host table shows active MAC addresses and their source ports, which can be correlated with DHCP leases:
# Show bridge-learned MACs/interface bridge host print
# Cross-reference with DHCP leases/ip dhcp-server lease printThis correlation is useful for locating a client physically when you know its IP address from the DHCP lease.
DHCP Alert (Rogue Server Detection)
Section titled “DHCP Alert (Rogue Server Detection)”DHCP Alert monitors a network interface for DHCP responses and can trigger an action when a DHCP server not on an approved list responds. This is a passive network scanning feature, not client discovery.
/ip dhcp-server alertadd interface=bridge \ alert-timeout=1m \ valid-server=192.168.88.1 \ on-alert=":log warning \"Rogue DHCP server detected!\""Check alert state:
/ip dhcp-server alert printThe on-alert script runs when an unexpected DHCP server is detected. Use it
to send a notification, block the offending MAC in the firewall, or page an
administrator.
Neighbor Discovery and DHCP Clients
Section titled “Neighbor Discovery and DHCP Clients”RouterOS /ip neighbor (MNDP/CDP/LLDP) is protocol-based and discovers only
devices that actively send neighbor discovery frames — it does not populate
from DHCP leases. To see all DHCP clients as neighbors, the clients themselves
must run a supported discovery protocol.
For a unified view of all hosts on a segment, combine:
/ip dhcp-server lease print— IP/MAC/hostname from DHCP/ip arp print— ARP table (enhanced byadd-arp=yes)/interface bridge host print— L2 port visibility
Troubleshooting
Section titled “Troubleshooting”Lease Script Does Not Run
Section titled “Lease Script Does Not Run”Verify the script name is spelled correctly:
/ip dhcp-server print detail where name=dhcp1Check that the named script exists:
/system script print where name=<script-name>Run the script manually to check for errors:
/system script run <script-name>Watch the script log topic for runtime errors:
/log print follow where topics~"script"BOOTP Clients Not Getting Addresses
Section titled “BOOTP Clients Not Getting Addresses”Check that bootp-support is not none:
/ip dhcp-server print detail where name=dhcp1For bootp-support=static, verify a static lease exists for the client MAC:
/ip dhcp-server lease print where mac-address=<client-mac>Capture traffic to confirm BOOTP requests are reaching the router:
/tool sniffer quick port=67,68 interface=<client-facing-interface>No ARP Entries for DHCP Clients
Section titled “No ARP Entries for DHCP Clients”Confirm add-arp=yes on the DHCP server:
/ip dhcp-server set [find name=dhcp1] add-arp=yesVerify the client’s lease is in bound state:
/ip dhcp-server lease print where active-address=<ip>Related Features
Section titled “Related Features”| Feature | Location |
|---|---|
| Custom DHCP options and vendor-class matchers | Custom DHCP Options, PXE Boot, and Vendor Option Sets |
| DHCP relay across subnets | DHCP Relay: Forwarding Requests Across Subnets and VLANs |
| Static simple queues | /queue simple |
| Firewall address lists | /ip firewall address-list |
| System logging | /system logging |
References
Section titled “References”- RouterOS documentation: IP/DHCP Server
- RouterOS documentation: Scripting
- RouterOS documentation: System Logging