FreeRADIUS & Dart API Integration Saga: Resolving PPPoE Authentication Timeouts Integrasi FreeRADIUS & Dart API: Mengatasi Timeout Otentikasi PPPoE

This document provides a comprehensive historical log and architectural post-mortem of the debugging saga to transition the ISPANA Platform to a modern, stateless, dynamic client RADIUS architecture.


πŸ—ΊοΈ Architectural Objective

The goal was to enable Stateless Dynamic Client Discovery and Subscriber Authentication via a REST-to-RADIUS bridge:

  1. Dynamic Router Registration: When an unknown MikroTik router connects, FreeRADIUS queries /api/radius/nas?ip=... to fetch its secret and register it in-memory.
  2. Stateless Authentication: Subscribers are authenticated dynamically via /api/radius/authorize, querying subscriber credentials directly from the MongoDB database through the Dart API.

πŸ“ˆ The Step-by-Step Debugging Journey

πŸ” Problem 1: Stale Configuration Files (.save Conflicts)

  • Symptoms: FreeRADIUS loaded duplicate client definitions and failed to start or processed requests using stale, static values.
  • Root Cause: Text editors created backup files (e.g., /etc/freeradius/3.0/clients.d/ispana.conf.save). FreeRADIUS blindly includes all files in clients.d/ regardless of extension.
  • Resolution: Cleaned the directory, leaving only active configuration files.

πŸ”‘ Problem 2: API Validation & JWT Bypass (401/403 Errors)

  • Symptoms: FreeRADIUS requests were rejected with 401 Unauthorized or 403 Forbidden from the Dart API.
  • Root Causes:
    1. RADIUS routes were protected by global JWT middleware.
    2. VPN subscribers took priority over PPPoE subscribers in database lookups.
    3. Status validation failed because PPPoE users use "active" while VPN users use "enabled".
  • Resolution:
    1. Bypassed JWT validation for /api/radius/* routes.
    2. Reversed query priority in vendor_remote_data_source.dart.
    3. Updated vendor_controller.dart to support both status types.

πŸ“‘ Problem 3: Wildcard Client Secret Mismatch (RADIUS Timeout)

  • Symptoms: When clients.d/ispana.conf was removed to test dynamic lookups, the router logged radius timeout.
  • Root Cause: FreeRADIUS matched the router to the catch-all subnet client dynamic_network (0.0.0.0/0) which was statically set to secret = dummy. Since the router used its true secret, signature check failed.
  • Resolution: Implemented the dynamic_clients module to dynamically register routers with their correct database secrets.

βš™οΈ Problem 4: Duplicate Virtual Server Compilation Issues

  • Symptoms: Custom authenticate block was ignored.
  • Root Cause: FreeRADIUS already had a default server dynamic-clients-server defined earlier. It loaded empty default block and ignored custom one.
  • Resolution: Deleted/commented out duplicate server definitions.

πŸ—ΊοΈ Problem 5: REST Response Mapping Mismatch (Reply vs. Control)

  • Symptoms: FreeRADIUS logged Cannot add client: Required attribute "FreeRADIUS-Client-Secret" is missing.
  • Root Cause: The REST module (rest_nas) parses API JSON response and puts attributes in the request's reply list. FreeRADIUS C-code strictly expects dynamic client details in the control list.
  • Resolution: Injected a virtual server policy (update control) to copy attributes from reply to control.

πŸ”’ Problem 6: Network Listener Virtual Server Constraint

  • Symptoms: FreeRADIUS logged Cannot add client: Virtual server default is not the same as the virtual server for the network.
  • Root Cause: Wildcard client matched on port bound to server default, but API returned FreeRADIUS-Client-Virtual-Server = "dynamic_clients".
  • Resolution: Aligned API payload in vendor_controller.dart to dynamically assign 'FreeRADIUS-Client-Virtual-Server': 'dynamic_clients'.

πŸ’‘ Problem 7: Hardcoded C-Module Virtual Server (The Final Boss)

  • Symptoms: FreeRADIUS failed to resolve dynamic clients, throwing No such virtual server "dynamic_clients".
  • Root Cause:
    1. The rlm_dynamic_clients module has virtual server name dynamic_clients hardcoded inside its C-source code.
    2. Because network listener on port 1812 is bound to default, FreeRADIUS rejected registering client under dynamic_clients.
  • Resolution (The Alignment Hack):
    1. Kept network wildcard client mapping to default.
    2. Restored hardcoded server dynamic_clients block to run the lookup.
    3. Inside server dynamic_clients's update control block, forced FreeRADIUS-Client-Virtual-Server = "default".