diff --git a/net/freeradius/Makefile b/net/freeradius/Makefile index 25ae21e74..fcf7a8a36 100644 --- a/net/freeradius/Makefile +++ b/net/freeradius/Makefile @@ -1,5 +1,5 @@ PLUGIN_NAME= freeradius -PLUGIN_VERSION= 1.9.4 +PLUGIN_VERSION= 1.9.5 PLUGIN_COMMENT= RADIUS Authentication, Authorization and Accounting Server PLUGIN_DEPENDS= freeradius3 PLUGIN_MAINTAINER= m.muenz@gmail.com diff --git a/net/freeradius/pkg-descr b/net/freeradius/pkg-descr index 134f325b6..3a02d99bb 100644 --- a/net/freeradius/pkg-descr +++ b/net/freeradius/pkg-descr @@ -15,6 +15,10 @@ The server is fast, feature-rich, modular, and scalable. Plugin Changelog ================ +1.9.5 + +* Fix SQLite support + 1.9.4 * Add Service-Type to user form diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/+TARGETS b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/+TARGETS index 228fec66e..083726a5d 100644 --- a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/+TARGETS +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/+TARGETS @@ -8,6 +8,7 @@ mods-enabled-ldap:/usr/local/etc/raddb/mods-enabled/ldap mods-enabled-sql:/usr/local/etc/raddb/mods-enabled/sql mods-enabled-sqlippool:/usr/local/etc/raddb/mods-enabled/sqlippool queries.conf:/usr/local/etc/raddb/mods-config/sql/main/sqlite/queries.conf +queries2.conf:/usr/local/etc/raddb/mods-config/sql/ippool/sqlite/queries.conf radiusd:/etc/rc.conf.d/radiusd radiusd.conf:/usr/local/etc/raddb/radiusd.conf sites-enabled-default:/usr/local/etc/raddb/sites-enabled/default diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-dhcp_sqlippool b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-dhcp_sqlippool index 5437dcfee..de614dcf2 100644 --- a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-dhcp_sqlippool +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-dhcp_sqlippool @@ -5,29 +5,33 @@ sqlippool dhcp_sqlippool { ippool_table = "radippool" + # Name of the check item attribute to be used as a key in the SQL queries + pool_name = "Pool-Name" + lease_duration = 7200 # Client's MAC address is mapped to Calling-Station-Id in policy.conf pool_key = "%{Calling-Station-Id}" # For now, it works with MySQL. - #$INCLUDE ${modconfdir}/sql/ippool-dhcp/mysql/queries.conf + $INCLUDE ${modconfdir}/sql/ippool-dhcp/mysql/queries.conf # It may also work with sqlite - this is very experimental. # Comment out the above line and add the following include. # To use sqlite you need to add '%' to safe_characters in # raddb/mods-config/sql/main/sqlite/queries.conf. - $INCLUDE ${modconfdir}/sql/ippool-dhcp/sqlite/queries.conf + # $INCLUDE ${modconfdir}/sql/ippool-dhcp/sqlite/queries.conf sqlippool_log_exists = "DHCP: Existing IP: %{reply:Framed-IP-Address} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" - sqlippool_log_success = "DHCP: Allocated IP: %{reply:Framed-IP-Address} from %{control:Pool-Name} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + sqlippool_log_success = "DHCP: Allocated IP: %{reply:Framed-IP-Address} from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" sqlippool_log_clear = "DHCP: Released IP %{Framed-IP-Address} (did %{Called-Station-Id} cli %{Calling-Station-Id} user %{User-Name})" - sqlippool_log_failed = "DHCP: IP Allocation FAILED from %{control:Pool-Name} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + sqlippool_log_failed = "DHCP: IP Allocation FAILED from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" - sqlippool_log_nopool = "DHCP: No Pool-Name defined (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + sqlippool_log_nopool = "DHCP: No ${..pool_name} defined (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" } + {% endif %} diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sql b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sql index a999e7da5..5ca9063ce 100644 --- a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sql +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sql @@ -2,21 +2,13 @@ {% if helpers.exists('OPNsense.freeradius.general.sqlite') and OPNsense.freeradius.general.sqlite == '1' %} sql { + dialect = "sqlite" driver = "rlm_sql_sqlite" sqlite { - # Path to the sqlite database filename = "/usr/local/etc/raddb/freeradius.db" - - # How long to wait for write locks on the database to be - # released (in ms) before giving up. busy_timeout = 200 - - # If the file above does not exist and bootstrap is set - # a new database file will be created, and the SQL statements - # contained within the bootstrap file will be executed. bootstrap = "${modconfdir}/${..:name}/main/sqlite/schema.sql" } - dialect = "sqlite" radius_db = "radius" acct_table1 = "radacct" acct_table2 = "radacct" diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sqlippool b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sqlippool index de7a306a5..36ca7646d 100644 --- a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sqlippool +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/mods-enabled-sqlippool @@ -1,7 +1,7 @@ {% if helpers.exists('OPNsense.freeradius.general.sqlite') and OPNsense.freeradius.general.sqlite == '1' %} sqlippool { - # SQL instance to use (from sql.conf) + # SQL instance to use (from mods-available/sql) # # If you have multiple sql instances, such as "sql sql1 {...}", # use the *instance* name here: sql1. @@ -12,14 +12,53 @@ sqlippool { # reference expansions. dialect = "sqlite" + # Name of the check item attribute to be used as a key in the SQL queries + pool_name = "Pool-Name" + # SQL table to use for ippool range and lease info ippool_table = "radippool" # IP lease duration. (Leases expire even if Acct Stop packet is lost) lease_duration = 3600 - # protocol to use. The default is IPv4. -# ipv6 = yes + # + # Timeout between each consecutive 'allocate_clear' queries (default: 1s) + # This will avoid having too many deadlock issues, especially on MySQL backend. + # + allocate_clear_timeout = 1 + + # + # As of 3.0.16, the 'ipv6 = yes' configuration is deprecated. + # You should use the "attribute_name" configuration item + # below, instead. + # + + # + # The attribute to use for IP address assignment. The + # default is Framed-IP-Address. You can change this to any + # attribute which is IPv4 or IPv6. + # + # e.g. Framed-IPv6-Prefix, or Delegated-IPv6-Prefix. + # + # As of 3.0.16, all of the default queries have been updated to use + # this attribute_name. So you can do IPv6 address assignment simply + # by putting IPv6 addresses into the pool, and changing the following + # line to "Framed-IPv6-Prefix" + # + # Note that you MUST use separate pools for each attribute. i.e. one pool + # for Framed-IP-Address, a different one for Framed-IPv6-prefix, etc. + # + # This means configuring separate "sqlippool" instances, and different + # "ippool_table" in SQL. Then, populate the pool with addresses and + # it will all just work. + # + attribute_name = Framed-IP-Address + + # + # Assign the IP address, even if the above attribute already exists + # in the reply. + # +# allow_duplicates = no # Attribute which should be considered unique per NAS # @@ -47,18 +86,19 @@ sqlippool { # which writes Module-Success-Message message. # messages { - exists = "Existing IP: %{reply:Framed-IP-Address} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + exists = "Existing IP: %{reply:${..attribute_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" - success = "Allocated IP: %{reply:Framed-IP-Address} from %{control:Pool-Name} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + success = "Allocated IP: %{reply:${..attribute_name}} from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" - clear = "Released IP %{Framed-IP-Address} (did %{Called-Station-Id} cli %{Calling-Station-Id} user %{User-Name})" + clear = "Released IP ${..attribute_name} (did %{Called-Station-Id} cli %{Calling-Station-Id} user %{User-Name})" - failed = "IP Allocation FAILED from %{control:Pool-Name} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + failed = "IP Allocation FAILED from %{control:${..pool_name}} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" - nopool = "No Pool-Name defined (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" + nopool = "No ${..pool_name} defined (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})" } $INCLUDE ${modconfdir}/sql/ippool/${dialect}/queries.conf } + {% endif %} diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries.conf b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries.conf index 67c20d874..7345a9b88 100644 --- a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries.conf +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries.conf @@ -3,12 +3,97 @@ safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /%" {% raw %} +####################################################################### +# Query config: Username +####################################################################### +# This is the username that will get substituted, escaped, and added +# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below +# everywhere a username substitution is needed so you you can be sure +# the username passed from the client is escaped properly. +# +# Uncomment the next line, if you want the sql_user_name to mean: +# +# Use Stripped-User-Name, if it's there. +# Else use User-Name, if it's there, +# Else use hard-coded string "DEFAULT" as the user name. +#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}" +# sql_user_name = "%{User-Name}" +####################################################################### +# Default profile +####################################################################### +# This is the default profile. It is found in SQL by group membership. +# That means that this profile must be a member of at least one group +# which will contain the corresponding check and reply items. +# This profile will be queried in the authorize section for every user. +# The point is to assign all users a default profile without having to +# manually add each one to a group that will contain the profile. +# The SQL module will also honor the User-Profile attribute. This +# attribute can be set anywhere in the authorize section (ie the users +# file). It is found exactly as the default profile is found. +# If it is set then it will *overwrite* the default profile setting. +# The idea is to select profiles based on checks on the incoming packets, +# not on user group membership. For example: +# -- users file -- +# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound" +# DEFAULT Service-Type == Framed-User, User-Profile := "framed" +# +# By default the default_user_profile is not set +# +#default_user_profile = "DEFAULT" + +####################################################################### +# NAS Query +####################################################################### +# This query retrieves the radius clients +# +# 0. Row ID (currently unused) +# 1. Name (or IP address) +# 2. Shortname +# 3. Type +# 4. Secret +# 5. Server +####################################################################### + client_query = "\ SELECT id, nasname, shortname, type, secret, server \ FROM ${client_table}" +####################################################################### +# Authorization Queries +####################################################################### +# These queries compare the check items for the user +# in ${authcheck_table} and setup the reply items in +# ${authreply_table}. You can use any query/tables +# you want, but the return data for each row MUST +# be in the following order: +# +# 0. Row ID (currently unused) +# 1. UserName/GroupName +# 2. Item Attr Name +# 3. Item Attr Value +# 4. Item Attr Operation +####################################################################### + +# +# Use these for case sensitive usernames. +# +#authorize_check_query = "\ +# SELECT id, username, attribute, value, op \ +# FROM ${authcheck_table} \ +# WHERE username = BINARY '%{SQL-User-Name}' \ +# ORDER BY id" + +#authorize_reply_query = "\ +# SELECT id, username, attribute, value, op \ +# FROM ${authreply_table} \ +# WHERE username = BINARY '%{SQL-User-Name}' \ +# ORDER BY id" + +# +# The default queries are case insensitive. (for compatibility with older versions of FreeRADIUS) +# authorize_check_query = "\ SELECT id, username, attribute, value, op \ FROM ${authcheck_table} \ @@ -21,6 +106,15 @@ authorize_reply_query = "\ WHERE username = '%{SQL-User-Name}' \ ORDER BY id" +# +# Use these for case sensitive usernames. +# +#group_membership_query = "\ +# SELECT groupname \ +# FROM ${usergroup_table} \ +# WHERE username = BINARY '%{SQL-User-Name}' \ +# ORDER BY priority" + group_membership_query = "\ SELECT groupname \ FROM ${usergroup_table} \ @@ -41,6 +135,18 @@ authorize_group_reply_query = "\ WHERE groupname = '%{${group_attribute}}' \ ORDER BY id" +####################################################################### +# Simultaneous Use Checking Queries +####################################################################### +# simul_count_query - query for the number of current connections +# - If this is not defined, no simultaneous use checking +# - will be performed by this module instance +# simul_verify_query - query to return details of current connections +# for verification +# - Leave blank or commented out to disable verification step +# - Note that the returned field order should not be changed. +####################################################################### + simul_count_query = "\ SELECT COUNT(*) \ FROM ${acct_table1} \ @@ -54,8 +160,25 @@ simul_verify_query = "\ WHERE username = '%{${group_attribute}}' \ AND acctstoptime IS NULL" +####################################################################### +# Accounting and Post-Auth Queries +####################################################################### +# These queries insert/update accounting and authentication records. +# The query to use is determined by the value of 'reference'. +# This value is used as a configuration path and should resolve to one +# or more 'query's. If reference points to multiple queries, and a query +# fails, the next query is executed. +# +# Behaviour is identical to the old 1.x/2.x module, except we can now +# fail between N queries, and query selection can be based on any +# combination of attributes, or custom 'Acct-Status-Type' values. +####################################################################### accounting { - reference = "%{tolower:type.%{Acct-Status-Type}.query}" + reference = "%{tolower:type.%{%{Acct-Status-Type}:-%{Request-Processing-Stage}}.query}" + + # Write SQL queries to a logfile. This is potentially useful for bulk inserts + # when used with the rlm_sql_null driver. +# logfile = ${logdir}/accounting.sql column_list = "\ acctsessionid, \ @@ -79,7 +202,11 @@ accounting { acctterminatecause, \ servicetype, \ framedprotocol, \ - framedipaddress" + framedipaddress, \ + framedipv6address, \ + framedipv6prefix, \ + framedinterfaceid, \ + delegatedipv6prefix" type { accounting-on { @@ -95,7 +222,7 @@ accounting { - strftime('%%s', acctstarttime)), \ acctterminatecause = '%{Acct-Terminate-Cause}' \ WHERE acctstoptime IS NULL \ - AND nasipaddress = '%{NAS-IP-Address}' \ + AND nasipaddress = '%{NAS-IP-Address}' \ AND acctstarttime <= %{integer:Event-Timestamp}" } @@ -103,6 +230,58 @@ accounting { query = "${..accounting-on.query}" } + # + # Implement the "sql_session_start" policy. + # See raddb/policy.d/accounting for more details. + # + # You also need to fix the other queries as + # documented below. Look for "sql_session_start". + # + post-auth { + query = "\ + INSERT INTO ${....acct_table1} \ + (${...column_list}) \ + VALUES(\ + '%{Acct-Session-Id}', \ + '%{Acct-Unique-Session-Id}', \ + '%{SQL-User-Name}', \ + '%{Realm}', \ + '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \ + NULLIF('%{%{NAS-Port-ID}:-%{NAS-Port}}', ''), \ + '%{NAS-Port-Type}', \ + %{%{integer:Event-Timestamp}:-date('now')}, \ + NULL, \ + NULL, \ + 0, \ + '', \ + '%{Connect-Info}', \ + NULL, \ + 0, \ + 0, \ + '%{Called-Station-Id}', \ + '%{Calling-Station-Id}', \ + NULL, \ + '%{Service-Type}', \ + NULL, \ + '', \ + '', \ + '', \ + '', \ + '')" + + query = "\ + UPDATE ${....acct_table1} SET \ + AcctStartTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + AcctUpdateTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + ConnectInfo_start = '%{Connect-Info}', \ + AcctSessionId = '%{Acct-Session-Id}' \ + WHERE UserName = '%{SQL-User-Name}' \ + AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \ + AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \ + AND NASPortType = '%{NAS-Port-Type}' \ + AND AcctStopTime IS NULL" + } + start { # # Insert a new record into the sessions table @@ -132,23 +311,71 @@ accounting { '', \ '%{Service-Type}', \ '%{Framed-Protocol}', \ - '%{Framed-IP-Address}')" + '%{Framed-IP-Address}', \ + '%{Framed-IPv6-Address}', \ + '%{Framed-IPv6-Prefix}', \ + '%{Framed-Interface-Id}', \ + '%{Delegated-IPv6-Prefix}')" + # + # When using "sql_session_start", you should comment out + # the previous query, and enable this one. + # + # Just change the previous query to "-query", + # and this one to "query". The previous one + # will be ignored, and this one will be + # enabled. + # + -query = "\ + UPDATE ${....acct_table1} \ + SET \ + AcctSessionId = '%{Acct-Session-Id}', \ + AcctUniqueId = '%{Acct-Unique-Session-Id}', \ + AcctAuthentic = '%{Acct-Authentic}', \ + ConnectInfo_start = '%{Connect-Info}', \ + ServiceType = '%{Service-Type}', \ + FramedProtocol = '%{Framed-Protocol}', \ + framedipaddress = '%{Framed-IP-Address}', \ + framedipv6address = '%{Framed-IPv6-Address}', \ + framedipv6prefix = '%{Framed-IPv6-Prefix}', \ + framedinterfaceid = '%{Framed-Interface-Id}', \ + delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \ + AcctStartTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + AcctUpdateTime = %{%{integer:Event-Timestamp}:-date('now')} \ + WHERE UserName = '%{SQL-User-Name}' \ + AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \ + AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \ + AND NASPortType = '%{NAS-Port-Type}' \ + AND AcctStopTime IS NULL" + + # + # Key constraints prevented us from inserting a new session, + # use the alternate query to update an existing session. + # query = "\ UPDATE ${....acct_table1} SET \ acctstarttime = %{%{integer:Event-Timestamp}:-date('now')}, \ - acctupdatetime = %{%{integer:Event-Timestamp}:-date('now'))}, \ + acctupdatetime = %{%{integer:Event-Timestamp}:-date('now')}, \ connectinfo_start = '%{Connect-Info}' \ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'" } interim-update { + # + # Update an existing session and calculate the interval + # between the last data we received for the session and this + # update. This can be used to find stale sessions. + # query = "\ UPDATE ${....acct_table1} \ SET \ acctupdatetime = %{%{integer:Event-Timestamp}:-date('now')}, \ acctinterval = 0, \ framedipaddress = '%{Framed-IP-Address}', \ + framedipv6address = '%{Framed-IPv6-Address}', \ + framedipv6prefix = '%{Framed-IPv6-Prefix}', \ + framedinterfaceid = '%{Framed-Interface-Id}', \ + delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \ acctsessiontime = %{%{Acct-Session-Time}:-NULL}, \ acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \ << 32 | %{%{Acct-Input-Octets}:-0}, \ @@ -156,6 +383,10 @@ accounting { << 32 | %{%{Acct-Output-Octets}:-0} \ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'" + # + # The update condition matched no existing sessions. Use + # the values provided in the update to create a new session. + # query = "\ INSERT INTO ${....acct_table1} \ (${...column_list}) \ @@ -183,10 +414,53 @@ accounting { '', \ '%{Service-Type}', \ '%{Framed-Protocol}', \ - '%{Framed-IP-Address}')" + '%{Framed-IP-Address}', \ + '%{Framed-IPv6-Address}', \ + '%{Framed-IPv6-Prefix}', \ + '%{Framed-Interface-Id}', \ + '%{Delegated-IPv6-Prefix}')" + + # + # When using "sql_session_start", you should comment out + # the previous query, and enable this one. + # + # Just change the previous query to "-query", + # and this one to "query". The previous one + # will be ignored, and this one will be + # enabled. + # + -query = "\ + UPDATE ${....acct_table1} \ + SET \ + AcctSessionId = '%{Acct-Session-Id}', \ + AcctUniqueId = '%{Acct-Unique-Session-Id}', \ + AcctAuthentic = '%{Acct-Authentic}', \ + ConnectInfo_start = '%{Connect-Info}', \ + ServiceType = '%{Service-Type}', \ + FramedProtocol = '%{Framed-Protocol}', \ + framedipaddress = '%{Framed-IP-Address}', \ + framedipv6address = '%{Framed-IPv6-Address}', \ + framedipv6prefix = '%{Framed-IPv6-Prefix}', \ + framedinterfaceid = '%{Framed-Interface-Id}', \ + delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \ + AcctUpdateTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \ + AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \ + << 32 | '%{%{Acct-Input-Octets}:-0}', \ + AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \ + << 32 | '%{%{Acct-Output-Octets}:-0}' \ + WHERE UserName = '%{SQL-User-Name}' \ + AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \ + AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \ + AND NASPortType = '%{NAS-Port-Type}' \ + AND AcctStopTime IS NULL" + } stop { + # + # Session has terminated, update the stop time and statistics. + # query = "\ UPDATE ${....acct_table2} SET \ acctstoptime = %{%{integer:Event-Timestamp}:-date('now')}, \ @@ -199,6 +473,10 @@ accounting { connectinfo_stop = '%{Connect-Info}' \ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'" + # + # The update condition matched no existing sessions. Use + # the values provided in the update to create a new session. + # query = "\ INSERT INTO ${....acct_table2} \ (${...column_list}) \ @@ -226,12 +504,73 @@ accounting { '%{Acct-Terminate-Cause}', \ '%{Service-Type}', \ '%{Framed-Protocol}', \ - '%{Framed-IP-Address}')" + '%{Framed-IP-Address}', \ + '%{Framed-IPv6-Address}', \ + '%{Framed-IPv6-Prefix}', \ + '%{Framed-Interface-Id}', \ + '%{Delegated-IPv6-Prefix}')" + + # + # When using "sql_session_start", you should comment out + # the previous query, and enable this one. + # + # Just change the previous query to "-query", + # and this one to "query". The previous one + # will be ignored, and this one will be + # enabled. + # + -query = "\ + UPDATE ${....acct_table1} \ + SET \ + AcctSessionId = '%{Acct-Session-Id}', \ + AcctUniqueId = '%{Acct-Unique-Session-Id}', \ + AcctAuthentic = '%{Acct-Authentic}', \ + ConnectInfo_start = '%{Connect-Info}', \ + ServiceType = '%{Service-Type}', \ + FramedProtocol = '%{Framed-Protocol}', \ + framedipaddress = '%{Framed-IP-Address}', \ + framedipv6address = '%{Framed-IPv6-Address}', \ + framedipv6prefix = '%{Framed-IPv6-Prefix}', \ + framedinterfaceid = '%{Framed-Interface-Id}', \ + delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \ + AcctStopTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + AcctUpdateTime = %{%{integer:Event-Timestamp}:-date('now')}, \ + AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \ + AcctInputOctets = '%{%{Acct-Input-Gigawords}:-0}' \ + << 32 | '%{%{Acct-Input-Octets}:-0}', \ + AcctOutputOctets = '%{%{Acct-Output-Gigawords}:-0}' \ + << 32 | '%{%{Acct-Output-Octets}:-0}', \ + AcctTerminateCause = '%{Acct-Terminate-Cause}', \ + ConnectInfo_stop = '%{Connect-Info}' \ + WHERE UserName = '%{SQL-User-Name}' \ + AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \ + AND NASPortId = '%{%{NAS-Port-ID}:-%{NAS-Port}}' \ + AND NASPortType = '%{NAS-Port-Type}' \ + AND AcctStopTime IS NULL" + + } + + + # + # No Acct-Status-Type == ignore the packet + # + accounting { + query = "SELECT true" } } } +####################################################################### +# Authentication Logging Queries +####################################################################### +# postauth_query - Insert some info after authentication +####################################################################### + post-auth { + # Write SQL queries to a logfile. This is potentially useful for bulk inserts + # when used with the rlm_sql_null driver. +# logfile = ${logdir}/post-auth.sql + query = "\ INSERT INTO ${..postauth_table} \ (username, pass, reply, authdate) \ diff --git a/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries2.conf b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries2.conf new file mode 100644 index 000000000..4abc70cfb --- /dev/null +++ b/net/freeradius/src/opnsense/service/templates/OPNsense/Freeradius/queries2.conf @@ -0,0 +1,170 @@ +{% if helpers.exists('OPNsense.freeradius.general.sqlite') and OPNsense.freeradius.general.sqlite == '1' %} +{% raw %} +# -*- text -*- +# +# ippool/sqlite/queries.conf -- SQLite queries for rlm_sqlippool +# +# $Id: 31a5df365949cd02dfc0505cab3de7fa09150565 $ + +# +# This series of queries allocates an IP address +# +#allocate_clear = "\ +# UPDATE ${ippool_table} \ +# SET \ +# nasipaddress = '', pool_key = 0, \ +# callingstationid = '', username = '', \ +# expiry_time = NULL \ +# WHERE pool_key = '${pool_key}'" + +# +# This series of queries allocates an IP address +# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port +# then you may wish to delete the "AND nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' +# from the WHERE clause) +# +allocate_clear = "\ + UPDATE ${ippool_table} \ + SET \ + nasipaddress = '', \ + pool_key = 0, \ + callingstationid = '', \ + username = '', \ + expiry_time = NULL \ + WHERE expiry_time <= datetime(strftime('%%s', 'now') - 1, 'unixepoch') \ + AND nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'" + +# +# The ORDER BY clause of this query tries to allocate the same IP-address +# which user had last session... +# +allocate_find = "\ + SELECT framedipaddress \ + FROM ${ippool_table} \ + WHERE pool_name = '%{control:${pool_name}}' \ + AND ( \ + ( expiry_time < datetime('now') OR expiry_time IS NULL ) \ + OR ( nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' ) \ + ) \ + ORDER BY \ + (username <> '%{User-Name}'), \ + (callingstationid <> '%{Calling-Station-Id}'), \ + expiry_time \ + LIMIT 1 \ + FOR UPDATE" + +# +# If you prefer to allocate a random IP address every time, i +# use this query instead +# Note: This is very slow if you have a lot of free IPs. +# + +#allocate_find = "\ +# SELECT framedipaddress \ +# FROM ${ippool_table} \ +# WHERE pool_name = '%{control:${pool_name}}' \ +# AND expiry_time IS NULL \ +# ORDER BY RAND() \ +# LIMIT 1 \ +# FOR UPDATE" + +# +# If an IP could not be allocated, check to see if the pool exists or not +# This allows the module to differentiate between a full pool and no pool +# Note: If you are not running redundant pool modules this query may be +# commented out to save running this query every time an ip is not allocated. +# +pool_check = "\ + SELECT id \ + FROM ${ippool_table} \ + WHERE pool_name='%{control:${pool_name}}' \ + LIMIT 1" + +# +# This is the final IP Allocation query, which saves the allocated ip details +# +allocate_update = "\ + UPDATE ${ippool_table} \ + SET \ + nasipaddress = '%{NAS-IP-Address}', \ + pool_key = '${pool_key}', \ + callingstationid = '%{Calling-Station-Id}', \ + username = '%{User-Name}', \ + expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \ + WHERE framedipaddress = '%I'" + + +# +# This series of queries frees an IP number when an accounting START record arrives +# +start_update = "\ + UPDATE ${ippool_table} \ + SET \ + expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \ + WHERE nasipaddress = '%{NAS-IP-Address}' \ + AND pool_key = '${pool_key}' \ + AND username = '%{User-Name}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND framedipaddress = '%{${attribute_name}}'" + +# +# This series of queries frees an IP number when an accounting STOP record arrives +# +stop_clear = "\ + UPDATE ${ippool_table} \ + SET \ + nasipaddress = '', \ + pool_key = 0, \ + callingstationid = '', \ + username = '', \ + expiry_time = NULL \ + WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \ + AND pool_key = '${pool_key}' \ + AND username = '%{User-Name}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND framedipaddress = '%{${attribute_name}}'" + +# +# This series of queries frees an IP number when an accounting +# ALIVE record arrives +# +alive_update = "\ + UPDATE ${ippool_table} \ + SET \ + expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \ + WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \ + AND pool_key = '${pool_key}' \ + AND username = '%{User-Name}' \ + AND callingstationid = '%{Calling-Station-Id}' \ + AND framedipaddress = '%{${attribute_name}}'" + +# +# This series of queries frees the IP numbers allocate to a +# NAS when an accounting ON record arrives +# +on_clear = "\ + UPDATE ${ippool_table} \ + SET \ + nasipaddress = '', \ + pool_key = 0, \ + callingstationid = '', \ + username = '', \ + expiry_time = NULL \ + WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'" + +# +# This series of queries frees the IP numbers allocate to a +# NAS when an accounting OFF record arrives +# +off_clear = "\ + UPDATE ${ippool_table} \ + SET \ + nasipaddress = '', \ + pool_key = 0, \ + callingstationid = '', \ + username = '', \ + expiry_time = NULL \ + WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'" + +{% endraw %} +{% endif %}