diff --git a/UPGRADING b/UPGRADING index c25f28c34d6982145be388f36ccc95cdd2fb0a07..e0e12693a1b0fe9d7c63a2e212befb2010d9c2d6 100644 --- a/UPGRADING +++ b/UPGRADING @@ -1,3 +1,9 @@ + +2011-01-11: + Move configuration file item "use_packet_timestamp=" to "[radius]" section + +--- + r574: # Database diff --git a/smradius/config.pm b/smradius/config.pm index 3143f1912eb8d90aa1a346bd34e74a200a654983..d81bb7d38351fe4509577ae6a6dd1e31ad16ae0f 100644 --- a/smradius/config.pm +++ b/smradius/config.pm @@ -63,17 +63,17 @@ sub Init $server->{'smradius'}{'database'} = $db; # Setup event timezone config - if (defined($config->{'server'}{'event_timezone'})) { - $server->{'smradius'}{'event_timezone'} = $config->{'server'}{'event_timezone'}; + if (defined($config->{'system'}{'event_timezone'})) { + $server->{'smradius'}{'event_timezone'} = $config->{'system'}{'event_timezone'}; } else { $server->{'smradius'}{'event_timezone'} = "GMT"; } # Should we use the packet timestamp? - if (defined($config->{'server'}{'use_packet_timestamp'})) { - if ($config->{'server'}{'use_packet_timestamp'} =~ /^\s*(yes|true|1)\s*$/i) { + if (defined($config->{'radius'}{'use_packet_timestamp'})) { + if ($config->{'radius'}{'use_packet_timestamp'} =~ /^\s*(yes|true|1)\s*$/i) { $server->{'smradius'}{'use_packet_timestamp'} = 1; - } elsif ($config->{'server'}{'use_packet_timestamp'} =~ /^\s*(no|false|0)\s*$/i) { + } elsif ($config->{'radius'}{'use_packet_timestamp'} =~ /^\s*(no|false|0)\s*$/i) { $server->{'smradius'}{'use_packet_timestamp'} = 0; } else { $server->log(LOG_NOTICE,"smradius/config.pm: Value for 'use_packet_timestamp' is invalid"); @@ -82,8 +82,43 @@ sub Init $server->{'smradius'}{'use_packet_timestamp'} = 0; } + # Should we use abuse prevention? + if (defined($config->{'radius'}{'use_abuse_prevention'})) { + if ($config->{'radius'}{'use_abuse_prevention'} =~ /^\s*(yes|true|1)\s*$/i) { + $server->{'smradius'}{'use_abuse_prevention'} = 1; + } elsif ($config->{'radius'}{'use_abuse_prevention'} =~ /^\s*(no|false|0)\s*$/i) { + $server->{'smradius'}{'use_abuse_prevention'} = 0; + } else { + $server->log(LOG_NOTICE,"smradius/config.pm: Value for 'use_abuse_prevention' is invalid"); + } + } else { + $server->{'smradius'}{'use_abuse_prevention'} = 0; + } + if (defined($config->{'radius'}{'access_request_abuse_threshold'})) { + if ($config->{'radius'}{'access_request_abuse_threshold'} =~ /^[1-9][0-9]*$/i) { + $server->{'smradius'}{'access_request_abuse_threshold'} = $config->{'radius'}{'access_request_abuse_threshold'}; + } else { + $server->log(LOG_NOTICE,"smradius/config.pm: Value for 'access_request_abuse_threshold' is invalid"); + } + } else { + $server->{'smradius'}{'access_request_abuse_threshold'} = 10; + } + if (defined($config->{'radius'}{'accounting_request_abuse_threshold'})) { + if ($config->{'radius'}{'accounting_request_abuse_threshold'} =~ /^[1-9][0-9]*$/i) { + $server->{'smradius'}{'accounting_request_abuse_threshold'} = $config->{'radius'}{'accounting_request_abuse_threshold'}; + } else { + $server->log(LOG_NOTICE,"smradius/config.pm: Value for 'accounting_request_abuse_threshold' is invalid"); + } + } else { + $server->{'smradius'}{'accounting_request_abuse_threshold'} = 5; + } + $server->log(LOG_NOTICE,"smradius/config.pm: Using ". ( $server->{'smradius'}{'use_packet_timestamp'} ? 'packet' : 'server' ) ." timestamp"); $server->log(LOG_NOTICE,"smradius/config.pm: Using timezone '".$server->{'smradius'}{'event_timezone'}."'"); + $server->log(LOG_NOTICE,"smradius/config.pm: Abuse prevention ".( $server->{'smradius'}{'use_abuse_prevention'} ? + 'active (access-threshold = '.$server->{'smradius'}{'access_request_abuse_threshold'}. + ', accounting-threshold = '.$server->{'smradius'}{'accounting_request_abuse_threshold'}.')' + : 'inactive')); } diff --git a/smradiusd b/smradiusd index 32ea1d1940409ff4825f09d727d9668ddcf095db..2362c4a247c54058fa7fdb246c437d30ee98f454 100755 --- a/smradiusd +++ b/smradiusd @@ -348,7 +348,7 @@ sub post_configure_hook { $self->log(LOG_INFO,"[SMRADIUS] Initializing system modules."); # Init caching engine -# awitpt::cache::Init($self); + awitpt::cache::Init($self); $self->log(LOG_INFO,"[SMRADIUS] System modules initialized."); } @@ -447,9 +447,12 @@ sub process_request { return; } - # Profiling... + # Very first timer ... my $timer0 = [gettimeofday]; + # Grab NOW() + my $now = time(); + # Parse packet my $pkt = new Radius::Packet($self->{'radius'}->{'dictionary'},$udp_packet); @@ -479,7 +482,7 @@ sub process_request { $timeout = 120; } # Get time left - my $timepassed = time() - $self->{'client'}->{'dbh_status'}; + my $timepassed = $now - $self->{'client'}->{'dbh_status'}; # Then check... if ($timepassed >= $timeout) { $self->log(LOG_WARN,"[SMRADIUS] Client BYPASS timeout exceeded, reconnecting..."); @@ -512,7 +515,7 @@ sub process_request { if (defined($pkt->rawattr('Event-Timestamp')) && $self->{'smradius'}->{'use_packet_timestamp'}) { $user->{'_Internal'}->{'Timestamp-Unix'} = $pkt->rawattr('Event-Timestamp'); } else { - $user->{'_Internal'}->{'Timestamp-Unix'} = time(); + $user->{'_Internal'}->{'Timestamp-Unix'} = $now; } # VERY IMPORTANT!!!!!! @@ -526,6 +529,25 @@ sub process_request { # Set username $user->{'Username'} = $pkt->attr('User-Name'); + # First thing we do is to make sure the NAS behaves if we using abuse prevention + if ($self->{'smradius'}->{'use_abuse_prevention'} && defined($user->{'Username'})) { + my ($res,$val) = cacheGetKeyPair('FloodCheck',$server->{'peeraddr'}."/".$user->{'Username'}."/".$pkt->code); + if (defined($val)) { + my $timePeriod = $now - $val; + if ($pkt->code eq "Access-Request" && $timePeriod < $self-{'smradius'}->{'access_request_abuse_threshold'}) { + $self->log(LOG_WARN,"[SMRADIUS] ABUSE: Server trying too fast. server = ".$server->{'peeraddr'}.", user = ".$user->{'Username'}. + ", code = ".$pkt->code.", timeout = ".($now - $val)); + return; + } elsif ($pkt->code eq "Accounting-Request" && $timePeriod < $self->{'smradius'}->{'accounting_request_abuse_threshold'}) { + $self->log(LOG_WARN,"[SMRADIUS] ABUSE: Server trying too fast. server = ".$server->{'peeraddr'}.", user = ".$user->{'Username'}. + ", code = ".$pkt->code.", timeout = ".($now - $val)); + return; + } + } + # We give the benefit of the doubt and let a query take 60s. We update to right stamp at end of this function + cacheStoreKeyPair('FloodCheck',$server->{'peeraddr'}."/".$user->{'Username'}."/".$pkt->code,$now + 60); + } + # # GRAB & PROCESS CONFIG # @@ -561,6 +583,9 @@ sub process_request { } } + # Get the user timer + my $timer1 = [gettimeofday]; + # FIXME - need secret # FIXME - need acl list @@ -613,6 +638,9 @@ sub process_request { } } + # Process the packet timer + my $timer2 = [gettimeofday]; + # Is this an accounting request if ($pkt->code eq "Accounting-Request") { @@ -1025,9 +1053,16 @@ CHECK_RESULT: } # END - my $timer1 = [gettimeofday]; - my $timediff = tv_interval($timer0,$timer1); - $self->log(LOG_NOTICE,"[SMRADIUS] Result: $logReason (${timediff}s) => $logLine"); + my $timer9 = [gettimeofday]; + my $timediff1 = tv_interval($timer0,$timer1); + my $timediff2 = tv_interval($timer1,$timer2); + my $timediff = tv_interval($timer0,$timer9); + $self->log(LOG_NOTICE,"[SMRADIUS] Result: $logReason (%.3fs + %.3fs = %.3fs) => $logLine",$timediff1,$timediff2,$timediff); + + # If we using abuse prevention record the time we ending off + if ($self->{'smradius'}->{'use_abuse_prevention'} && defined($user->{'Username'})) { + cacheStoreKeyPair('FloodCheck',$server->{'peeraddr'}."/".$user->{'Username'}."/".$pkt->code,time()); + } return; } @@ -1041,7 +1076,7 @@ sub server_exit $self->log(LOG_DEBUG,"Destroying system modules."); # Destroy cache -# cbp::cache::Destroy($self); + awitpt::cache::Destroy($self); $self->log(LOG_DEBUG,"System modules destroyed."); # Parent exit diff --git a/smradiusd.conf b/smradiusd.conf index f6c8e78f9d5169a422852c235bbdce9e0838855d..6c816e5436a8ad74c344a6dbbb6dc5796b1e0bc1 100644 --- a/smradiusd.conf +++ b/smradiusd.conf @@ -72,6 +72,8 @@ # Defaults to "GMT" event_timezone=GMT + +[radius] # Use packet timestamp, if unset, the default is to use the server # timestamp at the moment the packet is received. # @@ -82,8 +84,27 @@ event_timezone=GMT # first user logs in .. BAM, you'll have sessions with a period key # in current month but an event timestamp in 1970. # +# Defaults to "no" #use_packet_timestamp=yes +# Radius server abuse prevention +# +# Abuse prevention will drop packets which flood the radius server, +# or are duplicated in a short timeframe. You probably want this if +# you are not being fed by a radius proxy. +# +# Defaults to "no" +#use_abuse_prevention=no + +# How fast can a NAS spam the same type of request +# +# Access-Request defaults to 10s +#access_request_abuse_threshold=10 +# +# Accounting-Request defaults to 5s +#accounting_request_abuse_threshold=5 + + [database] #DSN=DBI:SQLite:dbname=smradius.sqlite DSN=DBI:mysql:database=smradius;host=localhost