|
I was previously running straight 2.15 (and perl
5.6.0, incidentally), except for a single patch to Radius.pm that allows it to
send responses to NASes correctly even when ipaddresses and
netmasks were retrieved from Auth modules in BINARY format (i.e.
4-ascii-character). (BTW, thanks for sticking that request into 2.16,
Mike - though I'm happy to say that I've learned a lot of perl, and I could now
parse it in PostAuthHook, if I had to :D ).
My config is below. I had been letting Radiator use its internal session database,
though I don't really need the session limits at this time (I'll do it with SQL
when I overcome a problem unrelated to this message). Everything was working
great. I installed 2.16, and restarted radiusd, and
immediately, nobody was able to log in. Enabling Trace 4 and a
glance at the debug log showed that everyone was being denied because "session
limit of 1 exceeded" (I may have the exact phrasing wrong).
Well, I wasn't sure what might have changed between
2.15 and 2.16 that would break my config, but having read the release notes, I
was sure I knew how to work around it quickly and give myself time to figure it
out. I quickly added the <SessionDatabase NULL> lines you see at the
bottom of the config (no, my comments there aren't actually in the config, I
only put those in this message to help illustrate) and restarted
radiusd.
Much to my chagrin, the problem didn't go away. I
then added the MaxSessions line and restarted again. Still no improvement. Well,
I had been down for about three minutes at this point, which isn't good, so I
backed out and reinstalled 2.15 (putting Mike's patched Radius.pm back
in place) and restarted again (I didn't even take the MaxSessions or the
<SessionDatabase NULL> out of the config). Ahhh...all better. I let
everything hum happily for 15 or 20 minutes before testing a bit
more.
I reinstalled 2.16, restarted, and everything broke
again exactly as it had before. I reinstalled 2.15, restarted, and everything
was happy again. That last cycle was just to be sure I hadn't
inadvertently broken something in the config myself, so I did these steps
without even touching it.
So, Mike, Hugh, or anyone: any ideas what I may be
doing that's incompatible with 2.16? It must be something unusual, because I
haven't heard anyone else screaming about this problem.
AuthPort 1812 AcctPort 1813 BindAddress 209.xxx.xxx.xxx LogDir /var/log/radius DbDir /usr/local/etc/radius.cfg.d PidFile /var/run/radiusd.pid LivingstonOffs 22 LivingstonHole 1 Trace 4
# Username rewriting rules # First, downcase the whole thing RewriteUsername tr/A-Z/a-z/ # Remove all white space RewriteUsername s/\s+//g # For Mailsite interoperability, change %'s to @'s RewriteUsername tr/%/@/ # Convert Microsoft domain syntax to Internet RewriteUsername s/(^.*)[\/\\]+(.*)/$2\@$1/ # Change realm txdirect* or idworld* (with no suffix or any suffix that starts with a .) to realm idworld.net RewriteUsername s/[\@\.]+(?:idworld|txdirect)(?:\..*$|$)/\@idworld.net/ # If no realm, make it @idworld.net RewriteUsername s/^([^@]*)$/$1\@idworld.net/ include %D/clients.cfg # For testing from localhost <Client 209.xxx.xxx.xxx> Secret xxxxxx NasType NortelCVX1800 </Client> PreClientHook file:"%D/PreClientHook.pl" <Realm DEFAULT> MaxSession 9999999 <---- (2nd thing I did) PreAuthHook file:"%D/PreAuthHook.pl" PostAuthHook file:"%D/PostAuthHook.pl" <AuthBy SQL> DBSource dbi:mysql:idaaa DBUsername radiusd DBAuth xxxxxxxx AuthSelect \ select \ password, \ status, \ find_in_set('dialup',services), \ simultaneoususe, \ ipaddress, \ netmask, \ dialuptype, \ portlimit, \ checkitems, \ replyitems \ from subscribers where \ mailbox = '%U' and \ domain = '%R' AuthColumnDef 0, User-Password, check AuthColumnDef 1, IDI-Status, reply AuthColumnDef 2, IDI-Dialup-Enabled, reply AuthColumnDef 3, Simultaneous-Use, check AuthColumnDef 4, Framed-IP-Address, reply AuthColumnDef 5, Framed-IP-Netmask, reply AuthColumnDef 6, IDI-Dialup-Type, reply AuthColumnDef 7, Port-Limit, reply AuthColumnDef 8, GENERIC, check AuthColumnDef 9, GENERIC, reply AcctSQLStatement \ insert into accounting set \ mailbox = '%U', \ domain = '%R', \ timestamp = from_unixtime(%{Timestamp}), \ statustype = '%{IDI-Acct-Status-Type-Int}', \ ipaddress = %{IDI-SQL-Framed-IP-Address}, \ inputoctets = '%{Acct-Input-Octets}', \ outputoctets = '%{Acct-Output-Octets}', \ sessionid = '%{Acct-Session-Id}', \ sessiontime = '%{Acct-Session-Time}', \ terminatecause = '%{IDI-Terminate-Cause}', \ nasipaddress = %{IDI-SQL-NAS-IP-Address}, \ nasport = '%{NAS-Port}', \ nasporttype = '%{IDI-NAS-Port-Type-Int}', \ servicetype = '%{IDI-Service-Type-Int}', \ callednumber = '%{Called-Station-Id}', \ callingnumber = '%{Calling-Station-Id}' </AuthBy> </Realm>
<SessionDatabase NULL> <---- (1st thing I did) </SessionDatabase> <---- (1st thing I did)
And here are hooks:
PreClientHook:
# Our PreClientHook's job is to extrapolate a few more bits of info to # facilitate logging, storing them in some pseudo-attributes. Note that # Acct-Terminate-Cause and Ascend-Disconnect-Cause are combined into one # and that we shift A-D-C up 8 bits so we can tell them apart when # examining our logs. sub { &main::log($main::LOG_DEBUG, "Entering PreClientHook"); my $request = ${$_[0]}; if ($request->code eq 'Accounting-Request') { &main::log($main::LOG_DEBUG, "Adding IDI pseudo-attributes to accounting request"); $request->add_attr('IDI-Terminate-Cause', ($request->{Dict}->valNameToNum('Acct-Terminate-Cause', $request->get_attr('Acct-Terminate-Cause'))) | ($request->{Dict}->valNameToNum('Ascend-Disconnect-Cause', $request->get_attr('Ascend-Disconnect-Cause')) << 8)); $request->add_attr('IDI-Acct-Status-Type-Int', $request->{Dict}->valNameToNum('Acct-Status-Type', $request->get_attr('Acct-Status-Type'))); $request->add_attr('IDI-NAS-Port-Type-Int', $request->{Dict}->valNameToNum('NAS-Port-Type', $request->get_attr('NAS-Port-Type'))); $request->add_attr('IDI-Service-Type-Int', $request->{Dict}->valNameToNum('Service-Type', $request->get_attr('Service-Type'))); my $octets = $request->getNasId(); $octets =~ tr/\./,/; $request->add_attr('IDI-SQL-NAS-IP-Address', "char($octets)"); $octets = $request->get_attr('Framed-IP-Address'); $octets =~ tr/\./,/; $octets or $octets = '0,0,0,0'; $request->add_attr('IDI-SQL-Framed-IP-Address', "char($octets)"); } &main::log($main::LOG_DEBUG, "Exiting PreClientHook"); }
PreAuthHook:
# This hook is a kludge to make things compatible with MailSite's authentication # from the same database. Since we want everyone to be able to use their email # address as their login, and MailSite understands that some of our SPECIFIC # domains are considered synonyms of our main domain, idworld.net, we have to # make Radiator understand that, too. sub { &main::log($main::LOG_DEBUG, "Entering PreAuthHook"); my $request = ${$_[0]}; my $reply = ${$_[1]}; if ($request->code eq 'Access-Request') { my ($mailbox, $domain) = split(/@/, $request->getAttrByNum($Radius::Radius::USER_NAME),2); if (-e "/usr/local/etc/idworld-synonyms/$domain") { $domain = 'idworld.net'; $request->changeAttrByNum($Radius::Radius::USER_NAME, "$mailbox\@$domain"); &main::log($main::LOG_DEBUG, "Rewrote user name to $mailbox\@$domain (synonym)"); } } &main::log($main::LOG_DEBUG, "Exiting PreAuthHook"); }
PostAuthHook:
# This PostAuthHook accomplishes three things: 1. It extrapolates some # implicit timeouts based on the subscriber's dialup 'type' (unlimited, # metered, or dedicated) and sticks those in the reply packet; 2. It # notices if the NAS is an Ascend NAS and converts several attributes # to Ascend's syntax (including the aforementioned timeouts) and adds # a couple more that Ascends seem to need. We've been doing this for # years, and perhaps Ascend has corrected this incompatibility, but I # don't feel like finding out, and it WORKS this way; 3. It checks # a couple of other requirements before accepting an Access-Request: # The customer must have a status of 'active' (as opposed to 'locked' # or 'cancelled'), and must be enabled for 'dialup' service (remember, # we use this same database for authentication of other services, such # as email-only accounts). Otherwise, change the reply to a deny and # strip the unneeded attributes. sub { &main::log($main::LOG_DEBUG, "Entering PostAuthHook"); my $request = ${$_[0]}; my $reply = ${$_[1]}; my $denied = ${$_[2]}; if (not $denied and $request->code eq 'Access-Request') { my $status = $reply->get_attr('IDI-Status'); my $dialup = $reply->get_attr('IDI-Dialup-Enabled'); $reply->delete_attr('IDI-Status'); $reply->delete_attr('IDI-Dialup-Enabled'); if ($status eq 'active' and $dialup) { &main::log($main::LOG_DEBUG, "Extrapolating timeouts for Access-Accept"); $reply->change_attr('Idle-Timeout', 900); $reply->change_attr('Session-Timeout', 36000); if ($reply->get_attr('IDI-Dialup-Type') eq 'metered') { $reply->change_attr('Session-Timeout', 0); } elsif ($reply->get_attr('IDI-Dialup-Type') eq 'dedicated') { $reply->change_attr('Idle-Timeout', 0); $reply->change_attr('Session-Timeout', 0); } if ($request->{Client}->{NasType} =~ /^Ascend/) { &main::log($main::LOG_DEBUG, "Converting Access-Accept for NasType Ascend"); $reply->change_attr('Ascend-Idle-Limit', $reply->get_attr('Idle-Timeout')); $reply->delete_attr('Idle-Timeout'); $reply->change_attr('Ascend-Maximum-Time', $reply->get_attr('Session-Timeout')); $reply->delete_attr('Session-Timeout'); $reply->change_attr('Ascend-Maximum-Channels', $reply->get_attr('Port-Limit')); $reply->delete_attr('Port-Limit'); $reply->change_attr('Ascend-PPP-Address', $reply->get_attr('Ascend-PPP-Address') || '209.142.75.128'); $reply->change_attr('Ascend-Route-IP', $reply->get_attr('Ascend-Route-IP') || 'Route-IP-Yes'); } } else { ${$_[2]} = $denied = 1; $reply->delete_attr('Framed-IP-Address'); $reply->delete_attr('Framed-IP-Netmask'); $reply->delete_attr('Port-Limit'); my $message = 'Access rejected for ' . $request->get_attr('User-Name') . ': '; if ($dialup) { $message .= "\u$status"; } else { $message .= 'Not enabled for dialup service'; } &main::log($main::LOG_INFO, $message); } } $reply->delete_attr('IDI-Dialup-Type'); &main::log($main::LOG_DEBUG, "Exiting PostAuthHook"); }
Thanks in advance for any help any of you might be
able to provide.
Mike Nerone
|