Introduction
Articles
Snapshots
Links
Books
Commerce
Outdoors
Me :)

Your comments & suggestions may be mailed to:
archeryring@nm.ru

Copyright ї 1998 Taras Plakhotnichenko
Most recent revision 22 Feb 2004

стрельба из лука в России

The first archery dedicated WEB site in Russia




Организация provisioning system (система обеспечения кабельных модемов) для клиентов без аутентификации (кабельный модем находится у клиента в квартире) Примечание: вообще говоря, лучше всего использовать LDAP как backend для ICS DHCP. ISC DHCP сервер можно собрать с поддержкой  LDAP. А еще лучше использовать вышеупомянутый docsis_server.
Flowcd  (агент для протокола netflow) собирает статистику сетевой активности клиентов, выполняет агрегацию трафика по портам., и накапливает информацию в базе данных MySQL в таблице flows:
                  
router_id  tinyint(3) unsigned                      0
in_if_id mediumint(8) unsigned MUL 0
out_if_id mediumint(8) unsigned MUL 0
timestamp datetime MUL 0000-00-00 00:00:00
src_addr int(10) unsigned MUL 0
dst_addr int(10) unsigned MUL 0
d_pkts int(10) unsigned 0
d_octets int(10) unsigned 0
protocol mediumint(8) unsigned 0
src_port mediumint(8) unsigned 0
dst_port mediumint(8) unsigned 0
src_as mediumint(8) unsigned 0
dst_as mediumint(8) unsigned 0


Информация о клиенте (название, IP адрес клиента, мак адрес клиента, IP адрес модема, мак адрес модема, трафик-байты, трафик-пакеты, лимит трафика, конф. файл модема, цена,  итоговая сумма) содержится в таблице clients,  а промежуточные значения - по дням - в clients_traffic:

CREATE TABLE `clients` (
`id` varchar(20) default NULL,
`cpe_ip` varchar(15) NOT NULL default '',
`cpe_mac` varchar(17) default NULL,
`cm_ip` varchar(15) NOT NULL default '',
`cm_mac` varchar(17) NOT NULL default '',
`octets` bigint(20) default '0',
`packets` bigint(20) default '0',
`traf_lim` bigint(20) default '0',
`config_file` varchar(15) default 'noaccess.cm',
`price` varchar(10) default '0',
`total` varchar(15) default '0',
PRIMARY KEY  (`cpe_ip`),
UNIQUE KEY `cm_ip` (`cm_ip`),
UNIQUE KEY `cm_mac` (`cm_mac`),
UNIQUE KEY `cm_ip_2` (`cm_ip`)
    ) TYPE=MyISAM


CREATE TABLE `client_traffic` (
   `date_time` timestamp(14) NOT NULL,
   `cpe_ip` varchar(15) NOT NULL default '0',
   `octets` bigint(20) default '0'
) TYPE=MyISAM

 



Как  это работает:

В таблицу clients вводится информация о клиенте. Запускается скрипт
(add_client.pl) на перле, который на основе данных о клиенте генерирует
конфигурационный файл  - dhcpd.conf для dhcp сервера ISC и перезапускает
его. Скрипт использует файлы dhcp.head  - шаблон для для dhcpd.conf:



#add_client.pl
#!/usr/bin/perl
use DBI;
my $database = "clients";
my $data_source = "DBI:mysql:$database";
my $username = "flowbill";
my $password = "SjM1!#";
$dbh = DBI->connect( $data_source, $username, $password) or
die "Can't connect to $data_source: $dbh->errstr\n";
my $table_data = $dbh->prepare("select * from clients");
$table_data->execute;
system("mv  dhcpd.conf dhcpd.conf.backup");
system("cp  dhcpd.head dhcpd.head.tmp");
my $file = './dhcpd.head.tmp';
open(FH, ">>$file") or "Can't open $file : $!";
while(my(@data)=$table_data->fetchrow_array) {
   #CPE section
   print FH  "group {\n";
   print FH "host $data[0]  {hardware ethernet $data[2];\n";
   #print FH "$data[2];\n";
   print FH "fixed-address $data[1];}\n";
   print FH "}\n";
   #for (0..$#data) {
   #print  "$data[$_]\n";
   #}
   #CM section
   print FH "group {\n";
   print FH "filename \"$data[8]\";\n";
   my $host_id = "$data[0]" . "2";
   print FH "host $host_id   {hardware ethernet $data[4];}\n";
   #print FH "fixed-address $data[4];}\n";
   print FH  "}\n";   

}

$dbh->disconnect;
close(FH);
system("mv  dhcpd.head.tmp dhcpd.conf");
system("cp dhcpd.conf /etc/dhcpd.conf");
system("rm -f   dhcpd.head.tmp");
#system("kill -HUP `cat /var/run/dhcpd.pid`");
system("/etc/init.d/dhcpd restart");
exit(0);





#dhcpd.head
authoritative;
ddns-update-style none;
option domain-name-servers 172.18.1.202, 172.18.1.230;
option domain-name "zvezda";
default-lease-time 345600; #4 day lease
max-lease-time 691200;      #8 day lease


subnet 172.18.1.0 netmask 255.255.255.0 {
     }      #Ethernet Interface in Linux box - dummy declaration
shared-network "CPE_Pool" {
   default-lease-time 14400; # 4 hour lease on non-static IP's
   max-lease-time 28800; # 8 hour max lease
   filename "noaccess.cm";

subnet 10.254.1.0 netmask 255.255.255.0 {  #CPE Network
#  range 10.254.1.100 10.254.1.254;
   option subnet-mask 255.255.255.0;
   option broadcast-address 10.254.1.255;
   option routers 10.254.1.1;
pool {
     range 10.254.1.2 10.254.1.254;
     deny unknown-clients;
     }
} # CPE Network
  

}  #End shared-network

# This is the CM network   
subnet 10.128.0.0 netmask 255.255.0.0 {
   range 10.128.0.2 10.128.255.254;
   option subnet-mask 255.255.0.0;
   option broadcast-address 10.128.255.255;
   filename "noaccess.cm";
   option routers 10.128.0.1;  #Cable Card in 3Com CMTS
   option log-servers 10.128.0.1;
   option tftp-server-name "172.18.1.202";
   option time-servers 10.128.0.1; }





#dhcpd.conf
authoritative;
ddns-update-style none;
option domain-name-servers 172.18.1.202, 172.18.1.230;
option domain-name "zvezda";
default-lease-time 345600; #4 day lease
max-lease-time 691200;      #8 day lease


subnet 172.18.1.0 netmask 255.255.255.0 {
     }      #Ethernet Interface in Linux box - dummy declaration
shared-network "CPE_Pool" {
   default-lease-time 14400; # 4 hour lease on non-static IP's
   max-lease-time 28800; # 8 hour max lease
   filename "noaccess.cm";

subnet 10.254.1.0 netmask 255.255.255.0 {  #CPE Network
#  range 10.254.1.100 10.254.1.254;
   option subnet-mask 255.255.255.0;
   option broadcast-address 10.254.1.255;
   option routers 10.254.1.1;
pool {
     range 10.254.1.2 10.254.1.254;
     deny unknown-clients;
     }
} # CPE Network
  

}  #End shared-network

# This is the CM network   
subnet 10.128.0.0 netmask 255.255.0.0 {
   range 10.128.0.2 10.128.255.254;
   option subnet-mask 255.255.0.0;
   option broadcast-address 10.128.255.255;
   filename "noaccess.cm";
   option routers 10.128.0.1; 
   option log-servers 10.128.0.1;
   option tftp-server-name "172.18.1.202";
   option time-servers 10.128.0.1; }


group {
host Host_name1  {hardware ethernet 00:c0:ca:13:5b:21;
fixed-address 10.254.1.3;}
}
group {
filename "128_64.cm";
host Modem_name1   {hardware ethernet 00:0B:06:D7:D5:08;}
}




Для отключения клиента работает следующий скрипт, который находит мак адрес клиента через IP адрес компьютера клиента. Записывает noaccess.cm - файл отключения в таблицу clients соотв. клиенту и дает команду циске отключить модем клиента:

#!/usr/bin/perl -w
use DBI;
(my $client_ip) = @ARGV;
#print "$client_ip\n";

my $database = "clients";
my $data_source = "DBI:mysql:$database";
my $username = "flowbill";
my $password = "SjM1!#";
$dbh = DBI->connect( $data_source, $username, $password) or
die "Can't connect to $data_source: $dbh->errstr\n";
my $table_data = $dbh->prepare("select cm_mac from clients
where cpe_ip = \"$client_ip\"");
$table_data->execute;
#print "select cm_mac from clients where cpe_ip = \"$client_ip\"";
my $cm_mac = $table_data->fetchrow_array();
#print "$cm_mac";
$table_data->finish();

my $query="update clients set config_file='noaccess.cm'
where cpe_ip=\"$client_ip\"";
my $insert=$dbh->prepare("$query");
$insert->execute() or die "Could not execute SQL statement";
$insert->finish();
#print "$query";

$dbh->disconnect;
@array=split(/\:/, $cm_mac);
#print "$cm_mac\n";
#print "$array[0]";
#print "$array[1]";
$cm_mac="$array[0]"  . "$array[1]" . "." . "$array[2]" . "$array[3]" .
"." . "$array[4]" .  "$array[5]\n";
#print "$cm_mac\n";
system("rsh -l traffic  172.18.1.12  clear cable modem '$cm_mac'
 reset" );
exit(0);




Подсчет трафика (итоговый трафик по каждому клиенту, трафик по каждому клиенту и на каждый день),  его накопление, усечение таблицы flows, контроль лимитов и т.д. осуществляется следующим скриптом:

#!/usr/bin/perl -w
use DBI;
my $database = "netflow";
my $data_source = "DBI:mysql:$database";
my $username = "flowbill";
my $password = "SjM1!#";
my $database_cl = "clients";
my $data_source_cl = "DBI:mysql:$database_cl";

$dbh_clients = DBI->connect( $data_source_cl, $username, $password) or
 die "Can't connect to $data_source_cl: $dbh_clients->errstr\n";
$dbh_flow = DBI->connect( $data_source, $username, $password) or
 die "Can't connect to $data_source: $dbh_flow->errstr\n";
my $table_data_cl = $dbh_clients->prepare("select cpe_ip,  octets,
 packets from clients");
$table_data_cl->execute;

while(my(@data_cl)=$table_data_cl->fetchrow_array) {
#print "$data_cl[0];\n"; #CPE IP
my $query_string = "select  sum(d_pkts), sum( d_octets)  from  flows
 where dst_addr = INET_ATON(\"$data_cl[0]\")";
my $table_data = $dbh_flow->prepare("$query_string");
$table_data->execute;
my @data_fl = $table_data->fetchrow_array();
$data_fl[1] = '0' unless $data_fl[1];
my $total_traf = ($data_fl[1] + $data_cl[2]);
my $dayly_traf=$dbh_clients->prepare("INSERT INTO client_traffic
(cpe_ip, octets)  VALUES (?,?)");
$dayly_traf->execute($data_cl[0], $data_fl[1]);
$dayly_traf->finish();

my $query_string_cl="update clients set packets=\"$total_traf\" where
cpe_ip=\"$data_cl[0]\"";
my $insert=$dbh_clients->prepare("$query_string_cl");
$insert->execute() or die "Could not execute SQL statement";
$insert->finish();
$table_data->finish;
#
#Check traffic limits
my $query_traf_limit="select traf_lim from clients where cpe_ip=\"$data_cl[0]\"";
my $select_traf_limit=$dbh_clients->prepare("$query_traf_limit");
$select_traf_limit->execute() or die "Could not execute SQL statement";
my @client_row=$select_traf_limit->fetchrow_array;
#print "$total_traf   $client_row[0]\n";
if ($total_traf > $client_row[0]) {
   print "$data_cl[0] traffic limit\n";
   #print "$total_traf   $client_row[0]\n";
   system("./reset_client.pl $data_cl[0]");
   }
my $del_query_string="delete from flows where dst_addr =
 INET_ATON(\"$data_cl[0]\")";
my $dbh_del=$dbh_flow->prepare("$del_query_string");
$dbh_del->execute() or die "Could not execute SQL statement";
$dbh_del->finish();
} # end while
$dbh_clients->disconnect;
$dbh_flow->disconnect;
exit(0);




Таким образом, информация о текущем состоянии клиента извлекается через ODBC, а через  ssh канал осуществляется удаленное управление. Кроме того, решаются вопросы безопасности. Выполнение команд на удаленном хосте без ввода пароля т.е. автоматически  можно организовать например с помощью plink.exe. (http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) Т.е. с помощью puttygen.exe генерируетcz пара ключей (SSH2 RSA). Публичный ключ размещается на сервере, а секретный ключ - на управляющем сервере в безопасном месте.

plink.exe  -ssh -i id_rsa.ppk <remote_user>@<remote_host> <команда на удаленный хост>
Передать файл на удаленный хост:

pscp.exe -i id_rsa.ppk <local_file> <user>@<remote_host>:/<dir_name>