Redundant SQL connection. Starting radiusd and Respond with Access-Accept if all databases do not work #2
Никита Борисенков
bna at sunlink.ru
Thu Dec 5 08:29:07 CET 2019
> The task is to allow or prohibit calls to subscribers. If the subscriber
> has valid status, then we send Access-Accept. If the subscriber calls
> the emergency service, then we send Access-Accept. In other cases, we
> send Access-Reject.
>
> I configured two radius server, and two sql server. Replication
> configured between sql servers.
>
> I write accounting and authentication to the database.
>
> I want that when one database is unavailable, data is written to another
> database. But if both databases are not available, then we send
> Access-Accept
>
> Some questions:
> * Is there a way to not duplicate config for modules sql1 and sql2
> because they differ only in ip-address?
> * Is there a way to start freeradius if one or all databases are down?
> * What is the correct way to verify that sql1 and sql2 modules are fail
> without checking "Calling-Station-Id-Is-Exists" for empty string?
> * How can I simplify this configuration?
>
>
> My config:
>
> sql sql1 {
> driver = "rlm_sql_mysql"
> dialect = "mysql"
>
> server = "localhost"
> port = 3306
> login = "radius"
> password = "test"
>
> query_timeout = 5
>
> radius_db = "radius"
>
> read_clients = no
>
> # Table to keep radius client info
> client_table = "nas"
>
> # If you want both stop and start records logged to the
> # same SQL table, leave this as is. If you want them in
> # different tables, put the start table in acct_table1
> # and stop table in acct_table2
> acct_table1 = "radacct"
> acct_table2 = "radacct"
>
> # Allow for storing data after authentication
> postauth_table = "radpostauth"
>
> # Tables containing 'check' items
> authcheck_table = "radcheck"
> groupcheck_table = "radgroupcheck"
>
> # Tables containing 'reply' items
> authreply_table = "radreply"
> groupreply_table = "radgroupreply"
>
> # Table to keep group info
> usergroup_table = "radusergroup"
>
> pool {
> start = ${thread[pool].start_servers}
> min = ${thread[pool].min_spare_servers}
> max = ${thread[pool].max_servers}
> spare = ${thread[pool].max_spare_servers}
>
> uses = 0
> retry_delay = 30
> lifetime = 0
> idle_timeout = 60
> }
>
> # This entry should be used for additional instances (sql foo {})
> # of the SQL module.
> group_attribute = "${.:instance}-SQL-Group"
>
> # This entry should be used for the default instance (sql {})
> # of the SQL module.
> #group_attribute = "SQL-Group"
>
> # Read database-specific queries
> # $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
> $INCLUDE ${modconfdir}/sql/main/${dialect}/queries.conf
> }
>
> sql sql2 {
> driver = "rlm_sql_mysql"
> dialect = "mysql"
>
> server = "172.27.65.243"
> port = 3306
> login = "radius"
> password = "test"
>
> query_timeout = 5
>
> radius_db = "radius"
>
> read_clients = no
>
> # Table to keep radius client info
> client_table = "nas"
>
> # If you want both stop and start records logged to the
> # same SQL table, leave this as is. If you want them in
> # different tables, put the start table in acct_table1
> # and stop table in acct_table2
> acct_table1 = "radacct"
> acct_table2 = "radacct"
>
> # Allow for storing data after authentication
> postauth_table = "radpostauth"
>
> # Tables containing 'check' items
> authcheck_table = "radcheck"
> groupcheck_table = "radgroupcheck"
>
> # Tables containing 'reply' items
> authreply_table = "radreply"
> groupreply_table = "radgroupreply"
>
> # Table to keep group info
> usergroup_table = "radusergroup"
>
> pool {
> start = ${thread[pool].start_servers}
> min = ${thread[pool].min_spare_servers}
> max = ${thread[pool].max_servers}
> spare = ${thread[pool].max_spare_servers}
>
> uses = 0
> retry_delay = 30
> lifetime = 0
> idle_timeout = 60
> }
>
> # This entry should be used for additional instances (sql foo {})
> # of the SQL module.
> group_attribute = "${.:instance}-SQL-Group"
>
> # This entry should be used for the default instance (sql {})
> # of the SQL module.
> #group_attribute = "SQL-Group"
>
> # Read database-specific queries
> #$INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
> $INCLUDE ${modconfdir}/sql/main/${dialect}/queries.conf
> }
>
> # Create virtual module for SELECTs
> instantiate {
> redundant sql1_or_sql2 {
> sql1
> sql2
> }
> }
>
> server ats_local {
> authorize {
> update control {
> Calling-Station-Id-Status = "%{sql1_or_sql2:SELECT
> gtdb_users.status FROM gtdb_users WHERE aon='%{Calling-Station-Id}'}"
> Called-Station-Id-Status = "%{sql1_or_sql2:SELECT
> gtdb_users.status FROM gtdb_users WHERE aon='%{Called-Station-Id}'}"
>
> Calling-Station-Id-Is-Exists = "%{sql1_or_sql2:SELECT
> COUNT(gtdb_users.status) FROM gtdb_users WHERE
> aon='%{Calling-Station-Id}'}"
> Called-Station-Id-Is-Exists = "%{sql1_or_sql2:SELECT
> COUNT(gtdb_users.status) FROM gtdb_users WHERE
> aon='%{Called-Station-Id}'}"
>
> Called-Station-Id-Emergency = "%{sql1_or_sql2:SELECT
> COUNT(aon) FROM emergency_cid WHERE aon='%{Called-Station-Id}'}"
> }
>
> # These attributes in normal condition must contain the number
> >= 0 (because we use sql COUNT() )
> # If there is an empty string inside, then sql queries failed
> for some reason and we return Access-Accept
>
> if (&control:Calling-Station-Id-Is-Exists == '' ||
> &control:Called-Station-Id-Is-Exists == '') {
> update control {
> Auth-Type := Accept
> }
> }
> else {
> if (control:Called-Station-Id-Emergency == '1') {
> update control {
> Auth-Type := Accept
> }
> }
>
> # ...
> # bunch of elsif for Calling-Station-Id-Status and
> Called-Station-Id-Status
> # ...
>
> else {
> update control {
> Auth-Type := Reject
> }
> }
> }
> }
>
>
> authenticate {
> }
>
> preacct {
> acct_unique
> }
>
> $INCLUDE ${confdir}/ats_accounting.conf
>
> session {
> }
>
> post-auth {
> update reply {
> cisco-avpair = "h323-credit-time=86400"
> }
>
> if (&User-Name) {
> # this not work, because I can't put "ok" to virtual module
> "sql1_or_sql2"
> # sql1_or_sql2
> redundant {
> sql1
> sql2
> ok
> }
> }
>
> Post-Auth-Type REJECT {
> if (&User-Name) {
> redundant {
> sql1
> sql2
> ok
> }
> }
> }
>
> }
>
> pre-proxy {
> }
>
> post-proxy {
> }
> }
> See raddb/templates.conf You can put all of the configuration
> *except* the "server" file into a "template" in that file. Then
> configure two SQL modules:
>
> sql sql1 {
> $template sql_template
> server = localhost
> }
>
> sql sql2 {
> $template sql_template
> server = 172.27.65.243
> }
>
>
> > * Is there a way to start freeradius if one or all databases are down?
>
> See the pool config. This is documented. Set "start = 0", and "min
> = 0"
>
> > * What is the correct way to verify that sql1 and sql2 modules are
> fail without checking "Calling-Station-Id-Is-Exists" for empty string?
>
> Use a "redundant" block.
>
> > * How can I simplify this configuration?
>
> It seems OK to me.
>
> Alan DeKok.
Sorry for repeating the message, I mistakenly deleted all previous messages.
Thanks for the help. Everything worked out for me. The config began to
look more simple.
All my problems were due to the fact that I did not read the
documentation. And I also deleted all the comments from the
configuration files to make it easier to read, but in the end I made it
worse for myself. Now I make a copy and rename the file to
"*_with_comments" to look into it if necessary.
More information about the Freeradius-Users
mailing list