feat(freeradius): implement node pinning and dynamic IP allocation

- add node pinning logic in authorize (reject if wrong node)
- optimize SQL queries using control variables
- assign Pool-Name dynamically for engineers
- integrate sqlippool for dynamic IP allocation (engineers only)
- add Session-Timeout aligned with lease_duration
- fix duplicate sqlippool execution in post-auth/accounting
- configure sqlippool with NAS-IP scoping for multi-node isolation

Ensures correct routing, tenant isolation, and scalable IP management.
This commit is contained in:
2026-04-20 16:15:55 +02:00
parent fca66dfa52
commit 69a4e3a3b8
2 changed files with 45 additions and 15 deletions
+2 -2
View File
@@ -30,7 +30,7 @@ sqlippool {
# That way the NAS will automatically kick the user offline when the # That way the NAS will automatically kick the user offline when the
# lease expires. # lease expires.
# #
lease_duration = 86400 lease_duration = 18000
# #
# Timeout between each consecutive 'allocate_clear' queries (default: 1s) # Timeout between each consecutive 'allocate_clear' queries (default: 1s)
@@ -76,7 +76,7 @@ sqlippool {
# pool_key = "%{NAS-Port}" # pool_key = "%{NAS-Port}"
# pool_key = "%{Calling-Station-Id}" # pool_key = "%{Calling-Station-Id}"
pool_key = "%{User-Name}" pool_key = "%{User-Name}"
nas_ip_address = "%{NAS-IP-Address}"
################################################################ ################################################################
# #
# WARNING: MySQL (MyISAM) has certain limitations that means it can # WARNING: MySQL (MyISAM) has certain limitations that means it can
+43 -13
View File
@@ -418,20 +418,31 @@ authorize {
# #
# See "Authorization Queries" in mods-available/sql # See "Authorization Queries" in mods-available/sql
sql sql
### Node pinning + client type (optimized)
update control { update control {
Tmp-String-0 := "%{sql:SELECT node_ip FROM node_assignments WHERE username='%{User-Name}'}" Tmp-String-0 := "%{sql:SELECT node_ip FROM node_assignments WHERE username='%{User-Name}'}"
} Tmp-String-1 := "%{sql:SELECT client_type FROM node_assignments WHERE username='%{User-Name}'}"
}
if (&control:Tmp-String-0 == "") { # No assignment → reject
reject if (&control:Tmp-String-0 == "") {
} reject
}
if (&control:Tmp-String-0 != "%{NAS-IP-Address}") { # Wrong node → reject (string compare to avoid type mismatch)
update reply { if ("%{control:Tmp-String-0}" != "%{NAS-IP-Address}") {
Reply-Message := "Wrong node" update reply {
} Reply-Message := "Wrong node (%{NAS-IP-Address}) expected %{control:Tmp-String-0}"
reject }
} reject
}
# Engineers → dynamic pool
if (&control:Tmp-String-1 == "engineer") {
update control {
Pool-Name := "engineers-%{sql:SELECT SUBSTRING_INDEX('%{User-Name}','@',-1)}"
}
}
# If you are using /etc/smbpasswd, and are also doing mschap authentication, the un-comment this line, and configure the 'smbpasswd' module. # If you are using /etc/smbpasswd, and are also doing mschap authentication, the un-comment this line, and configure the 'smbpasswd' module.
# smbpasswd # smbpasswd
@@ -632,8 +643,17 @@ accounting {
# Return an address to the IP Pool when we see a stop record. # Return an address to the IP Pool when we see a stop record.
# Ensure that &control:Pool-Name is set to determine which pool of IPs are used. # Ensure that &control:Pool-Name is set to determine which pool of IPs are used.
sqlippool # sqlippool
### rebuild Pool-Name
update control {
Pool-Name := "engineers-%{sql:SELECT SUBSTRING_INDEX('%{User-Name}','@',-1)}"
}
### apply only for engineers
if (&control:Pool-Name =~ /^engineers-/) {
sqlippool
}
# Log traffic to an SQL database. # Log traffic to an SQL database.
# See "Accounting queries" in mods-available/sql # See "Accounting queries" in mods-available/sql
sql sql
@@ -765,8 +785,18 @@ post-auth {
# #
# Ensure that &control:Pool-Name is set to determine which # Ensure that &control:Pool-Name is set to determine which
# pool of IPs are used. # pool of IPs are used.
sqlippool # sqlippool
# Engineers → dynamic IP
#
if (&control:Pool-Name =~ /^engineers-/) {
update reply {
Session-Timeout := 3600
}
sqlippool
}
# Create the CUI value and add the attribute to Access-Accept. # Create the CUI value and add the attribute to Access-Accept.
# Uncomment the line below if *returning* the CUI. # Uncomment the line below if *returning* the CUI.