diff --git a/opentrafficshaper/plugins/radius/radius.pm b/opentrafficshaper/plugins/radius/radius.pm new file mode 100644 index 0000000000000000000000000000000000000000..1c1be38c442b36899706410b925b3a6b981a2ec6 --- /dev/null +++ b/opentrafficshaper/plugins/radius/radius.pm @@ -0,0 +1,231 @@ +# OpenTrafficShaper radius module +# Copyright (C) 2007-2013, 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + + +package opentrafficshaper::plugins::radius; + +use strict; +use warnings; + + +use POE; +use IO::Socket::INET; + +use opentrafficshaper::logger; + + + +# Exporter stuff +require Exporter; +our (@ISA,@EXPORT,@EXPORT_OK); +@ISA = qw(Exporter); +@EXPORT = qw( +); +@EXPORT_OK = qw( +); + +use constant { + VERSION => '0.0.1', + DATAGRAM_MAXLEN => 8192, +}; + + +# Plugin info +our $pluginInfo = { + Name => "Radius", + Version => VERSION, + + Init => \&init, +}; + + +# Copy of system globals +my $globals; +my $logger; + + +# Initialize plugin +sub init +{ + $globals = shift; + + + # Setup our environment + $logger = $globals->{'logger'}; + + # Radius listener + POE::Session->create( + inline_states => { + _start => \&server_init, + get_datagram => \&server_read, + } + ); + + $logger->log(LOG_NOTICE,"[RADIUS] OpenTrafficShaper Radius Module v".VERSION." - Copyright (c) 2013, AllWorldIT") +} + + +# Initialize server +sub server_init { + my $kernel = $_[KERNEL]; + + my $socket = IO::Socket::INET->new( + Proto => 'udp', + LocalPort => '1813', + ); + die "Couldn't create server socket: $!" unless $socket; + + $kernel->select_read($socket, "get_datagram"); +} + + +# Read event for server +sub server_read { + my ($kernel, $socket) = @_[KERNEL, ARG0]; + + + my $peer = recv($socket, my $udp_packet = "", DATAGRAM_MAXLEN, 0); + # If we don't have a peer, just return + return unless defined $peer; + + # Get peer port and addy from remote host + my ($peer_port, $peer_addr) = unpack_sockaddr_in($peer); + my $peer_addr_h = inet_ntoa($peer_addr); + + # Parse packet + my $pkt = new Radius::Packet($globals->{'radius'}->{'dictionary'},$udp_packet); + + # Build log line + my $logLine = sprintf("Remote: $peer_addr_h, Code: %s, Identifier: %s => ",$pkt->code,$pkt->identifier); + foreach my $attr ($pkt->attributes) { + $logLine .= sprintf(" %s: '%s',", $attr, $pkt->rawattr($attr)); + } + # Add vattributes onto logline + $logLine .= ". VREPLY => "; + # Loop with vendors + foreach my $vendor ($pkt->vendors()) { + # Loop with attributes + foreach my $attr ($pkt->vsattributes($vendor)) { + # Grab the value + my @attrRawVal = ( $pkt->vsattr($vendor,$attr) ); + my $attrVal = $attrRawVal[0][0]; + # Sanatize it a bit + if ($attrVal =~ /[[:cntrl:]]/) { + $attrVal = "-nonprint-"; + } else { + $attrVal = "'$attrVal'"; + } + + $logLine .= sprintf(" %s/%s: %s,",$vendor,$attr,$attrVal); + } + } + $logger->log(LOG_DEBUG,"[RADIUS] $logLine"); + + + # TODO - verify packet + + + + + # Pull in a variables from packet + my $username = $pkt->rawattr("User-Name"); + my $trafficGroup; + if (my $attrRawVal = $pkt->vsattr(11111,'OpenTrafficShaper-Traffic-Group')) { + $trafficGroup = @{ $attrRawVal }[0]; + } + my $trafficClass; + if (my $attrRawVal = $pkt->vsattr(11111,'OpenTrafficShaper-Traffic-Class')) { + $trafficClass = @{ $attrRawVal }[0]; + } + my $trafficLimit; + if (my $attrRawVal = $pkt->vsattr(11111,'OpenTrafficShaper-Traffic-Limit')) { + $trafficLimit = @{ $attrRawVal }[0]; + } + + # Grab rate limits from the string we got + my $trafficLimitRx = 0; my $trafficLimitTx = 0; + my $trafficLimitRxBurst = 0; my $trafficLimitTxBurst = 0; + if (defined($trafficLimit)) { + my ($trafficLimitRxQuantifier,$trafficLimitTxQuantifier); + my ($trafficLimitRxBurstQuantifier,$trafficLimitTxBurstQuantifier); + # Match rx-rate[/tx-rate] rx-burst-rate[/tx-burst-rate] + if ($trafficLimit =~ /^(\d+)([km])(?:\/(\d+)([km]))?(?: (\d+)([km])(?:\/(\d+)([km]))?)?/) { + $trafficLimitRx = getKbit($1,$2); + $trafficLimitTx = getKbit($3,$4); + $trafficLimitRxBurst = getKbit($5,$6); + $trafficLimitTxBurst = getKbit($7,$8); + } + } + + # Set default if they undefined + if (!defined($trafficGroup)) { + $trafficGroup = 0; + } + if (!defined($trafficClass)) { + $trafficClass = 0; + } + + my $user = { + 'Username' => $username, + 'IP' => $pkt->attr('Framed-IP-Address'), + 'Group' => $trafficGroup, + 'GroupName' => "Group 1", + 'Class' => $trafficClass, + 'ClassName' => "Class A", + 'Limits' => "$trafficLimitTx / $trafficLimitRx", + 'BurstLimits' => "$trafficLimitTxBurst / $trafficLimitRxBurst", + 'Status' => $pkt->rawattr('Acct-Status-Type'), + }; + + $globals->{'users'}->{$username} = $user; + + $logger->log(LOG_DEBUG,"=> Code: $user->{'status'}, User: $user->{'username'}, IP: $user->{'ip'}, Group: $user->{'group'}, Class: $user->{'class'}, Limits: $user->{'limits'}, Burst: $user->{'burstlimits'}"); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1; +# vim: ts=4