Commit 035c70fa authored by Nigel Kukard's avatar Nigel Kukard
Browse files

FEATURE: CoA

parent c615c7ea
...@@ -898,82 +898,91 @@ sub process_request { ...@@ -898,82 +898,91 @@ sub process_request {
foreach my $attrOp (keys %{$user->{'Attributes'}->{$attrName}}) { foreach my $attrOp (keys %{$user->{'Attributes'}->{$attrName}}) {
# Grab attribute # Grab attribute
my $attr = $user->{'Attributes'}->{$attrName}->{$attrOp}; my $attr = $user->{'Attributes'}->{$attrName}->{$attrOp};
# Check attribute against accounting attributes attributes # Check attribute against accounting attributes
my $res = checkAcctAttribute($self,$user,$acctAttributes,$attr); my $res = checkAcctAttribute($self,$user,$acctAttributes,$attr);
# We don't care if it fails # We don't care if it fails
} }
} }
# TEST START
my $coaReq = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'});
# Process the reply attributes # The coaReq may be either POD or CoA
$self->_processReplyAttributes($request,$user,$coaReq); my $coaReq = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'});
# TEST END
# Set packet identifier
$coaReq->set_identifier( $$ & 0xff );
# Check if we must POD the user # Check if we must POD the user, if so we set the code to disconnect
if ($PODUser) { if ($PODUser) {
$self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying to disconnect user..."); $self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying to disconnect user...");
$coaReq->set_code('Disconnect-Request');
} else {
# If this is *not* a POD, we need to process reply attributes
$self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Sending CoA...");
$coaReq->set_code('CoA-Request');
# Process the reply attributes
$self->_processReplyAttributes($request,$user,$coaReq);
}
my $resp = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'}); # NAS identification
$coaReq->set_attr('NAS-IP-Address',$pkt->attr('NAS-IP-Address'));
$resp->set_code('Disconnect-Request'); # Session identification
my $id = $$ & 0xff; $coaReq->set_attr('User-Name',$pkt->attr('User-Name'));
$resp->set_identifier( $id ); $coaReq->set_attr('NAS-Port',$pkt->attr('NAS-Port'));
$coaReq->set_attr('Acct-Session-Id',$pkt->attr('Acct-Session-Id'));
$resp->set_attr('User-Name',$pkt->attr('User-Name'));
$resp->set_attr('Framed-IP-Address',$pkt->attr('Framed-IP-Address'));
$resp->set_attr('NAS-IP-Address',$pkt->attr('NAS-IP-Address'));
# Add onto logline # Add onto logline
$request->addLogLine(". REPLY => "); $request->addLogLine(". REPLY => ");
foreach my $attrName ($resp->attributes) { foreach my $attrName ($coaReq->attributes) {
$request->addLogLine( $request->addLogLine(
"%s: '%s'", "%s: '%s'",
$attrName, $attrName,
$resp->rawattr($attrName) $coaReq->rawattr($attrName)
); );
} }
# Grab packet # Generate coaReq packet
my $response = auth_resp($resp->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret")); my $coaReq_packet = auth_resp($coaReq->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret"));
my $coaServer; # Array CoA servers to contact
my @coaServers;
# Check for old POD server attribute # Check for old POD server attribute
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'})) { if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'})) {
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-PODServer is defined"); $self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-PODServer is defined");
$coaServer = $user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'}; @coaServers = @{$user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'}};
} }
# Check for new CoA server attribute # Check for new CoA server attribute
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-CoAServer'})) { if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-CoAServer'})) {
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-CoAServer is defined"); $self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-CoAServer is defined");
$coaServer = $user->{'ConfigAttributes'}->{'SMRadius-Config-CoAServer'}; @coaServers = @{$user->{'ConfigAttributes'}->{'SMRadius-Config-CoAServer'}};
}
# If we didn't get provided a CoA server, use the peer address
if (!@coaServers) {
push(@coaServers,$server->{'peeraddr'});
} }
# Check for CoA servers
if (defined($coaServer)) {
# Check address format # Check address format
foreach my $coaServerAttribute (@{$coaServer}) { foreach my $coaServer (@coaServers) {
# Remove IPv6 portion for now...
$coaServer =~ s/^::ffff://;
# Check for valid IP # Check for valid IP
if ($coaServerAttribute =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/) { my ($coaServerIP,$coaServerPort) = ($coaServer =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(?::([0-9]+))?/);
my $coaServer = $1;
# If we have a port, use it, otherwise use default 1700 if (!defined($coaServerIP)) {
my $coaServerPort; $self->log(LOG_NOTICE,"[SMRADIUS] POST-ACCT: CoAServer '$coaServer' looks incorrect");
if ($coaServerAttribute =~ /:([0-9]+)$/) { next;
$coaServerPort = $1;
} else {
$coaServerPort = 1700;
} }
# Set default CoA server port
$coaServerPort //= 1700;
$self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying CoAServer => IP: '".$coaServer."' Port: '".$coaServerPort."'"); $self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying CoAServer => IP: '".$coaServer."' Port: '".$coaServerPort."'");
# Create socket to send packet out on # Create socket to send packet out on
my $coaServerTimeout = "10"; # 10 second timeout my $coaServerTimeout = "2"; # 2 second timeout
my $coaSock = IO::Socket::INET->new( my $coaSock = IO::Socket::INET->new(
PeerAddr => $coaServer, PeerAddr => $coaServerIP,
PeerPort => $coaServerPort, PeerPort => $coaServerPort,
Type => SOCK_DGRAM, Type => SOCK_DGRAM,
Proto => 'udp', Proto => 'udp',
...@@ -981,45 +990,53 @@ sub process_request { ...@@ -981,45 +990,53 @@ sub process_request {
); );
if (!$coaSock) { if (!$coaSock) {
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to create socket to send POD on"); $self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to create socket to send CoA on: $!");
next; next;
} }
# Check if we sent the packet... # Check if we sent the packet...
if (!$coaSock->send($response)) { if (!$coaSock->send($coaReq_packet)) {
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to send data on socket"); $self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to send data on CoA socket: $!");
next; next;
} }
# Once sent, we need to get a response back # Once sent, we need to get a response back
my $sh = IO::Select->new($coaSock); my $select = IO::Select->new($coaSock);
if (!$sh) { if (!$select) {
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to select data on socket"); $self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to select data on socket: $!");
next; next;
} }
if (!$sh->can_read($coaServerTimeout)) { if (!$select->can_read($coaServerTimeout)) {
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to receive data on socket"); $self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to receive data on socket: $!");
next; next;
} }
my $data; # Grab CoA response
$coaSock->recv($data, 65536); my $coaRes_packet;
if (!$data) { $coaSock->recv($coaRes_packet, 65536);
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Receive data failed"); if (!$coaRes_packet) {
$logReason = "CoA Failure"; $self->log(LOG_INFO,"[SMRADIUS] POST-ACCT: No data received in response to our request to '$coaServerIP:$coaServerPort': $!");
} else { $logReason = "No Response";
$logReason = "User POD"; next;
} }
#my @stuff = unpack('C C n a16 a*', $data); # Parse the radius packet
#$self->log(LOG_DEBUG,"STUFF: ".Dumper(\@stuff)); my $coaRes = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'},$coaRes_packet);
} else {
$self->log(LOG_DEBUG,"[SMRADIUS] Invalid CoA Server value: '".$coaServerAttribute."'"); # Check status
} if ($coaRes->code eq "CoA-ACK") {
} $logReason = "CoA Success";
last;
} elsif ($coaRes->code eq "CoA-NACK") {
$logReason = "CoA Fail";
} elsif ($coaRes->code eq "Disconnect-ACK") {
$logReason = "POD Success";
last;
} elsif ($coaRes->code eq "Disconnect-NACK") {
$logReason = "POD Fail";
} else { } else {
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-CoAServer is not defined"); $logReason = "CoA/POD Fail";
} }
} }
......
...@@ -835,7 +835,7 @@ if ($child = fork()) { ...@@ -835,7 +835,7 @@ if ($child = fork()) {
# Add an attribute so we can check the FUP match results # Add an attribute so we can check the FUP match results
my $user5attr4_ID = testDBInsert("Create user 'testuser5' attribute 'SMRadius-Evaluate'", my $user5attr4_ID = testDBInsert("Create user 'testuser5' attribute 'SMRadius-Evaluate'",
"INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)", "INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)",
$user5_ID,'SMRadius-Evaluate','||+=',"SMRadius_FUP > 0 ? [14988:Mikrotik-Rate-Limit] = 1638k/8m" $user5_ID,'SMRadius-Evaluate','||+=',"SMRadius_FUP > 0 ? [14988:Mikrotik-Rate-Limit] = 1638k/8m : [14988:Mikrotik-Rate-Limit] = 1k/1m"
); );
my $session4_ID = "a8abc40"; my $session4_ID = "a8abc40";
...@@ -871,7 +871,8 @@ if ($child = fork()) { ...@@ -871,7 +871,8 @@ if ($child = fork()) {
'Service-Type=Framed-User', 'Service-Type=Framed-User',
); );
is(ref($res),"HASH","smradclient should return a HASH"); is(ref($res),"HASH","smradclient should return a HASH");
is($res->{'response'}->{'vattributes'},undef,"Check that the vendor attributes are not defined"); is($res->{'listen'}->{'response'}->{'vattributes'}->{'14988'}->{'Mikrotik-Rate-Limit'}->[0],"1k/1m","Check that the vendor attribute".
"'14988:Mikrotik-Rate-Limit' is returned on the negative side of the IF");
# #
...@@ -900,7 +901,7 @@ if ($child = fork()) { ...@@ -900,7 +901,7 @@ if ($child = fork()) {
# Add an attribute so we can check the FUP match results # Add an attribute so we can check the FUP match results
my $user6attr4_ID = testDBInsert("Create user 'testuser6' attribute 'SMRadius-Evaluate'", my $user6attr4_ID = testDBInsert("Create user 'testuser6' attribute 'SMRadius-Evaluate'",
"INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)", "INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)",
$user6_ID,'SMRadius-Evaluate','||+=',"SMRadius_FUP > 0 ? [14988:Mikrotik-Rate-Limit] = 1638k/8m" $user6_ID,'SMRadius-Evaluate','||+=',"SMRadius_FUP > 0 ? [14988:Mikrotik-Rate-Limit] = 1638k/8m : [14988:Mikrotik-Rate-Limit] = 1k/1m"
); );
my $session5_ID = "582dc00"; my $session5_ID = "582dc00";
...@@ -936,7 +937,7 @@ if ($child = fork()) { ...@@ -936,7 +937,7 @@ if ($child = fork()) {
'Service-Type=Framed-User', 'Service-Type=Framed-User',
); );
is(ref($res),"HASH","smradclient should return a HASH"); is(ref($res),"HASH","smradclient should return a HASH");
is($res->{'response'}->{'vattributes'}->{'14988'}->{'Mikrotik-Rate-Limit'}->[0],"1638k/8m","Check that the vendor attribute". is($res->{'listen'}->{'response'}->{'vattributes'}->{'14988'}->{'Mikrotik-Rate-Limit'}->[0],"1638k/8m","Check that the vendor attribute".
"'14988:Mikrotik-Rate-Limit' is returned"); "'14988:Mikrotik-Rate-Limit' is returned");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment