802.1X Port Security

802.1X port security provides a framework for controlling access to a switched Ethernet network on a per-port basis. Ports can be configured to operate in a locked state. If a port is configured this way, all user traffic is blocked until authentication completes. Only special 802.1X control messages (EAPOL frames) are allowed to reach the authenticator software running on the host.

The authenticator validates client credentials using Extensible Authentication Protocol (EAP) methods. This can be done locally by hostapd acting as an EAP server, or remotely through a RADIUS backend. Once the client is authenticated, its MAC address is explicitly installed into the forwarding database (FDB). From this point, normal Ethernet traffic for that MAC is permitted. All other sources remain blocked, ensuring that only authenticated devices can communicate through the switch.

By combining hardware enforcement in the driver and dynamic authorization logic in user space, 802.1X port security ensures that unauthorized or rogue clients cannot send traffic onto the network. It also prevents accidental leaks by disabling flooding and learning until authentication has succeeded. This provides a strong security boundary at the first hop of the network.

Setup Overview

A setup could consist of three components working together:

  • Supplicant (wpa_supplicant) running on the client device.

  • Authenticator (hostapd) running on the switch. It processes EAPOL frames and validates credentials.

  • Switch driver + Linux bridge, which enforce the locked-port behavior and only allow traffic from authorized MAC addresses.

The authenticator uses hostapd_cli, a command-line client for hostapd’s control interface, in action mode to trigger a helper script. In this mode, hostapd_cli stays connected to hostapd and listens for events such as client connect, disconnect, or EAP success/failure. When an event occurs, it executes the helper script with the event details as arguments. The script then installs or removes FDB entries dynamically, ensuring that only authenticated MAC addresses are allowed to forward traffic.

In the setup described here, hostapd is configured to act as the EAP server, validating client credentials directly. An alternative deployment is to have hostapd forward EAP requests to an external RADIUS server for authentication. This document focuses on the simpler case where hostapd itself provides the EAP server functionality.

+----------------+   +---------------------------------------------------------+
|  Client host   |   |                      Switch host                        |
|----------------|   |---------------------------------------------------------|
|                |   |  +-------------------+      +-------------------------+ |
|   Supplicant   |   |  |   Authenticator   |      | Switch Driver + Linux   | |
|(wpa_supplicant)|   |  |    (hostapd)      |      | Bridge                  | |
|                |   |  |                   |      | (FDB enforcement)       | |
|                |   |  +-------------------+      +-------------------------+ |
+----------------+   +---------------------------------------------------------+
         |                       |                           [Locked Port]
         |   EAPOL frames        |                                 |
         |---------------------->|                                 |
         |                       | Authentication decision         |
         |                       |                                 |
         |                       | hostapd_cli action script       |
         |                       | runs "bridge fdb add"           |
         |                       | (if authenticated)              |
         |                       |-------------------------------->|
         |                       |                                 v
         |                       |               [FDB add → Port Unlocked]
         |                       |                                 |
         |   Normal traffic now allowed (MAC authorized)           |
         |<--------------------------------------------------------|

Client (Supplicant)

The client must run a wired supplicant such as wpa_supplicant, which is responsible for sending 802.1X credentials to the switch. The credentials configured in the supplicant must match the EAP configuration defined in the authenticator.

wpa_supplicant.conf

Place this file at /etc/wpa_supplicant/wpa_supplicant.conf.

ctrl_interface=/var/run/wpa_supplicant
ap_scan=0

network={
    key_mgmt=IEEE8021X
    eap=MD5
    identity="testuser"
    password="password123"
    eapol_flags=0
}

Platform (Authenticator)

On the switch, a user-space authenticator daemon such as hostapd must be running. Hostapd terminates EAPOL frames from the client and authenticates the credentials. When using the internal EAP server, no external RADIUS server is required.

Hostapd listens for EAPOL frames, parses the EAP messages, and verifies them against its internal user database. When authentication succeeds, it installs the client’s MAC into the bridge FDB via a helper script. If authentication fails, the port remains locked.

hostapd.conf (internal EAP server)

Place this file at /etc/hostapd/hostapd.conf.

interface=eth1
driver=none
ieee8021x=1
eapol_version=2

# Enable internal EAP server
eap_server=1

# Define authentication method
eap_user_file=/etc/hostapd.eap_user

ctrl_interface=/var/run/hostapd
logger_syslog=-1
logger_stdout=1
logger_stdout_level=2

hostapd.eap_user

Place this file at /etc/hostapd.eap_user.

# identity   EAP method
"testuser"   MD5    "password123"

hostapd_cli Action Script

To dynamically manage FDB entries based on authentication events, run hostapd with hostapd_cli -a pointing to an action script.

Place the following script at /usr/local/sbin/hostapd-fdb.sh and make it executable (chmod +x /usr/local/sbin/hostapd-fdb.sh).

#!/usr/bin/env bash
set -euo pipefail

BRIDGE="${BRIDGE:-br0}"
VID="${VID:-}"
LOG_TAG="hostapd-fdb"

IFACE="${1:-}"
EVENT="${2:-}"

log() { logger -t "$LOG_TAG[$IFACE]" -- "$*"; }

add_fdb() {
  local mac="$1"
  if [[ -n "$VID" ]]; then
    bridge fdb add "$mac" dev "$IFACE" master static vlan "$VID" || true
  else
    bridge fdb add "$mac" dev "$IFACE" master static || true
  fi
  log "FDB ADD mac=$mac iface=$IFACE bridge=$BRIDGE vlan=${VID:-none}"
}

del_fdb() {
  local mac="$1"
  if [[ -n "$VID" ]]; then
    bridge fdb del "$mac" dev "$IFACE" master vlan "$VID" || true
  else
    bridge fdb del "$mac" dev "$IFACE" master || true
  fi
  log "FDB DEL mac=$mac iface=$IFACE bridge=$BRIDGE vlan=${VID:-none}"
}

extract_mac() {
  for token in $*; do
    if [[ "$token" =~ ^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$ ]]; then
      echo "$token"
      return 0
    fi
  done
  return 1
}

case "$EVENT" in
  AP-STA-CONNECTED*|CTRL-EVENT-EAP-SUCCESS*)
    if mac="$(extract_mac "$EVENT")"; then
      add_fdb "$mac"
    else
      log "No MAC found in connect/success event: $EVENT"
    fi
    ;;
  AP-STA-DISCONNECTED*|CTRL-EVENT-EAP-FAILURE*|CTRL-EVENT-DISCONNECTED*)
    if mac="$(extract_mac "$EVENT")"; then
      del_fdb "$mac"
    else
      log "No MAC found in disconnect/failure event: $EVENT"
    fi
    ;;
  *)
    ;;
esac

exit 0

Run it like:

hostapd_cli -i eth1 -a /usr/local/sbin/hostapd-fdb.sh -B

Control Interface (hostapd_cli)

hostapd_cli is a command-line client that communicates with the hostapd control socket. It can be used to:

  • Query station state and status information.

  • Subscribe to events such as client connection, disconnection, or EAP success/failure.

  • Run in action mode (hostapd_cli -a <script>) where it automatically executes a script when events occur.

In the port security setup, hostapd_cli is primarily used in action mode together with an event script to add or remove FDB entries dynamically based on authentication state.

Examples

Lock a Port

bridge link set dev eth1 locked on

Authorize a MAC

bridge fdb add 00:11:22:33:44:55 dev eth1 master static

Remove Authorization

bridge fdb del 00:11:22:33:44:55 dev eth1 master

Show VLANs and MAC Table

bridge vlan show dev eth1
bridge fdb show dev br0

Run the Supplicant

Start wpa_supplicant on the client:

sudo wpa_supplicant -i eth0 -c /etc/wpa_supplicant/wpa_supplicant.conf -d

Here -i specifies the client interface, -c points to the config file, and -d enables debug logging.

Run the Authenticator

Start hostapd on the switch:

sudo hostapd -dd /etc/hostapd/hostapd.conf

The -dd flag enables extra debug output for troubleshooting authentication.