Description

This article describes how to set up a lab environment to authenticate devices dynamically using RADIUS and assign VLANs based on authentication results.

The lab includes a Juniper EX4100 switch, a QFX core switch, a FreeRADIUS server, a DHCP server, and a client device.


Symptoms

Topology

  • Client Device (VM1): Connected to EX4100.  
  • Access Switch (EX4100): Authenticates devices and assigns VLANs dynamically.  
  • Core Switch/DHCP Server (QFX): Routes traffic between VLANs and DHCP Server for IP address allocation.    
  • RADIUS(VM2): Handles authentication and VLAN assignment.

 

Example IP Addressing

  • Management VLAN: 192.168.99.0/24
  • Guest VLAN: 192.168.20.0/24
  • Secure VLAN: 192.168.30.0/24
  • Server VLAN: 192.168.3.0/24

Solution

1. Configure the FreeRADIUS and DHCP Server (VM2)

Assign a physical NIC on VM2 to the management VLAN (192.168.3.0/24) to enable communication with the switches.

Linux Network Configuration

  Update `/etc/netplan` (for Ubuntu) or `/etc/network/interfaces` (for Debian-based systems):  

cat <<EOL | sudo tee /etc/netplan/01-network-config.yaml
  network:
    version: 2
      ens192:
        dhcp4: no
        addresses:
          - 192.168.3.1/24
  EOL

Or using below command (this will be deleted after any reboot.

ip add add 192.168.3.1/24 dev ens192
ip route add 192.168.0.0/16 dev ens192 via 192.168.3.254

Apply changes:  
sudo netplan apply

 

Install necessary packages

sudo apt update
sudo apt upgrade

or

sudo apt-get update
sudo apt-get install -y freeradius freeradius-utils 

 

RADIUS Server Configuration for Dynamic VLANs

sudo bash -c "cat > /etc/freeradius/3.0/clients.conf" <<EOF

client AccessSwitch {
  ipaddr = 192.168.99.1
  secret = Juniper123
  require_message_authenticator = no
}
EOF

cat /etc/freeradius/3.0/clients.conf

sudo bash -c "cat > /etc/freeradius/3.0/mods-config/files/authorize" <<EOF
0050569e1ccf Cleartext-Password := "0050569e1ccf"
  Tunnel-Type = VLAN,
  Tunnel-Medium-Type = IEEE-802,
  Tunnel-Private-Group-Id = "20"
EOF

 

Restart freeradius

sudo systemctl restart freeradius
sudo systemctl stop freeradius

Other useful commands.

sudo systemctl restart freeradius
sudo systemctl stop freeradius

To monitor freeradius messages:
sudo freeradius -X

 

2. Configure VM1 as a Simulated Guest

 

On VM1, configure it to act as a RADIUS client and request DHCP once authenticated.

Install necessary tools:

sudo apt update
sudo apt upgrade
sudo apt update && sudo apt install wpa_supplicant isc-dhcp-client -y

 

Configure `wpa_supplicant` for 802.1X

 

sudo bash -c "cat > /etc/wpa_supplicant/wpa_supplicant.conf" <<EOF

ctrl_interface=/var/run/wpa_supplicant
network={
  key_mgmt=IEEE8021X
  eap=PEAP
  identity="Guest"
  password="Juniper123"
  phase2="auth=PAP"
}
EOF

 

Bring up the interface:

sudo wpa_supplicant -i ens34 -c /etc/wpa_supplicant/wpa_supplicant.conf -B

 

cat <<EOL | sudo tee /etc/netplan/01-netcfg.yaml

network:
 version: 2
 ethernets:
  ens34:
   dhcp4: true
EOL

 

Apply the interface configuration and initialize the dhcp process.

sudo netplan apply
sudo dhclient ens34

 

3: Configure DHCP on the Core

set system host-name CoreSwitch
set system services dhcp-local-server group printers interface irb.20
set interfaces ge-0/0/0 unit 0 family ethernet-switching interface-mode access
set interfaces ge-0/0/0 unit 0 family ethernet-switching vlan members Server
set interfaces ge-0/0/47 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members all
set interfaces irb unit 3 family inet address 192.168.3.254/24
set interfaces irb unit 20 family inet address 192.168.20.254/24
set interfaces irb unit 20 proxy-arp restricted
set interfaces irb unit 30 family inet address 192.168.30.254/24
set interfaces irb unit 99 family inet address 192.168.99.254/24
set interfaces irb unit 99 proxy-arp restricted
set access address-assignment pool Guest-pool family inet network 192.168.20.0/24
set access address-assignment pool Guest-pool family inet range Guest-range low 192.168.20.34
set access address-assignment pool Guest-pool family inet range Guest-range high 192.168.20.40
set protocols lldp interface all
set vlans Guest vlan-id 20
set vlans Guest l3-interface irb.20
set vlans MgmtVLAN vlan-id 99
set vlans MgmtVLAN l3-interface irb.99
set vlans SecureVLAN vlan-id 30
set vlans SecureVLAN l3-interface irb.30
set vlans Server vlan-id 3
set vlans Server l3-interface irb.3

Step 4: Configure EX4100 (Access)

set system host-name AccessSwitch
set system management-instance
set interfaces interface-range access-ports member-range ge-0/0/0 to ge-0/0/35
set interfaces interface-range access-ports unit 0 family ethernet-switching interface-mode access
set interfaces interface-range access-ports unit 0 family ethernet-switching vlan members Guest
set interfaces ge-0/0/47 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 20
set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 30
set interfaces ge-0/0/47 unit 0 family ethernet-switching vlan members 99
set interfaces irb unit 99 family inet address 192.168.99.1/24
set access radius-server 192.168.3.1 port 1812 <<<<< -- make sure you are matchig the port on the Access switch and the Radius Server
set access radius-server 192.168.3.1 secret "$9$cwZrKWNdsJGiLxGik.zFcylKLx-VwgaZ"
set access radius-server 192.168.3.1 source-address 192.168.99.1
set access profile auth-profile authentication-order radius
set access profile auth-profile radius authentication-server 192.168.3.1
set access profile auth-profile radius accounting-server 192.168.3.1
set routing-options static route 0.0.0.0/0 next-hop 192.168.99.254
set protocols dot1x authenticator authentication-profile-name auth-profile
set protocols dot1x authenticator no-mac-table-binding
set protocols dot1x authenticator interface access-ports supplicant multiple
set protocols dot1x authenticator interface access-ports mac-radius restrict
set protocols dot1x authenticator interface access-ports mac-radius authentication-protocol pap
set protocols dot1x authenticator interface access-ports reauthentication 28800
set protocols lldp interface all
set vlans Guest description "Guest VLAN"
set vlans Guest vlan-id 20
set vlans Guest forwarding-options dhcp-security ip-source-guard
set vlans Management description "Management VLAN"
set vlans Management vlan-id 99
set vlans Management l3-interface irb.99
set vlans Secure description "Secure VLAN"
set vlans Secure vlan-id 30
set vlans Secure forwarding-options dhcp-security ip-source-guard

 

  • Run this on VM1 to keep the radius on, even if this is started, this will monitor the freeradius messages.

root@VM2-IP232-JNPR32:~# sudo freeradius -X
FreeRADIUS Version 3.0.26
Copyright (C) 1999-2021 The FreeRADIUS server project and contributors
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE

<snipped>
Ready to process requests
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
BlastRADIUS check: Received packet without Proxy-State.
Setting "limit_proxy_state = true" for client AccessSwitch
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
The packet does not contain Message-Authenticator, which is a security issue.
UPGRADE THE CLIENT AS YOUR NETWORK MAY BE VULNERABLE TO THE BLASTRADIUS ATTACK.
Once the client is upgraded, set "require_message_authenticator = true" for client AccessSwitch
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(0) Received Access-Request Id 200 from 192.168.99.1:56300 to 192.168.3.1:1812 length 167
(0)   User-Name = "0050569e1ccf"
(0)   User-Password = "0050569e1ccf"
(0)   NAS-Port = 632
(0)   Service-Type = Call-Check
(0)   Acct-Session-Id = "8O2.1x815752d50002da85"
(0)   NAS-Port-Id = "ge-0/0/0.0"
(0)   Calling-Station-Id = "00-50-56-9e-1c-cf"
(0)   Called-Station-Id = "bc-0f-fe-08-8f-92"
(0)   EAP-Key-Name = 0x00
(0)   NAS-Identifier = "AccessSwitch"
(0)   NAS-Port-Type = Ethernet
(0)   NAS-IP-Address = 192.168.99.1
(0) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/default
(0)   authorize {
(0)     policy filter_username {
(0)       if (&User-Name) {
(0)       if (&User-Name)  -> TRUE
(0)       if (&User-Name)  {
(0)         if (&User-Name =~ / /) {
(0)         if (&User-Name =~ / /)  -> FALSE
(0)         if (&User-Name =~ /@[^@]*@/ ) {
(0)         if (&User-Name =~ /@[^@]*@/ )  -> FALSE
(0)         if (&User-Name =~ /\.\./ ) {
(0)         if (&User-Name =~ /\.\./ )  -> FALSE
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))  {
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))   -> FALSE
(0)         if (&User-Name =~ /\.$/)  {
(0)         if (&User-Name =~ /\.$/)   -> FALSE
(0)         if (&User-Name =~ /@\./)  {
(0)         if (&User-Name =~ /@\./)   -> FALSE
(0)       } # if (&User-Name)  = notfound
(0)     } # policy filter_username = notfound
(0)     [preprocess] = ok
(0)     [chap] = noop
(0)     [mschap] = noop
(0)     [digest] = noop
(0) suffix: Checking for suffix after "@"
(0) suffix: No '@' in User-Name = "0050569e1ccf", looking up realm NULL
(0) suffix: No such realm "NULL"
(0)     [suffix] = noop
(0) eap: No EAP-Message, not doing EAP
(0)     [eap] = noop
(0) files: users: Matched entry 0050569e1ccf at line 1
(0)     [files] = ok
(0)     [expiration] = noop
(0)     [logintime] = noop
(0)     [pap] = updated
(0)   } # authorize = updated
(0) Found Auth-Type = PAP
(0) # Executing group from file /etc/freeradius/3.0/sites-enabled/default
(0)   Auth-Type PAP {
(0) pap: Login attempt with password
(0) pap: Comparing with "known good" Cleartext-Password
(0) pap: User authenticated successfully
(0)     [pap] = ok
(0)   } # Auth-Type PAP = ok
(0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default
(0)   post-auth {
(0)     if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) {
(0)     if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name))  -> FALSE
(0)     update {
(0)       No attributes updated for RHS &session-state:
(0)     } # update = noop
(0)     [exec] = noop
(0)     policy remove_reply_message_if_eap {
(0)       if (&reply:EAP-Message && &reply:Reply-Message) {
(0)       if (&reply:EAP-Message && &reply:Reply-Message)  -> FALSE
(0)       else {
(0)         [noop] = noop
(0)       } # else = noop
(0)     } # policy remove_reply_message_if_eap = noop
(0)     if (EAP-Key-Name && &reply:EAP-Session-Id) {
(0)     if (EAP-Key-Name && &reply:EAP-Session-Id)  -> FALSE
(0)   } # post-auth = noop
(0) Sent Access-Accept Id 200 from 192.168.3.1:1812 to 192.168.99.1:56300 length 54
(0)   Tunnel-Type = VLAN
(0)   Tunnel-Medium-Type = IEEE-802
(0)   Tunnel-Private-Group-Id = "20"
(0) Finished request
Waking up in 4.9 seconds.
(0) Cleaning up request packet ID 200 with timestamp +28 due to cleanup_delay was reached
Ready to process requests



  •  On Core Switch:
{master:0}[edit]
root@CoreSwitch# run show dhcp server binding
IP address        Session Id  Hardware address   Expires     State      Interface
192.168.20.35     6           00:50:56:9e:1c:cf  86338       BOUND      irb.20
192.168.20.36     7           00:50:56:9e:1c:cf  86093       BOUND      irb.20

 

  • On the Access switch:

{master:0}[edit]
root@AccessSwitch# run show dot1x interface ge-0/0/0
Jan 20 12:21:34
802.1X Information:
Interface     Role           State           MAC address          User
ge-0/0/0.0    Authenticator  Authenticated   00:50:56:9E:1C:CF    0050569e1ccf

{master:0}[edit]
root@AccessSwitch# run show dhcp-security binding
Jan 20 12:21:44
IP address        MAC address         Vlan     Expires State   Interface
192.168.20.35     00:50:56:9e:1c:cf   Guest    86387   BOUND   ge-0/0/0.0

{master:0}[edit]
root@AccessSwitch# run show dhcp-security binding ip-source-guard
Jan 20 12:21:48
IP address        MAC address         Vlan     Expires State   Interface
192.168.20.35     00:50:56:9e:1c:cf   Guest    86383   BOUND   ge-0/0/0.0



root@AccessSwitch# run show ethernet-switching table
Jan 20 12:31:39

MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC
           GBP - group based policy)


Ethernet switching table : 3 entries, 3 learned
Routing instance : default-switch
    Vlan                MAC                 MAC         Age   GBP     Logical                NH        RTR
    name                address             flags             Tag     interface              Index     ID
    Guest               00:50:56:9e:1c:cf   D             -            ge-0/0/0.0             0         0
    Guest               7c:25:86:73:69:a0   D             -            ge-0/0/47.0            0         0
    Management          7c:25:86:73:69:a0   D             -            ge-0/0/47.0            0         0



{master:0}[edit]
root@AccessSwitch# run show vlans
Jan 20 12:31:50

Routing instance        VLAN name             Tag          Interfaces
default-switch          Guest                 20
                                                           ge-0/0/0.0*
                                                           ge-0/0/47.0*
default-switch          Management            99
                                                           ge-0/0/47.0*
default-switch          Secure                30
                                                           ge-0/0/47.0*
default-switch          default               1

 

Modification History

2025-01-09 : Article Created

2026-01-20 :  Font formatting has been corrected throughout the document.