suggestions for multiple vlans in hundreds of switches

Arran Cudbard-Bell A.Cudbard-Bell at sussex.ac.uk
Fri Apr 20 23:23:24 CEST 2007


Phil Mayers wrote:
> Matt Ashfield wrote:
>   
>> Hi,
>>
>> We'd like to use FR to assign users on our wired network to one of 30
>> different vlans on campus, based on an LDAP field. Currently, we are doing
>> this with huntgroups. Namely, we create a huntgroup for the NAS (in our
>> case, a network switch), and then in the users file, we put the following:
>>     
>
> Credit to Alan DeKok for this idea - it was one of the first questions I 
> asked on the list.
>
> Use two rlm_passwd modules to add "fake" items to the *request*:
>
> passwd nas2building {
>    file = /etc/raddb/nas2building
>    format = "*NAS-IP-Address:~MyBuilding"
>    hashsize = 100
> }
> passwd user2vlantype {
>    file = /etc/raddb/user2vlantype
>    format = "*User-Name:~MyVlanType"
>    hashsize = 100
>    allowmultiplekeys = yes
> }
>
> ...then in the users file you reduce NxM to AxB which is a hopefully 
> smaller combination:
>
> DEFAULT	MyBuilding == "facility1", MyVlanType == "guests"
> 	...
> DEFAULT	MyBuilding == "facility1", MyVlanType == "staff"
> 	...
>
> Note that if you're caching the files, FreeRadius will need to be HUPed 
> to re-read them (boo!). Also, you'll need to add the MyXXX attributes to 
> the dictionary like so:
>
> ATTRIBUTE      MyBuilding         3000    string
> ATTRIBUTE      MyVlanType         3001    string
>
> This could also be done cleaner (but slower) with cleverly designed SQL 
> tables or stored procedures
>   
Yeah, complex sql really can be quite slow, specially when the queries 
are being run multiple times for all the rounds required in eap 
authentication.
> - 
> List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
>   

I use a second instance of preprocess to read a second hints file called 
'nas_hints' this uses dynamic sql queries to grab extra nas_attributes 
from the server.

I actually use a really quick and dirty way of getting multiple values 
from a very simple query. You store multiple bool vars as a binary 
string representation of a 6 digit integer... can then use pattern 
matching in group check items to select required values and values you 
dont care about.

    authorization {
                nas_hints
    }

     preprocess nas_hints {
                hints = ${confdir}/nas_hints
     }


Here is my nas_hints file
#############################################################
# Should speed things up when proxying peap to itself
DEFAULT Packet-Src-IP-Address == localhost

#############################################################
# Set the 'PROXY' flag in the feature set for the JRS proxies
DEFAULT Packet-Src-IP-Address == roaming0.ja.net
        NAS-Feature-Set = '00000100100000000000'

DEFAULT Packet-Src-IP-Address == roaming1.ja.net
        NAS-Feature-Set = '00000100100000000000'

DEFAULT Packet-Src-IP-Address == roaming2.ja.net
        NAS-Feature-Set = '00000100100000000000'

#############################################################
# Debug entry for home testing.
#DEFAULT Packet-Src-IP-Address == arr-land.co.uk
#        NAS-Feature-Set = '00000100100000000000'

#############################################################
# Retrieve the feature set for all none recognised clients
# from the NetReg3 Database
# Note: Doing the initial pattern match is a far quicker was of doing things
# rather than concatinating the db columns and comparing with client ip !
DEFAULT Packet-Src-IP-Address =~ 
"^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$"
        NAS-Feature-Set = "SELECT 
EXPORT_SET(master.nas_flags,'1','0','',20) FROM `master` WHERE ip1 = 
'%{1}' AND ip2 = '%{2}' AND ip3 = '%{3}' AND ip4 = '%{4}' LIMIT 0,1"


Heres some group examples...


  SQL result

*Host:* localhost
*Database:* radius
*Generation Time:* Apr 20, 2007 at 10:20 PM
*Generated by:* phpMyAdmin 2.9.2 / MySQL 4.1.10a-standard-log
*SQL query:* SELECT * FROM `radgroupcheck` LIMIT 0, 30 ;
*Rows:* 5

id 	GroupName 	Attribute 	op 	Value
1 	nas_admins 	Service-Type 	<= 	NAS-Prompt-User
2 	nas_admins 	Service-Type 	>= 	Administrative-User
3 	nas_operators 	Service-Type 	== 	NAS-Prompt-User
20 	jrs_offsite_ao 	Huntgroup-Name 	== 	jrs-proxy
19 	jrs_offsite_ao 	NAS-Feature-Set 	=~ 	00000100100000000000



Heres a fun little php script to take a list of features and produce a 
bit string or integer value.

#!/usr/local/php/bin/php
<?php
if(isset($argv[1])){
        if(!isset($argv[2]) ){$argv[2] = false;}
        echo calc_nas_features($argv[1],$argv[2],20)."\n";
}else{
echo "/* Authentication Mediums */
        '802.1',  # 802.1 (Wired LAN)
        '802.11', # 802.11 (Wireless LAN)
        'IPSEC',  # IPSEC (VPN)
        'SSH',    # Secure Shell/Nas Prompt Login
        'HTTPS',  # Captive Portal/Nas Web Interface
        'PROXY',  # Client Isn't a NAS it's an offsite Proxy
        'unused', # For future use
        'unused', # For future use
/* Extended Features */
        'RADACCT',# NAS Can do RADIUS Accounting
        'D802.Q', # NAS Can do Dynamic Vlan Assignment
        'MULTIBESSID'); # NAS Can have multiple SSIDs / BSSIDs
";
}

function calc_nas_features($flags,$dec = true,$pad_to = null){
        $def = array('802.1', '802.11', 'IPSEC', 'SSH',  'HTTPS',  
'PROXY', 'unused', 'unused', 'RADACCT', 'D802.Q','MULTIBESSID');
        return 
calc_feature_bm(explode(',',strtoupper($flags)),$def,$dec,$pad_to);
}
/**
 * Convert feature flags to base10/Little Endian binary representation
 *
 *
 * @param string $flags
 * @param string $flags_def
 *
 * @return string
 */
function calc_feature_bm($flags = array(),$flags_def = array(),$dec_out 
= true,$pad_to = null){
        $def_flags = array_flip($flags_def);                     # Use 
arrays value as key, and posistion as BIT posistion.
        if((!$pad_to) || (count($flags_def) > $pad_to)){
            $bit_array = array_fill(0,count($flags_def),0);# Create an 
array equal to the maximum amount of possible flgs
        }else{
            $bit_array = array_fill(0,$pad_to,0);# Create an array equal 
to pad value, if created than maximum flags
        }
        foreach($flags as $value){                         # For each of 
the flags, see if it's value matches one of the keys
                if(key_exists($value,$def_flags)){ # If it does then set 
that BIT to true
                        $bit_array[$def_flags[$value]] = 1;
                
}else{                                                     # If it 
doesn't warn the user
                        trigger_error('Flag not found in flag 
definitions.',E_USER_NOTICE);
                }
        }
        $bin = implode('',array_reverse($bit_array));
        if($dec_out == true){
                return bindec($bin);
        }else{
                return implode('',$bit_array);
        }
}
?>

If someone actually wants to do it this way, i'll put together some 
proper functions for generating the bit strings and stuff...




More information about the Freeradius-Users mailing list