/dev/null proxy accounting while proxy sink is unresponsive

jared r r spiegel jrrs at ice-nine.org
Wed Nov 16 00:54:58 CET 2011


  hi.

  thanks for freeradius.  we converted from Radiator to freeradius and
  were able to halve the size of our radius cluster while still handling
  more load.

  we're using multiple detail files defined in radiusd.conf, which
  then sites-enabled/default defines as redundant-load-balance, so
  accounting gets written to them round-robin by freeradius.

  then we have another sites-enabled/ "site" defining multiple
  servers each listen to one of the accounting files and Proxy-To-Realm
  them to a realm which is defined in proxy.conf.

  the realm in proxy.conf has home_servers and home_server_pools
  defined for multiple different realms, each sending to different
  proxy sinks.  some sinks are just one host, some are multiple.

  this all works pretty much great, except when a proxy-sink fails to
  ACK the accounting we send it (thus being seen as dead or zombie).

  there are a small number of cases where we would love it if we could just
  /dev/null this proxy accounting if the remote server is dead/zombie,
  however i haven't figured out a way to actually configure this.

  it seems like i want to use a "fallback" server in the home_server_pool,
  where that fallback server would just 'ok' accounting or otherwise toss it
  in the trash, but after a few iterations of trying to make this work
  i have come up empty handed.

  if anyone can help, i'd be enormously grateful.

  here are the sanitized configs.

  so for example, i'd like to add a virtual server to the 
  'home_server_pool proxy-whatever' that would toss the accounting from the
  detail file into /dev/null for whatever period of fime site-1 and site-2
  were dead/zombie.

[proxy.conf]
------------------------------------------------------------------------------
# $Id: proxy.conf 34303 2011-10-26 20:31:34Z jrrs $

# This entry controls the behavior towards ALL other servers we proxy
# requests to.
proxy server {
	# Never, ever fall back to the DEFAULT realm when no
	# home servers are alive for a given ream.
	default_fallback = no
}

home_server proxy-whatever01-site-1 {
	type = acct
	ipaddr = 1.1.1.1
	port = 1845
	secret = "zz"
	status_check = none
	response_window = 10
}

home_server proxy-whatever01-site-2 {
	type = acct
	ipaddr = 2.2.2.2
	port = 1845
	secret = "zz"
	status_check = none
	response_window = 10
}

home_server_pool proxy-whatever {
	type = fail-over
	home_server = proxy-whatever01-site-1
	home_server = proxy-whatever01-site-2
}

realm proxy-whatever {
	acct_pool = proxy-whatever
	nostrip
}

[sites-enabled/default]
# $Id: default 34587 2011-11-15 22:45:31Z jrrs $

authorize {
	preprocess
	update request {
		Client-IP-Address := "%{Client-IP-Address}"
	}
	chap
	mschap
	suffix
	perl
	switch "%{Auth-Type}" {
		case 'sql.auth.wifi.site3' {
			redundant {
				sql.auth.wifi.site2
				sql.auth.wifi.site1
			}
		}
		case 'sql.auth.wifi.site2' {
			redundant {
				sql.auth.wifi.site2
				sql.auth.wifi.site1
			}
		}
		case 'sql.auth.wifi.site1' {
			redundant {
				sql.auth.wifi.site1
				sql.auth.wifi.site2
			}
		}
	}
	pap
}

authenticate {
	Auth-Type PAP {
		pap
	}
	Auth-Type CHAP {
		chap
	}
	Auth-Type MS-CHAP {
		mschap
	}
	Auth-Type ldap.site3 {
		redundant {
			ldap.site3
			ldap.site2
			ldap.site1
		}
	}
	Auth-Type ldap.site2 {
		redundant {
			ldap.site2
			ldap.site1
			ldap.site3
		}
	}
	Auth-Type ldap.site1 {
		redundant {
			ldap.site1
			ldap.site2
			ldap.site3
		}
	}
}

preacct {
	perl
}

accounting {
	perl
	redundant-load-balance {
		detail.proxy-whatever0
		detail.proxy-whatever1
		detail.proxy-whatever2
		detail.proxy-whatever3
		detail.proxy-whatever4
	}

	attr_filter.accounting_response
}

session {
}

post-auth {
	Post-Auth-Type REJECT {
		sql.authlog
		attr_filter.access_reject
	}
}

pre-proxy {
}

post-proxy {
	if ("%{proxy-reply:Packet-Type}" == "Access-Accept") {
		attr_filter.post-proxy
	}
}

[sites-enabled/proxy-tee]
# $Id: proxy-tee 34011 2011-10-18 02:35:39Z jrrs $

server buffered-proxy-whatever0 {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever0
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}

server buffered-proxy-whatever1 {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever1
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}

server buffered-proxy-whatever2 {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever2
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}

server buffered-proxy-whatever3 {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever3
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}

server buffered-proxy-whatever4 {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever4
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}

server buffered-proxy-whatever-catchup {
	listen {
		type = detail
		filename = ${radacctdir}/proxy-whatever-catchup
		load_factor = 100
	}
	preacct {
		if ("%{%{#User-Name}:-0}" <= 63 && "%{User-Name}" != "@") {
			attr_filter.proxy_whatever
			update control {
				Proxy-To-Realm := "proxy-whatever"
			}
		}
	}
	accounting {
		ok
	}
}


[radiusd.conf]
------------------------------------------------------------------------------
# -*- text -*-
##
## radiusd.conf	-- FreeRADIUS server configuration file.
##
##	http://www.freeradius.org/
##	$Id: radiusd.conf.in,v 1.272 2008/04/26 15:14:33 aland Exp $
##

prefix = /usr
exec_prefix = /usr
sysconfdir = /etc
localstatedir = /var
sbindir = ${exec_prefix}/sbin
logdir = /var/log/freeradius
raddbdir = /etc/freeradius
radacctdir = ${logdir}/radacct

confdir = ${raddbdir}
run_dir = ${localstatedir}/run/freeradius
db_dir = ${raddbdir}
libdir = /usr/lib/freeradius

pidfile = ${run_dir}/freeradius.pid

user = freerad
group = freerad
max_request_time = 30
cleanup_delay = 5
max_requests = 131072
listen {
	type = auth
	ipaddr = *
	port = 0
}

listen {
	ipaddr = *
	port = 0 
	type = acct
}
hostname_lookups = no
allow_core_dumps = no
regular_expressions = yes
extended_expressions = yes

log syslog {
	destination = syslog
	syslog_facility = daemon
	stripped_names = no
	auth = no
	auth_badpass = no
	auth_goodpass = no
}

checkrad = ${sbindir}/checkrad

security {
	max_attributes = 200
	reject_delay = 0
	status_server = yes
}

proxy_requests  = yes
$INCLUDE proxy.conf

$INCLUDE clients.conf

thread pool {
	start_servers = 32
	max_servers = 160
	min_spare_servers = 16
	max_spare_servers = 32
	max_requests_per_server = 0
}

modules {
	pap {
		auto_header = no
	}
	chap {
		authtype = CHAP
	}
	mschap {
	}
	ldap ldap.site3 {
		server = "ldap.pool.example.com ldap.site3.example.com"
		identity = "cn=Radiusd,o=example"
		password = "xx"
		basedn = "o=nonexistent"
		ldap_connections_number = 3
		timeout = 6
		timelimit = 5
		net_timeout = 1
		dictionary_mapping = ${confdir}/ldap.attrmap
		password_attribute = userPassword
	}
	ldap ldap.site2 {
		server = "ldap.pool.example.com ldap.site2.example.com"
		identity = "cn=Radiusd,o=example"
		password = "xx"
		basedn = "o=nonexistent"
		ldap_connections_number = 3
		timeout = 6
		timelimit = 5
		net_timeout = 1
		dictionary_mapping = ${confdir}/ldap.attrmap
		password_attribute = userPassword
	}
	ldap ldap.site1 {
		server = "ldap.pool.example.com ldap01.vip.example.com ldap02.vip.example.com"
		identity = "cn=Radiusd,o=example"
		password = "xx"
		basedn = "o=nonexistent"
		ldap_connections_number = 3
		timeout = 6
		timelimit = 5
		net_timeout = 1
		dictionary_mapping = ${confdir}/ldap.attrmap
		password_attribute = userPassword
	}
	perl {
		module = /etc/freeradius/IT_group.pm
		func_authorize = authorize
		func_preacct = preacct
		func_accounting = accounting
		max_clones = 160
		start_clones = 32
		min_spare_clones = 16
		max_spare_clones = 32
		cleanup_delay = 5
		max_request_per_clone = 0
	}
	realm suffix {
		format = suffix
		delimiter = "@"
	}
	preprocess {
	}

	detail detail.proxy-whatever0 {
		detailfile = ${radacctdir}/proxy-whatever0
		detailperm = 0640
		header = "%t"
	}
	detail detail.proxy-whatever1 {
		detailfile = ${radacctdir}/proxy-whatever1
		detailperm = 0640
		header = "%t"
	}
	detail detail.proxy-whatever2 {
		detailfile = ${radacctdir}/proxy-whatever2
		detailperm = 0640
		header = "%t"
	}
	detail detail.proxy-whatever3 {
		detailfile = ${radacctdir}/proxy-whatever3
		detailperm = 0640
		header = "%t"
	}
	detail detail.proxy-whatever4 {
		detailfile = ${radacctdir}/proxy-whatever4
		detailperm = 0640
		header = "%t"
	}

	sql_log sql.authlog {
		path = "${logdir}/failedauth/%Y%m%d-%H"
		Post-Auth = "%l	%{NAS-IP-Address}	%{%{reply:Reply-Message}:-%{Module-Failure-Message}}	%{User-Name}	%{%{User-Password}:-%{Chap-Password}}"
	}

	sql sql.acct {
		database = "mysql"
		driver = "rlm_sql_${database}"
		server = "write.sql.example.com"
		login = "radiusd"
		password = "yy"
		radius_db = "radius"
		acct_table = "ACCOUNTING"
		sqltrace = no
		sqltracefile = ${logdir}/sqltrace.sql
		num_sql_socks = 5
		connect_failure_retry_delay = 5
		lifetime = 0
		max_queries = 0
		sql_user_name = "%{User-Name}"

		accounting_start_query = " \
			INSERT INTO ${acct_table} ( \
				USERNAME, TIME_STAMP, ACCTSTATUSTYPE, ACCTDELAYTIME, \
				ACCTINPUTOCTETS, ACCTOUTPUTOCTETS, ACCTSESSIONID, \
				ACCTSESSIONTIME, ACCTTERMINATECAUSE, NASIP, NASPORT, \
				FRAMEDIPADDRESS, CALLED_STATION, CALLING_STATION \
			) VALUES( \
				'%{SQL-User-Name}', '%l', '%{Acct-Status-Type}', \
				'%{Acct-Delay-Time}', '%{Acct-Input-Octets}', \
				'%{Acct-Output-Octets}', '%{Acct-Session-Id}', \
				'%{Acct-Session-Time}', '%{Acct-Terminate-Cause}', \
				'%{NAS-IP-Address}', '%{NAS-Port}', \
				'%{Framed-IP-Address}', '%{Called-Station-Id}', \
				'%{Calling-Station-Id}');"

		accounting_stop_query = " \
			INSERT INTO ${acct_table} ( \
				USERNAME, TIME_STAMP, ACCTSTATUSTYPE, ACCTDELAYTIME, \
				ACCTINPUTOCTETS, ACCTOUTPUTOCTETS, ACCTSESSIONID, \
				ACCTSESSIONTIME, ACCTTERMINATECAUSE, NASIP, NASPORT, \
				FRAMEDIPADDRESS, CALLED_STATION, CALLING_STATION \
			) VALUES( \
				'%{SQL-User-Name}', '%l', '%{Acct-Status-Type}', \
				'%{Acct-Delay-Time}', '%{Acct-Input-Octets}', \
				'%{Acct-Output-Octets}', '%{Acct-Session-Id}', \
				'%{Acct-Session-Time}', '%{Acct-Terminate-Cause}', \
				'%{NAS-IP-Address}', '%{NAS-Port}', \
				'%{Framed-IP-Address}', '%{Called-Station-Id}', \
				'%{Calling-Station-Id}')"
	}

	sql sql.auth.wifi.site2 {
		database = "mysql"
		driver = "rlm_sql_${database}"
		server = "3.3.3.3"
		login = "radiusd"
		password = "yy"
		num_sql_socks = 3
		connect_failure_retry_delay = 60
		radius_db = "backend"
		authcheck_table = "wifi_users"
		authreply_table = "wifi_users"
		sqltrace = no
		sqltracefile = ${logdir}/sqltrace.sql
		sql_user_name = "%{User-Name}"
		authorize_check_query = " \
			SELECT NULL as id, \
			       '%{SQL-User-Name}' as username, \
			       'Cleartext-Password' AS attribute, \
			       userPassword AS value, \
			       ':=' AS op \
			  FROM ${authcheck_table} \
			 WHERE uid = '%{SQL-User-Name}'"

		authorize_reply_query = " \
			SELECT NULL as id, \
			       '%{SQL-User-Name}' as username, \
			       'Whatever-Service-Bundle' AS attribute, \
			       serviceType AS value, \
			       ':=' AS op \
			  FROM ${authcheck_table} \
			 WHERE uid = '%{SQL-User-Name}'"
	}

	sql sql.auth.wifi.site1 {
		database = "mysql"
		driver = "rlm_sql_${database}"
		server = "authread.sql.example.com"
		login = "radiusd"
		password = "yy"
		num_sql_socks = 3
		connect_failure_retry_delay = 60
		radius_db = "backend"
		authcheck_table = "wifi_users"
		authreply_table = "wifi_users"
		sqltrace = no
		sqltracefile = ${logdir}/sqltrace.sql
		sql_user_name = "%{User-Name}"
		authorize_check_query = " \
			SELECT NULL as id, \
			       '%{SQL-User-Name}' as username, \
			       'Cleartext-Password' AS attribute, \
			       userPassword AS value, \
			       ':=' AS op \
			  FROM ${authcheck_table} \
			 WHERE uid = '%{SQL-User-Name}'"

		authorize_reply_query = " \
			SELECT NULL as id, \
			       '%{SQL-User-Name}' as username, \
			       'Whatever-Service-Bundle' AS attribute, \
			       serviceType AS value, \
			       ':=' AS op \
			  FROM ${authcheck_table} \
			 WHERE uid = '%{SQL-User-Name}'"
	}
	attr_filter attr_filter.pre-proxy {
		attrsfile = ${confdir}/attrs.pre-proxy
	}
	attr_filter attr_filter.post-proxy {
		attrsfile = ${confdir}/attrs.post-proxy
	}
	attr_filter attr_filter.access_reject {
		key = %{User-Name}
		attrsfile = ${confdir}/attrs.access_reject
	}
	attr_filter attr_filter.accounting_response {
		key = %{User-Name}
		attrsfile = ${confdir}/attrs.accounting_response
	}
	attr_filter attr_filter.proxy_whatever {
		key = "DEFAULT"
		attrsfile = ${confdir}/attrs.proxy_whatever
	}
	always ok {
		rcode = ok
	}
}

$INCLUDE sites-enabled/


-- 

  jared



More information about the Freeradius-Users mailing list