I've come across an issue with dynamic home_servers for supporting OpenRoaming connections. In `authorize`, we use the following code to check if it's our home domain, if the 'home_server' already exists, or if we need to dynamically query which radsec server to proxy to: -------------------------------- openroaming_lookup { if (&control:Proxy-To-Realm || &control:Home-Server-Name) { return } if (&User-Name && &User-Name =~ /home.domain/) { return } elsif (&User-Name && &User-Name =~ /@(.*)$/) { switch "%{home_server_dynamic:%{1}}" { case "1" { # Proxy to this one particular home server update control { &Home-Server-Name := "%{1}" } } case "0" { # Proxy with home server pool, failover, etc. update control { &Proxy-To-Realm := "%{1}" } } case { # no home server exists, ask DNS update control { &Temp-Home-Server-String := `%{config:confdir}/mods-config/realm/freeradius-naptr-to-home-server.sh -d %{config:confdir} %{1} aaa+auth:radius> } if (&control:Temp-Home-Server-String == "" ) { reject } else { update control { &Home-Server-Name := "%{1}" } } } } } } -------------------------------- This generally works well. For a new (unknown home server), we call the below mods-config/realm/freeradius-naptr-to-home-server.sh script to perform the dynamic discovery: -------------------------------- #!/bin/sh usage() { echo "Usage: ${0} [OPTIONS] <realm> <optional NAPTR tag>" echo " -d RADIUS_DIR Set radius directory" echo " -t test (skip running radmin)" exit 1 } test -n "${1}" || usage RADDB=/usr/local/etc/raddb RADMIN=y while [ `echo "$1" | cut -c 1` = "-" ] do case "$1" in -d) RADDB=$2 shift;shift ;; -t) RADMIN= shift ;; *) usage ;; esac done test -n "${2}" && NAPTRTAG="${2}" || NAPTRTAG="x-eduroam:radius.tls" DIGCMD=$(command -v dig) HOSTCMD=$(command -v host) PRINTCMD=$(command -v printf) validate_host() { echo ${@} | tr -d '\n\t\r' | grep -E '^[_0-9a-zA-Z][-._0-9a-zA-Z]*$' } validate_port() { echo ${@} | tr -d '\n\t\r' | grep -E '^[0-9]+$' } dig_it_srv() { ${DIGCMD} +short srv $SRV_HOST | sort -n -k1 | while read line; do set $line PORT=$(validate_port $3) HOST=$(validate_host $4) if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then $PRINTCMD "\tipaddr = ${HOST%.}\n\tport = ${PORT}\n" fi done } dig_it_naptr() { ${DIGCMD} +short naptr "${REALM}" | grep $NAPTRTAG | sort -n -k1 | while read line; do set $line TYPE=$3 HOST=$(validate_host $6) if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then SRV_HOST=${HOST%.} dig_it_srv fi done } host_it_srv() { ${HOSTCMD} -t srv $SRV_HOST | sort -n -k5 | while read line; do set $line PORT=$(validate_port $7) HOST=$(validate_host $8) if [ -n "${HOST}" ] && [ -n "${PORT}" ]; then $PRINTCMD "\tipaddr ${HOST%.}:${PORT}\n" fi done } host_it_naptr() { ${HOSTCMD} -t naptr "${REALM}" | grep $NAPTRTAG | sort -n -k5 | while read line; do set $line TYPE=$7 HOST=$(validate_host ${10}) if ( [ "$TYPE" = "\"s\"" ] || [ "$TYPE" = "\"S\"" ] ) && [ -n "${HOST}" ]; then SRV_HOST=${HOST%.} host_it_srv fi done } REALM=$(validate_host ${1}) if [ -z "${REALM}" ]; then echo "realm \"${1}\" failed validation" >&2 usage fi if [ -x "${DIGCMD}" ]; then SERVERS=$(dig_it_naptr) elif [ -x "${HOSTCMD}" ]; then SERVERS=$(host_it_naptr) else echo "${0} requires either \"dig\" or \"host\" command." >&2 exit 1 fi if [ ! -n "${SERVERS}" ]; then echo "No servers found" >&2 exit 1 fi if [ -z "${RADMIN}" ]; then $PRINTCMD "home_server ${REALM} {\n${SERVERS}\n\t\$INCLUDE tls.conf\n}\n" exit 0 fi HOME_SERVER_FILE="$RADDB/home_servers/$1" if [ -f "$HOME_SERVER_FILE" ]; then echo "Home server file $HOME_SERVER_FILE already exists. Skipping creation and radmin command." >&2 else echo "Creating new home server file $HOME_SERVER_FILE." >&2 $PRINTCMD "home_server ${REALM} {\n${SERVERS}\n\t\$INCLUDE tls.conf\n}\n" > "$HOME_SERVER_FILE" /usr/local/sbin/radmin -e "add home_server file $HOME_SERVER_FILE" fi echo $1 -------------------------------- Again, this works well. It creates a new file in the home_servers folder, and radmin adds it to the server to use immediately. The problem arises if we have an authentication request from a new realm but the "server" is one that we already have a reference to, from a previously added dynamic home server definition. For example, an authentication request comes in with a realm of davidlloyd.openroaming.net and the script generates the following home server config: # cat home_servers/davidlloyd.openroaming.net home_server davidlloyd.openroaming.net { ipaddr = idpeu.openroaming.net port = 2083 $INCLUDE tls.conf } This new home server was then added via radmin, and everything was ok. The request is proxied to that new server. So far, so good. Later, another authentication request comes in with a realm of eu-sdk.openroaming.net, and the script generates the following home server config: # cat home_servers/eu-sdk.openroaming.net home_server eu-sdk.openroaming.net { ipaddr = idpeu.openroaming.net port = 2083 $INCLUDE tls.conf } However, this failed to add via radmin, because the "ipaddr" is the same as a previously defined dynamic home server, and the authentication fails as it doesn't proxy the request. ipaddr = idpeu.openroaming.net <<<< this The error thrown by radmin is: # radmin -e "add home_server file /usr/local/etc/raddb/home_servers/ davidlloyd.openroaming.net" ERROR: Unable to add home server - Failed adding home_server to the internal data structures This doesn't just happen for "openroaming" hosted realms either. Take cityroam in Japan for example. They have multiple realms too, but the same servers: # cat home_servers/*city* home_servers/jwa.bemap.cityroam.jp: home_server jwa.bemap.cityroam.jp { ipaddr = jpgw4.cityroam.jp port = 2083 ipaddr = jpgw.cityroam.jp port = 2083 $INCLUDE tls.conf } home_servers/w-jp1.wi2.cityroam.jp: home_server w-jp1.wi2.cityroam.jp { ipaddr = jpgw4.cityroam.jp port = 2083 ipaddr = jpgw.cityroam.jp port = 2083 $INCLUDE tls.conf } It's like we need a way to set servers and then map multiple realms to the same server (as traditionally done in proxy.conf)? How can we best solve this issue? Is there another method for doing this besides the one above? We can't statically define these servers (as the whole point of openroaming is to dynamic proxy to the resolved servers, which may change), and we'll never know what user realm may hit us next will be, and they will probably share servers. Thanks, James -- Visit purple.ai <https://purple.ai/> Purple on LinkedIn <https://uk.linkedin.com/company/purple-wifi> Email disclaimer <http://www.purple.ai/email-disclaimer/>