Hi all,
after some time I decided to move my VPN server from a Rasbperry PI to my OpenWrt router (x86) because of crypt performance. As my initial setup was using authentication via RADIUS and also considered returned attribute (for IP), I was struggeling how to achieve the same with OpenWrt. After several tries of compiling the existing OpenVPN plugins I decided to try a different approach via "radclient", which is available as package. And finally I came up with a setup where all my reqiurements work and even additional ones have been added. Basically I am now doing the authentication in a bash script and write the response attribute into the user-specific OpenVPN file. This works really great for me and I wanted to share my solution, if somebody else is having similar problems.
#!/bin/bash
# passed by openvpn (in the environment):
#
# $username
# $password
#
# Current supported radius attributes
#
# Framed-IP-Address : client ip address
# MS-Primary-DNS-Server : primary dns server
# MS-Secondary-DNS-Server : secondary dns server
# MS-CHAP-Domain : network domain
#
# Dependencies (OpenWrt packages):
#
# bash
# freeradius3-utils (radclient)
#
# required OpenVPN configuration:
#
# auth-user-pass-verify /path/to/script/auth.radius.sh via-env
# script-security 3
# client-config-dir /etc/openvpn/files
radiusserver=192.168.X.X
radiussecret=secret
nasidentifier=someidentifier
# no change needed below this line
ourname=auth.radius.sh
facility=auth
output=$(mktemp)
error=$(mktemp)
# clean temp files when we terminate
trap "rm -f ${output} ${error}" EXIT
logger -p "${facility}.info" -t "$ourname" "Trying to authenticate user ${username} against RADIUS"
echo "User-Name=${username},User-Password=${password},NAS-Identifier=${nasidentifier}" | radclient -x $radiusserver $facility $radiussecret 1>"${output}" 2>"${error}"
# look for "Access-Accept" line in the output of radclient
result=`cat $output`
echo "" > "/etc/openvpn/files/${username}"
# Access Accept received
if [[ $result == *"Access-Accept"* ]]; then
# Read Framed-IP-Address from response
ip=`echo $result | grep -o 'Framed-IP-Address = .*' | cut -d' ' -f3`
if [ ! -z "$ip" ];
then
echo "ifconfig-push $ip 255.255.255.255" >> "/etc/openvpn/files/${username}"
fi
# Read MS-Chap-Domain from response
domain=`echo $result | grep -o 'MS-CHAP-Domain = .*' | cut -d' ' -f3 | cut -d'"' -f2`
if [ ! -z "$domain" ];
then
echo "push \"dhcp-option-push DOMAIN ${domain}\"" >> "/etc/openvpn/files/${username}"
fi
# Read MS-Primary-DNS-Server from response
primarydns=`echo $result | grep -o 'MS-Primary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$primarydns" ];
then
echo "push \"dhcp-option DNS ${primarydns}\"" >> "/etc/openvpn/files/${username}"
fi
# Read MS-Secondary-DNS-Server from response
secondarydns=`echo $result | grep -o 'MS-Secondary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$secondarydns" ];
then
echo "push \"dhcp-option DNS ${secondarydns}\"" >> "/etc/openvpn/files/${username}"
fi
logger -p "${facility}.info" -t "{$ourname}" "User ${username} authenticated successfully"
exit 0
# Authentication failed
else
logger -p "${facility}.err" -t "${ourname}" "User ${username} NOT authenticated"
exit 1
fi
It is surely not a perfect solution but it works. Feel free to adjust it to your needs.
Bye
A small update to also support multiple REDIS servers.
#!/bin/bash
# passed by openvpn (in the environment):
#
# $username
# $password
#
# Current supported radius attributes
#
# Framed-IP-Address : client ip address
# MS-Primary-DNS-Server : primary dns server
# MS-Secondary-DNS-Server : secondary dns server
# MS-CHAP-Domain : network domain
#
# Dependencies (OpenWrt packages):
#
# bash
# freeradius3-utils (radclient)
#
# required OpenVPN configuration:
#
# auth-user-pass-verify /etc/openvpn/server/auth.radius.sh via-env
# script-security 3
radiusservers=( "192.168.XX.X" "192.168.XX.X" )
radiussecret=secret
nasidentifier=identifier
clientconfigdir="/etc/openvpn/files"
# no change needed below this line
ourname=auth.radius.sh
facility=auth
output=$(mktemp)
error=$(mktemp)
# clean temp files when we terminate
trap "rm -f ${output} ${error}" EXIT
logger -p "${facility}.info" -t "$ourname" "Trying to authenticate user ${username} against RADIUS"
for radiusserver in "${radiusservers[@]}"
do
echo "User-Name=${username},User-Password=${password},NAS-Identifier=${nasidentifier}" | radclient -x $radiusserver $facility $radiussecret 1>"${output}" 2>"${error}"
# look for "Access-Accept" line in the output of radclient
result=`cat $output`
echo "" > "${clientconfigdir}/${username}"
# Access Accept received
if [[ $result == *"Access-Accept"* ]]; then
# Read Framed-IP-Address from response
ip=`echo $result | grep -o 'Framed-IP-Address = .*' | cut -d' ' -f3`
if [ ! -z "$ip" ];
then
echo "ifconfig-push $ip 255.255.255.255" >> "${clientconfigdir}/${username}"
fi
# Read MS-Chap-Domain from response
domain=`echo $result | grep -o 'MS-CHAP-Domain = .*' | cut -d' ' -f3 | cut -d'"' -f2`
if [ ! -z "$domain" ];
then
echo "push \"dhcp-option-push DOMAIN ${domain}\"" >> "${clientconfigdir}/${username}"
fi
# Read MS-Primary-DNS-Server from response
primarydns=`echo $result | grep -o 'MS-Primary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$primarydns" ];
then
echo "push \"dhcp-option DNS ${primarydns}\"" >> "${clientconfigdir}/${username}"
fi
# Read MS-Secondary-DNS-Server from response
secondarydns=`echo $result | grep -o 'MS-Secondary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$secondarydns" ];
then
echo "push \"dhcp-option DNS ${secondarydns}\"" >> "${clientconfigdir}/${username}"
fi
logger -p "${facility}.info" -t "{$ourname}" "User ${username} authenticated successfully"
exit 0
# Authentication failed
elif [[ $result == *"Access-Reject"* ]]; then
logger -p "${facility}.err" -t "${ourname}" "User ${username} NOT authenticated"
exit 1
else
echo "failed for server ${radiusserver}"
fi
done
logger -p "${facility}.err" -t "${ourname}" "User ${username} NOT authenticated"
exit 1
There was an issue with assigning domain and network mask, which is fixed here:
#!/bin/bash
# passed by openvpn (in the environment):
#
# $username
# $password
#
# Current supported radius attributes
#
# Framed-IP-Address : client ip address
# MS-Primary-DNS-Server : primary dns server
# MS-Secondary-DNS-Server : secondary dns server
# MS-CHAP-Domain : network domain
#
# Dependencies (OpenWrt packages):
#
# bash
# freeradius3-utils (radclient)
#
# required OpenVPN configuration:
#
# auth-user-pass-verify /etc/openvpn/server/auth.radius.sh via-env
# script-security 3
radiusservers=( "192.168.XX.X" "192.168.XX.X" )
radiussecret=secret
nasidentifier=identifier
clientconfigdir="/etc/openvpn/files"
# no change needed below this line
ourname=auth.radius.sh
facility=auth
output=$(mktemp)
error=$(mktemp)
# clean temp files when we terminate
trap "rm -f ${output} ${error}" EXIT
logger -p "${facility}.info" -t "$ourname" "Trying to authenticate user ${username} against RADIUS"
for radiusserver in "${radiusservers[@]}"
do
echo "User-Name=${username},User-Password=${password},NAS-Identifier=${nasidentifier}" | radclient -x $radiusserver $facility $radiussecret 1>"${output}" 2>"${error}"
# look for "Access-Accept" line in the output of radclient
result=`cat $output`
echo "" > "${clientconfigdir}/${username}"
# Access Accept received
if [[ $result == *"Access-Accept"* ]]; then
# Read Framed-IP-Address from response
ip=`echo $result | grep -o 'Framed-IP-Address = .*' | cut -d' ' -f3`
if [ ! -z "$ip" ];
then
echo "ifconfig-push $ip 255.255.255.0" >> "${clientconfigdir}/${username}"
fi
# Read MS-Chap-Domain from response
domain=`echo $result | grep -o 'MS-CHAP-Domain = .*' | cut -d' ' -f3 | cut -d'"' -f2`
if [ ! -z "$domain" ];
then
echo "push \"dhcp-option DOMAIN ${domain}\"" >> "${clientconfigdir}/${username}"
fi
# Read MS-Primary-DNS-Server from response
primarydns=`echo $result | grep -o 'MS-Primary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$primarydns" ];
then
echo "push \"dhcp-option DNS ${primarydns}\"" >> "${clientconfigdir}/${username}"
fi
# Read MS-Secondary-DNS-Server from response
secondarydns=`echo $result | grep -o 'MS-Secondary-DNS-Server = .*' | cut -d' ' -f3`
if [ ! -z "$secondarydns" ];
then
echo "push \"dhcp-option DNS ${secondarydns}\"" >> "${clientconfigdir}/${username}"
fi
logger -p "${facility}.info" -t "{$ourname}" "User ${username} authenticated successfully"
exit 0
# Authentication failed
elif [[ $result == *"Access-Reject"* ]]; then
logger -p "${facility}.err" -t "${ourname}" "User ${username} NOT authenticated"
exit 1
else
echo "failed for server ${radiusserver}"
fi
done
logger -p "${facility}.err" -t "${ourname}" "User ${username} NOT authenticated"
exit 1