Вот скрипт который:
1. делает автоматическую настройку ip-mac на порту
2. блокирует доступ пользователям с отрицательным балансом ко всему кроме выделенной подсети (доступ к биллингу для активации карты).
Код:
#!/usr/bin/perl
# Привязка IP-MAC на порт
use Net::SNMP qw(:snmp DEBUG_ALL TRANSLATE_NONE TRANSLATE_ALL);
use Net::Telnet ();
use Data::Dumper;
use Net::IP qw(:PROC);
use DBI;
use strict;
use vars qw($SCRIPT $VERSION %OPTS);
$SCRIPT = 'des_control';
$VERSION = '0.0.0.3';
# Необходимо чтобы эти правила были уже установлены в свиче
#create access_profile ip source_ip_mask 255.255.255.255 profile_id 10
#create access_profile ip source_ip_mask 255.255.255.255 destination_ip_mask 255.255.255.0 profile_id 30
#create access_profile ip destination_ip_mask 0.0.0.0 profile_id 40
# параметры достпа к базе mysql в которой хранятся параметры доступа к свичам
my $db_host = "localhost";
my $db_user = "root";
my $db_passwd = "";
my $db_name = "devices";
# параметры доступа к базе биллинга
my $db_billing_host = "10.0.0.1";
my $db_billing_user = "billing";
my $db_billing_passwd = "billing";
my $db_billing_name = "billing";
my $bind_ip_profile_id = "10";
my $deny_profile_id = "30";
my $denyall_profile_id = "40";
my $MAX_ACCESS_ID = 800;
# моя подсеть к которой я даю доступ в любом случае в независимости от статуса пользователя
my $server_net = '10.10.0.0';
my $access_ids_oid = ".1.3.6.1.4.1.171.12.9.2.2.1.2.";
my $src_ip_oid = ".1.3.6.1.4.1.171.12.9.2.2.1.4.";
my $dst_ip_oid = ".1.3.6.1.4.1.171.12.9.2.2.1.4.";
my $port_oid = ".1.3.6.1.4.1.171.12.9.2.2.1.21.";
my $debug = 0;
# Init Telnet-connection
my $t = new Net::Telnet (
Timeout => 5,
Prompt => '/DES-3526:4#.*$/'
);
my ($session, $error);
my @good_boys;
my @bad_boys;
my $dbh = DBI->connect("DBI:mysql:$db_name:$db_host", $db_user, $db_passwd);
unless($dbh) {
exit -1;
}
my $dbh_bill = DBI->connect("DBI:mysql:$db_billing_name:$db_billing_host", $db_billing_user, $db_billing_passwd);
unless($dbh) {
exit -1;
}
my $query = "SELECT id, host, login, passwd, community FROM device";
my $sth = $dbh->prepare($query);
$sth->execute();
while(my @row = $sth->fetchrow_array()) {
eval {
process_host($row[0], $row[1], $row[2], $row[3], $row[4]);
};
if ($@) {
print "Error while process host " . $row[1] . " :: " . $@ . "\n";
}
}
sub process_host {
my $host_id = shift;
my $host_ip = shift;
my $login = shift;
my $passwd = shift;
my $community = shift;
_log("Process host:: $host_ip");
load_host_users($host_ip);
if($#good_boys < 0 && $#bad_boys < 0) {
return;
}
($session, $error) = snmp_init($host_ip, $community);
telnet_init($t, $host_ip, $login, $passwd);
test_good_boys();
deny_bad_boys();
close_telnet($t);
close_snmp($session);
_log("Finish process");
}
sub load_host_users {
my $host_ip = shift;
my $query = "
SELECT
c.id AS id,
c.title,
a.addr AS ip, IP хранится в INT-представлении
cs.`status` AS gate_status,
ug.port AS port,
g.host,
g.`comment`
FROM
***
WHERE
host = ?
";
my $sth = $dbh_bill->prepare($query);
$sth->execute($host_ip);
while(my $row = $sth->fetchrow_hashref()) {
if($row->{gate_status} != 0) {
add_to_array(\@bad_boys, , conver_ip($row->{ip}), $server_net, $row->{port}, $row->{id});
} else {
add_to_array(\@good_boys, , conver_ip($row->{ip}), $server_net, $row->{port}, $row->{id});
}
}
}
sub conver_ip {
my $bigintip = shift;
my $binip = ip_inttobin($bigintip, 4);
return ip_bintoip ($binip, 4);
}
sub snmp_init {
my $host_ip = shift;
my $community = shift;
my ($session,$error) = Net::SNMP->session(
-hostname => $host_ip,
-community => $community,
-version => 'snmpv2c',
);
if (!defined($session)) {
_exit($error);
}
return ($session, $error);
}
sub telnet_init {
my $t = shift;
my $host_ip = shift;
my $login = shift;
my $passwd = shift;
$t->open($host_ip);
$t->waitfor('/username:.*$/');
$t->print($login);
$t->waitfor('/password:.*$/');
$t->print($passwd);
}
sub close_telnet {
my $t = shift;
$t->close();
}
sub close_snmp {
my $session = shift;
$session->close();
}
sub test_good_boys {
process('10', \@good_boys, {'test_src' => 1, 'test_port' => 1, 'action' => 'permit'});
}
sub deny_bad_boys {
process('30', \@bad_boys, {'test_src' => 1, 'test_dst' => 1, 'test_port' => 1, 'action' => 'permit'});
process('40', \@bad_boys, {'test_src' => 0, 'test_dst' => 1, 'test_port' => 1, 'action' => 'deny'});
}
sub process {
my $profile_id = shift;
my $users = shift;
my $actions = shift; # {test_src => 1/0, test_dst => 1/0, test_port => 1/0, action => deny/permit}
my @tested;
my @access_ids = snmp_walk($access_ids_oid . $profile_id);
foreach my $access_id (@access_ids) {
my $_src_ip_oid = $src_ip_oid . $profile_id . '.' . $access_id->{value};
my $_dst_ip_oid = $dst_ip_oid . $profile_id . '.' . $access_id->{value};
my $_port_oid = $port_oid . $profile_id . '.' . $access_id->{value};
my $src_ip = snmp_get($_src_ip_oid);
my $dst_ip = snmp_get($_dst_ip_oid);
my $port = get_port_from_hex(snmp_get($_port_oid));
if(!check_user($users, $src_ip->{value}, $dst_ip->{value}, $port, $actions)) {
remove_access_id($profile_id, $access_id->{value});
} else {
push(@tested, $port);
_log("Nothing to do. Profile $profile_id, access " . $access_id->{value} . " skip port $port. ");
}
}
my $new_records = get_new_records($users, \@tested);
foreach my $record (@$new_records) {
add_access_id($profile_id, $record, $actions);
}
}
sub add_access_id {
my $profile_id = shift;
my $record = shift;
my $actions = shift;
my $access_id = get_free_access_id($profile_id);
my $cmd = "config access_profile profile_id $profile_id add access_id $access_id ip ";
$cmd .= ' source_ip ' . $record->{src_ip} . ' ' if($actions->{test_src});
$cmd .= ' destination_ip ' . $record->{dst_ip} . ' ' if($actions->{test_dst});
$cmd .= ' port ' . $record->{port} . ' ' if($actions->{test_port});
$cmd .= $actions->{action};
my @lines = $t->cmd($cmd);
_log($cmd);
}
sub remove_access_id {
my $profile_id = shift;
my $access_id = shift;
my $cmd = "config access_profile profile_id $profile_id delete access_id $access_id";
my @lines = $t->cmd($cmd);
_log($cmd);
}
sub check_user {
my $users = shift;
my $src_ip = shift;
my $dst_ip = shift;
my $port = shift;
my $actions = shift;
my $result = 0;
foreach my $usr (@$users) {
if($usr->{port} != $port) { next; }
if($actions->{test_src}) {
if($usr->{src_ip} eq $src_ip) {
$result = 1;
} else {
$result = 0;
}
}
if($actions->{test_dst}) {
if($usr->{dst_ip} eq $dst_ip) {
$result = 1;
} else {
$result = 0;
}
}
if($actions->{test_port}) {
if($usr->{port} eq $port) {
$result = 1;
} else {
$result = 0;
}
}
last;
}
return $result
}
sub get_port_from_hex {
my $hex_str = shift;
my $result = 0;
my $number = hex($hex_str->{value});
for(my $i = 2147483648; $i >=1; $i/=2) {
$result++;
if($i == $number) { last; }
}
#print "HEX: $hex_str->{value}, DEC: $number, RES: $result\n";
return $result;
}
sub get_new_records {
my $input_array = shift;
my $tested_ports = shift;
my @result;
my %seen = ();
foreach my $item (@$tested_ports) { $seen{$item} = 1 }
foreach my $obj (@$input_array) {
unless ($seen{$obj->{port}}) {
push(@result, $obj);
}
}
return \@result;
}
sub get_free_access_id {
my $profile_id = shift;
my $result;
my @seen;
my @access_ids = snmp_walk($access_ids_oid . $profile_id);
foreach my $access_id (@access_ids) {
$seen[$access_id->{value}] = 1;
}
for(my $i = 1; $i <= $MAX_ACCESS_ID; $i++) {
if($seen[$i] != 1) {
$result = $i;
last;
}
}
return $result;
}
sub snmp_walk {
my $_oid = shift;
my $oid;
my @result;
my @args = (-varbindlist => [$_oid] );
while (defined($session->get_next_request(@args))) {
$oid = ($session->var_bind_names())[0];
if (!oid_base_match($_oid, $oid)) { last;}
my %hash;
$hash{'oid'} = $oid;
$hash{'type'} = snmp_type_ntop($session->var_bind_types()->{$oid});
$hash{'value'} = $session->var_bind_list()->{$oid};
push( @result, \%hash);
@args = (-varbindlist => [$oid]);
}
return @result;
}
sub snmp_get {
my $_oid = shift;
my $debug = shift;
$session->translate(TRANSLATE_NONE);
my $result = $session->get_request(-varbindlist => [$_oid]);
my %hash;
$hash{'oid'} = $_oid;
$hash{'type'} = snmp_type_ntop($session->var_bind_types()->{$_oid});
$hash{'value'} = sprintf('0x%s', unpack('H*', $result->{$_oid}));
$session->translate(TRANSLATE_ALL);
return \%hash;
}
sub add_to_array {
my $array = shift;
my $src_ip = shift;
my $dst_ip = shift;
my $port = shift;
my $id = shift;
push(@$array, {'port' => $port, 'src_ip' => $src_ip, 'dst_ip' => $dst_ip, 'id' => $id });
}
sub _exit {
printf join('', sprintf("%s: ", $SCRIPT), shift(@_), ".\n"), @_;
exit 1;
}
sub _log {
my $msg = shift;
print $msg . "\n" if ($debug);
}