Merge branch 'FUP' into 'master'
Added FUP support See merge request !425
Showing
# Radius daemon | ||
# Copyright (C) 2007-2016, AllWorldIT | ||
# Copyright (C) 2007-2019, AllWorldIT | ||
# | ||
# This program is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
... | ... | @@ -898,109 +898,145 @@ sub process_request { |
foreach my $attrOp (keys %{$user->{'Attributes'}->{$attrName}}) { | ||
# Grab attribute | ||
my $attr = $user->{'Attributes'}->{$attrName}->{$attrOp}; | ||
# Check attribute against accounting attributes attributes | ||
# Check attribute against accounting attributes | ||
my $res = checkAcctAttribute($self,$user,$acctAttributes,$attr); | ||
# We don't care if it fails | ||
} | ||
} | ||
# Check if we must POD the user | ||
# The coaReq may be either POD or CoA | ||
my $coaReq = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'}); | ||
# Set packet identifier | ||
$coaReq->set_identifier( $$ & 0xff ); | ||
# Check if we must POD the user, if so we set the code to disconnect | ||
if ($PODUser) { | ||
$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')); | ||
# Session identification | ||
$coaReq->set_attr('User-Name',$pkt->attr('User-Name')); | ||
$coaReq->set_attr('NAS-Port',$pkt->attr('NAS-Port')); | ||
$coaReq->set_attr('Acct-Session-Id',$pkt->attr('Acct-Session-Id')); | ||
$resp->set_code('Disconnect-Request'); | ||
my $id = $$ & 0xff; | ||
$resp->set_identifier( $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 | ||
$request->addLogLine(". REPLY => "); | ||
foreach my $attrName ($resp->attributes) { | ||
$request->addLogLine( | ||
"%s: '%s'", | ||
$attrName, | ||
$resp->rawattr($attrName) | ||
); | ||
# Add onto logline | ||
$request->addLogLine(". REPLY => "); | ||
foreach my $attrName ($coaReq->attributes) { | ||
$request->addLogLine( | ||
"%s: '%s'", | ||
$attrName, | ||
$coaReq->rawattr($attrName) | ||
); | ||
} | ||
# Generate coaReq packet | ||
my $coaReq_packet = auth_resp($coaReq->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret")); | ||
# Array CoA servers to contact | ||
my @coaServers; | ||
# Check for old POD server attribute | ||
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'})) { | ||
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-PODServer is defined"); | ||
@coaServers = @{$user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'}}; | ||
} | ||
# Check for new CoA server attribute | ||
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-CoAServer'})) { | ||
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-CoAServer is defined"); | ||
@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 address format | ||
foreach my $coaServer (@coaServers) { | ||
# Remove IPv6 portion for now... | ||
$coaServer =~ s/^::ffff://; | ||
# Check for valid IP | ||
my ($coaServerIP,$coaServerPort) = ($coaServer =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(?::([0-9]+))?/); | ||
if (!defined($coaServerIP)) { | ||
$self->log(LOG_NOTICE,"[SMRADIUS] POST-ACCT: CoAServer '$coaServer' looks incorrect"); | ||
next; | ||
} | ||
# Grab packet | ||
my $response = auth_resp($resp->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret")); | ||
# Check for POD Servers and send disconnect | ||
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'})) { | ||
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-PODServer is defined"); | ||
# Check address format | ||
foreach my $podServerAttribute (@{$user->{'ConfigAttributes'}->{'SMRadius-Config-PODServer'}}) { | ||
# Check for valid IP | ||
if ($podServerAttribute =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/) { | ||
my $podServer = $1; | ||
# If we have a port, use it, otherwise use default 1700 | ||
my $podServerPort; | ||
if ($podServerAttribute =~ /:([0-9]+)$/) { | ||
$podServerPort = $1; | ||
} else { | ||
$podServerPort = 1700; | ||
} | ||
$self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying PODServer => IP: '".$podServer."' Port: '".$podServerPort."'"); | ||
# Create socket to send packet out on | ||
my $podServerTimeout = "10"; # 10 second timeout | ||
my $podSock = IO::Socket::INET->new( | ||
PeerAddr => $podServer, | ||
PeerPort => $podServerPort, | ||
Type => SOCK_DGRAM, | ||
Proto => 'udp', | ||
TimeOut => $podServerTimeout, | ||
); | ||
if (!$podSock) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to create socket to send POD on"); | ||
next; | ||
} | ||
# Check if we sent the packet... | ||
if (!$podSock->send($response)) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to send data on socket"); | ||
next; | ||
} | ||
# Once sent, we need to get a response back | ||
my $sh = IO::Select->new($podSock); | ||
if (!$sh) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to select data on socket"); | ||
next; | ||
} | ||
if (!$sh->can_read($podServerTimeout)) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to receive data on socket"); | ||
next; | ||
} | ||
my $data; | ||
$podSock->recv($data, 65536); | ||
if (!$data) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Receive data failed"); | ||
$logReason = "POD Failure"; | ||
} else { | ||
$logReason = "User POD"; | ||
} | ||
#my @stuff = unpack('C C n a16 a*', $data); | ||
#$self->log(LOG_DEBUG,"STUFF: ".Dumper(\@stuff)); | ||
} else { | ||
$self->log(LOG_DEBUG,"[SMRADIUS] Invalid POD Server value: '".$podServerAttribute."'"); | ||
} | ||
} | ||
# Set default CoA server port | ||
$coaServerPort //= 1700; | ||
$self->log(LOG_DEBUG,"[SMRADIUS] POST-ACCT: Trying CoAServer => IP: '".$coaServer."' Port: '".$coaServerPort."'"); | ||
# Create socket to send packet out on | ||
my $coaServerTimeout = "2"; # 2 second timeout | ||
my $coaSock = IO::Socket::INET->new( | ||
PeerAddr => $coaServerIP, | ||
PeerPort => $coaServerPort, | ||
Type => SOCK_DGRAM, | ||
Proto => 'udp', | ||
TimeOut => $coaServerTimeout, | ||
); | ||
if (!$coaSock) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to create socket to send CoA on: $!"); | ||
next; | ||
} | ||
# Check if we sent the packet... | ||
if (!$coaSock->send($coaReq_packet)) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to send data on CoA socket: $!"); | ||
next; | ||
} | ||
# Once sent, we need to get a response back | ||
my $select = IO::Select->new($coaSock); | ||
if (!$select) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to select data on socket: $!"); | ||
next; | ||
} | ||
if (!$select->can_read($coaServerTimeout)) { | ||
$self->log(LOG_ERR,"[SMRADIUS] POST-ACCT: Failed to receive data on socket: $!"); | ||
next; | ||
} | ||
# Grab CoA response | ||
my $coaRes_packet; | ||
$coaSock->recv($coaRes_packet, 65536); | ||
if (!$coaRes_packet) { | ||
$self->log(LOG_INFO,"[SMRADIUS] POST-ACCT: No data received in response to our request to '$coaServerIP:$coaServerPort': $!"); | ||
$logReason = "No Response"; | ||
next; | ||
} | ||
# Parse the radius packet | ||
my $coaRes = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'},$coaRes_packet); | ||
# 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 { | ||
$self->log(LOG_DEBUG,"[SMRADIUS] SMRadius-Config-PODServer is not defined"); | ||
$logReason = "CoA/POD Fail"; | ||
} | ||
} | ||
... | ... | @@ -1154,133 +1190,8 @@ sub process_request { |
$resp->set_identifier($pkt->identifier); | ||
$resp->set_authenticator($pkt->authenticator); | ||
# Loop with attributes we got from the getReplyAttributes function, its a hash of arrays which are the values | ||
my %replyAttributes = %{ $user->{'ReplyAttributes'} }; | ||
foreach my $attrName (keys %{$user->{'Attributes'}}) { | ||
# Loop with operators | ||
foreach my $attrOp (keys %{$user->{'Attributes'}->{$attrName}}) { | ||
# Grab attribute | ||
my $attr = $user->{'Attributes'}->{$attrName}->{$attrOp}; | ||
# Add this to the reply attribute? | ||
setReplyAttribute($self,\%replyAttributes,$attr); | ||
} | ||
} | ||
# Loop with reply attributes | ||
$request->addLogLine(". RFILTER => "); | ||
foreach my $attrName (keys %replyAttributes) { | ||
# Loop with values | ||
foreach my $value (@{$replyAttributes{$attrName}}) { | ||
# Check for filter matches | ||
my $excluded = 0; | ||
foreach my $item (@{$user->{'ConfigAttributes'}->{'SMRadius-Config-Filter-Reply-Attribute'}}) { | ||
my @attrList = split(/[;,]/,$item); | ||
foreach my $aItem (@attrList) { | ||
$excluded = 1 if (lc($attrName) eq lc($aItem)); | ||
} | ||
} | ||
# If we must be filtered, just exclude it then | ||
if (!$excluded) { | ||
# Add each value | ||
$resp->set_attr($attrName,$value); | ||
} else { | ||
$request->addLogLine("%s ",$attrName); | ||
} | ||
< |