From 6f4773e187086c0c6b3a47dc19b1c7c879b7482e Mon Sep 17 00:00:00 2001
From: Nigel Kukard <nkukard@lbsd.net>
Date: Sat, 22 Jun 2013 21:26:29 +0000
Subject: [PATCH] Added radius as a plugin

---
 opentrafficshaper/plugins/radius/radius.pm | 231 +++++++++++++++++++++
 1 file changed, 231 insertions(+)
 create mode 100644 opentrafficshaper/plugins/radius/radius.pm

diff --git a/opentrafficshaper/plugins/radius/radius.pm b/opentrafficshaper/plugins/radius/radius.pm
new file mode 100644
index 0000000..1c1be38
--- /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
-- 
GitLab