# Mikrotik DHCP & FreeRADIUS with a hint of unlang

*September 23, 2012* — https://jade.wtf/tech-notes/mikrotik-dhcp-freeradius-unlang/

Tags: Mikrotik, WISP

---


Mikrotik has two particularly useful subscriber management
features built into the [DHCP server](http://wiki.mikrotik.com/wiki/Manual:IP/DHCP_Serve) on RouterOS.
First, If you set the rate-limit property on a DHCP lease it will dynamically manage a
[Simple Queue](http://wiki.mikrotik.com/wiki/Manual:Queue#Simple_Queues) to enforce the rate limit.
Second, it will authenticate to a RADIUS server using the DHCP Client's MAC address as the username.
The RADIUS server can reply with the IP address, pool, or traffic shaping paramaters.

We use this combination to rate limit customers on [Ubiquiti AirMax](http://www.ubnt.com/airmax)
equipment since Ubiquiti is somewhat unaccommodating towards OSS/BSS integrations. When we set up our
system we envisioned three states of a customer so far as DHCP RADIUS is concerned:

  1. Users that aren't known to the system don't get a IP address. We do this by setting the default address-pool on the DHCP server instance to static-only.
  2. A user that is known to the system and has a active account is assigned a DHCP Pool of ubnt-cust (for Ubiquiti customer).
  3. A user with a delinquent account is assigned to the ubnt-deact (for Ubiquiti deactivated) pool. Users in this pool are assigned a RFC1918 IP address and redirected to a splash page.

You might think that we would want unknown users to get a splash page, and we do on our Cambium
Canopy network which comes with strong AAA support. On the Ubiquiti network we assume that anyone
we don't know about that manages to connect to our network is hostile and want to give them as little
data as possible. Every little obstacle helps. I may relax this after exploring the fairly new RADIUS
authentication support in Ubiquiti AirOS.

Anyway, We ended up with a Mikrotik router at each AirMax tower running RADIUS-backed DHCP. Our
B/OSS provisions our existing FreeRADIUS system with Ubiquiti device MAC addresses as usernames and
puts them in a group with a Mikrotik-Rate-Limit attribute that matches the customer's speed package.
Everything is working great until&hellip;

We started to retrofit existing towers with AirMax. These towers were often connected in a star
topology, as opposed to our previous expansion where we build out in a line and then expand to the
side to make a box. Since we had a central tower it didn't make sense to deploy a router at every
spoke site[^1].
Of course each tower (at a minimum) has its own VLAN to make management easier and contain bad
behavior. This presented a problem since the Mikrotik DHCP server can't dynamically select the
correct subnet based on the ingress interface (unlike the Cisco IOS or ISC DHCPd servers).
The solution is to create a separately named pool for each interface/tower and get the RADIUS server
to provide the appropriate pool in the RADIUS reply. How do we do that? Well, the "easy" way would
be to manually set a different pool for each tower in RADIUS. The problem is that is more work on
a ongoing basis.

What to do? Well, the Mikrotik DHCP server sends the DHCP server name in the RADIUS request as
the Called-Station-ID. On all our towers we had been setting this to ubnt-server. On routers
serving multiple towers I set the server name to ubnt-server-TWRID[^2].
Then I setup the pools for each tower as ubnt-cust-TWRID and ubnt-deact-TWRID. In the FreeRADIUS
server config I used unlang to extract the TWRID portion of each server name in the request and
append it to the pool in the reply.

in `sites-enabled/default`:

```freeradius
post-auth {
 # Rewrite Mikrotik IP Pool assignments for routers with multiple pools
 if (request:Called-Station-Id =~ /^ubnt-server-(.*$)/) {
  update reply {
   Framed-Pool := "%{reply:Framed-Pool}-%{1}"
  }
 }
}
```

Example Mikrotik DHCP server config:

```routeros
/ip pool
add name=ubnt-cust-HRT2 ranges=199.X.X.2-199.X.X.14
add name=ubnt-deact-HRT2 ranges=10.10.17.82-10.10.17.94
add name=ubnt-deact-HRT1 ranges=10.10.17.210-10.10.17.222
add name=ubnt-deact-SLNG1 ranges=10.10.17.194-10.10.17.206
add name=ubnt-cust-HRT1 ranges=199.X.X.18-199.X.X.30
add name=ubnt-cust-SLNG1 ranges=199.X.X.34-199.X.X.46

/ip dhcp-server
add add-arp=yes authoritative=yes disabled=no interface=v100-ether7 \
    lease-time=30m name= ubnt-server-HRT2 src-address=199.X.X.1 use-radius=yes
add add-arp=yes authoritative=yes disabled=no interface=v100-ether8 \
    lease-time=30m name=ubnt-server-HRT1 src-address=199.X.X.17 use-radius=yes
add add-arp=yes authoritative=yes disabled=no interface=v201-ether9 \
    lease-time=30m name=ubnt-server-SLNG1 src-address=199.X.X.33 use-radius=yes
```

[^1]: Since you aren't doing subscriber management at the tower you need some
kind of rate limiting in the CPE as a safety net to prevent subscriber-originated UDP floods
saturating the tower backhaul on their way to the router.

[^2]: TWRID is the unique ID for each tower. We base it off of psudo-CLLI code.
SLNG1, HRFD2, WHWR1, etc.


---

&copy; 2012 Jade Angrboða.
