This is a continuation of my previous question in sending static routes from Freeradius DHCP server implementation in combination with Strongswan VPN server.
When debugging Freeradius using tcpdump and Wireshark I found out that I can send classless static routes from Freeradius DHCP server by through adding DHCP-Classless-Static-Route
and DHCP-Site-specific-25
(aka Microsoft static route) options to my DHCP-Discover
and DHCP-Request
sections of the dhcp server configuration file.
However: It appears that the static routes are not accepted by Microsoft VPN client if I set the default gateway to be 0.0.0.0
as suggested by Strongswan documentation.
At least I cannot find the advetised routes on my Windows client when using route print -4
.
Also I cannot add the routes manually on Windows client when I am using 0.0.0.0
as standard gateway over VPN interface.
However:
Lets say I want to access the subnet 192.168.200.0/24
over VPN and my VPN server assign the address 192.168.201.2/24
to my Windows client. Then it is actually possible to create a static route on windows client side by declaring that the subnet 192.168.200.0/24 is accessible via 192.168.201.2 using the windows command:
route add 192.168.200.0 mask 255.255.255.0 192.168.201.2
I know it looks a bit weird, but I can ping any host on the 192.168.200.0
subnet, so as long as it works I am happy. :-)
But: I would be more happy if I could do the same thing by advertising the routes from my VPN server instead of doing it manually on all VPN clients. :-)
That means I have to do a bit of dynamic programming to the DHCP configuration in Freeradius. I my case it means I have to make a reference to a perl module in DHCP-Discover and DHCP-request that grabs the assigned client vpn ip address, convert it into octets and combine it with the static routes that is also given as octets.
An example:
The subnet 192.168.200.0/24
will be encoded as 0x18c0a8c8
as subnet mask is encoded first.
The client 192.168.201.2/24
will be encoded as 0xc0a8c902
as it is just converting each number in the ip address to hex.
The final encoding for the route will be: 0x18c0a8c8c0a8c902
as it is just a concatination of the two strings.
I then have to use update reply
with the following code:
update reply {
&DHCP-Classless-Static-Route = 0x18c0a8c8c0a8c902
&DHCP-Site-specific-25 = 0x18c0a8c8c0a8c902
}
If there are any more routes then all the routes will be concatenated into one long string.
The tricky part:
Assume you have the default configuration of Freeradius DHCP server as found in freeradius/3.0/sites-available/dhcp
file.
The general structure of the file for DHCP-Discover and DHCP-Request is as follows:
dhcp DHCP-Request {
update reply {
&DHCP-Message-Type = DHCP-Ack
}
update reply {
# General DHCP options, such as default GW, DNS, IP-address lease time etc.
}
update control {
&Pool-Name := "vpn_pool"
}
dhcp_sqlippool
ok
}
Then as far as I have gathered I need to call my perl module after dhcp_sqlippool
has been called and before returning ok
, because dhcp_sqlippool
is the module that assigns the ipaddress to the VPN client.
That means my version would be something like:
dhcp DHCP-Request {
update reply {
&DHCP-Message-Type = DHCP-Ack
}
update reply {
# General DHCP options, such as default GW, DNS, IP-address lease time etc.
}
update control {
&Pool-Name := "vpn_pool"
}
dhcp_sqlippool
perl
# If perl module returned no error
if(ok) {
update reply {
# Perl-Route contains a hex encoded string with all routes.
&DHCP-Classless-Static-Route = Perl-Route
&DHCP-Site-specific-25 = Perl-Route
}
}
# Not sure if this one is needed?
update reply {
&DHCP-End-Of-Options = 255
}
ok
}
In order to make it work, I have to enable perl under the freeradius/3.0/mods-enabled
folder and modify the filename in freeradius/3.0/mods-enabled/perl
to point it to my perl module. Like for instance:
filename = ${modconfdir}/${.:instance}/dhcp/Options.pm
But how do I do reference the call to perl the right way?
I thought I had to enable the line func_post_auth = post_auth
in freeradius/3.0/mods-enabled/perl
and create a sub post_auth
section in my perl module to handle calls from Freeradius, but as far as I can see in my log I get the following error in Freeradius:
(8) perl: perl_embed:: module = /etc/freeradius/3.0/mods-config/perl/dhcp/Options.pm ,
func = post_auth exit status= Undefined subroutine &main::post_auth called.
...
(8) [perl] = fail
(8) } # dhcp DHCP-Discover = fail
So what is it that I am not seeing?
I banged my head against the wall a few times, but at least I got the perl module to work, though I am not completely where I want to be, since static routing via DHCP does not pass from Freeradius DHCP server to VPN client via Strongswan, but debugging UDP packages from Freeradius DHCP server implies the issue lies elsewhere.
Anyhow here is what I did:
freeradius/3.0/mods-enabled
and set at least the following lines:freeradius/3.0/sites-enabled/dhcp
The relevant places areDHCP-Discover
andDHCP-Request
:freeradius/3.0/mods-config/perl/dhcp/Options.pm
:The perl code can be tweaked from here, so option 121 or option 249 is sent depending on client operating system.
I also leave the possibility to make the code more generic, so static routes can be defined directly in Freeradius config file to the reader.