High performance request remapping / rewriting
Phil Mayers
p.mayers at imperial.ac.uk
Fri Jul 8 15:15:09 CEST 2005
All,
We are looking to implement mac-based vlans with a radius backend. I'm
hoping freeradius is the obvious choice, but I'm having a hard time
seeing how to do what I need.
What I'm looking to is feed FreeRadius from our host registration
database. Each NAS (switch) may potentially have different VLANs on it,
and each registered host may fall into a different vlan "type", so the
radius server needs to map:
(clientmac, nasipaddress) -> vlantag
However, there are ~20k MAC addresses and ~1200 NASes (switches), so
clearly I can't do this:
DEFAULT Calling-Station-Id = "<mac0>", NAS-IP-Address = "<switch0>"
DEFAULT Calling-Station-Id = "<mac0>", NAS-IP-Address = "<switch1>"
DEFAULT Calling-Station-Id = "<mac0>", NAS-IP-Address = "<switch2>"
...
DEFAULT Calling-Station-Id = "<mac20k>", NAS-IP-Address = "<switch1k>"
...because it's 20 million entries. The file as a users compiled to dbm
is >4Gb :o(
I wanted to do some kind of optimisation - the switches are grouped into
zones in our database, and vlans are specific to these zones (normally a
building), so actually something like:
nasip -> zone
(clientmac, zone) -> vlan
...but that's still too large, so maybe:
nasip -> zone
clientmac -> clienttype (there are 5 types - unreg, guest, roaming,
home, blocked)
(clienttype, zone) -> vlan
...which would be much smaller, but I can't see how you do this. I must
admit to being somewhat confused about the request, check and reply
items, but from what I can tell a "users" item consists of:
username OR DEFAULT <space> [comma-separated items to check against
request] <newline>
[comma-separated items to add to reply]
...so even with Fall-Through=Yes you can never do this:
DEFAULT NAS-IP-Address = blah
Zone = "foo"
DEFAULT Calling-Station-Id = "00-11-22-33-44-55", User-Password =
"00-11-22-33-44-55"
Kind = "guest"
# Fallback - unknown hosts
DEFAULT Calling-Station-Id =~
"^[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}$"
, User-Password = `%{0}`
Kind = "unreg"
DEFAULT Zone = "foo", Kind = "unreg"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-ID := "1"
DEFAULT Zone = "foo", Kind = "guest"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-ID := "2"
...because Zone and Kind are set in the reply, so can't be matched
further down.
rlm_attr_rewrite has the beginnings of what is needed, but a linear
search through 20k regexps for the hosts, followed by 1k regexps for the
switches clearly isn't going to work.
Ideally an apache-like feature of DBM mapping is what's needed of
something like:
/etc/raddb/radiusd.conf:
attr_rewrite nas2zone {
attribute = NAS-IP-Address
searchin = packet
searchfor = "(.*)"
replacewith = "%{dbm:nas2zone:%{1}}"
new_attribute_name = "Zone"
}
...and similarly for Calling-Station-Id -> kind
The issue is that this needs to go very very fast - at peak times (e.g.
say a reboot of a PC cluster during overnight maintenance) the DHCP
servers get ~50 requests/second, so a radius server(s) would need to
answer with similar performance.
I originally tried to do this with rlm_sql direct to our registration
database, but the performance was abominal (which is not an SQL issue)
and eventually it hung the radius server anyway (rlm_sql_postgresql). In
any event I was never super-keen on that for security reasons, though
the fact it was instant-updating once a registration was processed was
very handy.
I'm assuming rlm_exec would have similar if not worse performance
characterisitcs (spawning 50 processes a second during peak times does
not strike me as overly sensible). Is there an rlm_socket:
socket mac_vlan {
path = "/var/run/mac_vlan.unixsock"
wait = yes
input_pairs = request
output_pairs = reply
}
...i.e. keep a persistent connection to something open.
I'd appreciate any suggestions.
More information about the Freeradius-Users
mailing list