Пример реализации скриптового универсального шлюза

Материал из BiTel WiKi

(Различия между версиями)
Перейти к: навигация, поиск
(Новая: Стоит задача привязки CISCO 6509 SUP-2/MSFC-2/PFC2 IOS (c6sup2_rp-JK2O3SV-M), Version 12.1(26)E9, RELEASE SOFTWARE (fc1) Так как весия IOS 12.1 поддер...)
(убрал типизацию (int и т.п))
 
(17 промежуточных версий не показаны.)
Строка 1: Строка 1:
-
Стоит задача привязки CISCO 6509 SUP-2/MSFC-2/PFC2 IOS (c6sup2_rp-JK2O3SV-M), Version 12.1(26)E9, RELEASE SOFTWARE (fc1)
+
Стоит задача привязки CISCO Catalyst 6509 SUP-2/MSFC-2/PFC2 IOS (c6sup2_rp-JK2O3SV-M), Version 12.1(26)E9, RELEASE SOFTWARE (fc1) к БГ-биллингу версии 4.5<br>
-
Так как весия IOS 12.1 поддерживает нумерацию правил акцесс-листа то из за этого шлюзы типа CISCO и CISCO2 не могут быть использованы для привязки данного железа к биллингу.
+
Так как весия IOS 12.1 для коммутаторов не поддерживает нумерацию правил акцесс-листа то из за этого стандартные шлюзы которые описаны в инструкции типа CISCO и CISCO2 не могут быть использованы для привязки данного железа к биллингу.<br>
-
Разработчиком был написан интерфейс в версии 4.5 который позволяет использовать внешние скрипты, куда собственно я и вынес логику общения биллинга с моей цыской.
+
В версии 4.5 разработчиком по моей просьбе был написан интерфейс и скрипт (JAVA) вызова файла с логикой шлюза (ACC) который позволяет использовать внешние скрипты, куда собственно я и вынес логику общения биллинга с моей цыской.<br>
-
Заходим в модуль IPN
+
Рекомендую перед началом действий сначала всё прочитать, а только потом что то делать, так как структура файлов очень мудрённая.
 +
 
 +
----
 +
 
 +
И так, заходим в настройки модуля IPN<br>
1. Создаём тип шлюза - Script-perl
1. Создаём тип шлюза - Script-perl
-
Конфигурация:
+
Закладка "Конфигурация" типа шлюза:
-
[code]
+
<pre>
user_rule.editor.class=bitel.billing.module.services.ipn.editor.ManadContractRuleEditor
user_rule.editor.class=bitel.billing.module.services.ipn.editor.ManadContractRuleEditor
gate_manager.class=bitel.billing.server.ipn.ManadGateWorker
gate_manager.class=bitel.billing.server.ipn.ManadGateWorker
use.script=1
use.script=1
 +
</pre>
 +
 +
Закладка "Комманды" - оставляем пустой.<br>
 +
Закладка "Типы правил" - оставляем пустой.<br>
 +
В закладке "Скрипт" пишем следующее:
 +
<source lang="java">
 +
import bitel.billing.server.ipn.bean.AddressRange;
 +
import bitel.billing.server.ipn.UserStatus;
 +
import bitel.billing.server.ipn.bean.AddressRangeManager;
 +
import bitel.billing.server.util.DefaultServerSetup;
 +
import bitel.billing.server.util.Utils;
 +
import bitel.billing.common.IPUtils;
 +
 +
protected void doSync()
 +
{
 +
    date = new GregorianCalendar();
 +
    gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n"
 +
);                             
 +
    script = gateSetup.getStringValue( "script");
 +
 +
    //цикл по всем договорам на этом шлюзе
 +
    for( UserStatus status : statusList )
 +
    {
 +
        cid = status.contractId;
 +
        //
 +
        AddressRangeManager man = new AddressRangeManager( con, mid );
 +
        addressList = man.getContractAddressRange( cid, date, -1 );
 +
        for ( AddressRange range : addressList)
 +
        {
 +
            ip = getIP( range);
 +
            mask = getMask ( range) ;
 +
            String host = gate.getHost();
 +
            if ( mask == null )
 +
            {
 +
                log.info( "Incorrect range  for cid = " + cid );
 +
                continue;
 +
            }
 +
            log.info( "script = " + script );
 +
            log.info( "ip = " + ip ); 
 +
            log.info( "mask = " + mask ); 
 +
            log.info( "host = " + host ); 
 +
 +
 +
            String [] arguments = { script, ip, mask, host, String.valueOf( status.status ) };
 +
 +
            //выполняем команду
 +
            Process process = Runtime.getRuntime().exec( arguments );
 +
              //ждем окончания работы процесса ..Это не обязательно
 +
            process.waitFor();
 +
            log.info( "exitCode=" + process.exitValue() );     
 +
     
 +
        }
 +
    }
 +
}
 +
 +
getIP ( range )
 +
{
 +
    return IPUtils.convertIpToString( range.getAddr1() );
 +
}
 +
getMask ( range )
 +
{
 +
    result = null;
 +
    delta = range.getAddr2() - range.getAddr1() + 1;
 +
    pow = getPow( delta );
 +
    log.info( "pow = " + pow );
 +
 
 +
 +
    //махинация для того чтоб получить 0xFFFFFFFF -в beanshell не
 +
//получилось задать такое большое число и модификатор l в конце не работает
 +
    ffMask = (0xFFFFFFF);
 +
    ffMask = (ffMask << 8 ) | 0xFF;
 +
 +
    if ( pow >= 0 )
 +
    {         
 +
        mask = ffMask;
 +
        mask = (mask << pow) & ffMask;     
 +
        result = IPUtils.convertIpToString( mask );
 +
    } 
 +
    return result;
 +
}
 +
 +
//находим разницу между двумя ip(она должна быть степеью двойки) и
 +
//возращаем эту степень
 +
getPow( long delta )
 +
{
 +
    idx = 0;
 +
    count = 0;
 +
    pow = -1;
 +
    while (  delta > 0 )
 +
    {
 +
         
 +
        if ( (delta  &  1 ) == 1 )
 +
        {
 +
            count ++;
 +
            pow = idx;
 +
            if ( count > 1)
 +
            {
 +
                break;
 +
            }                         
 +
        }
 +
        delta = (delta >> 1);
 +
         
 +
        idx++;
 +
                     
 +
    }
 +
    //если не одна единица в числе, значит это не степень двойки и
 +
//диапазон задан неверно
 +
    if ( count != 1 )
 +
    {
 +
          pow = -1;         
 +
    }
 +
    return pow;
 +
}
 +
</source>
 +
За данный код спасибо разработчикам.<br>
 +
Нажимаем ОК.<br>
 +
Тип шлюза создан!<br>
 +
 +
---
 +
 +
2. Идём в закладку Шлюзы.<br>
 +
Создаём шлюз:<br>
 +
В параметры Хост и порт шлюза, а так же Ключевое слово можно написать что угодно, оно для нас не имеет значения.<br>
 +
В "Тип шлюза" - указываем созданный нами тип шлюза - Script-perl<br>
 +
Комментарий оставляем пустым.<br>
 +
В конфигурацию пишем следующее:
 +
<pre>
script=/usr/local/BGBillingServer/ACC
script=/usr/local/BGBillingServer/ACC
-
[/code]
+
</pre>
-
Создаём шлюз -  
+
В переменную script пишем путь до нашего скрипта с логикой, а скрипт АСС - есть мой скрипт на перле с логикой связи, спасибо Мне!<br>
-
[code]
+
Нажимаем ОК<br>
 +
Шлюз создан!
 +
 
 +
---
 +
 
 +
3. Мой скрипт ACC написан на PERL и использует телнет для управления железом.<br>
 +
Для его работы необходим модуль NET:TELNET который можно взять из CPAN.<br>
 +
На цыске должен быть создан пользователь LOGIN с паролем PASS (крупные буквы заменить своими значениями).<br>
 +
Для уменьшения проблем вот конфиг цыски оптимизированной под данную связку:
 +
<pre>
 +
aaa new-model
 +
username LOGIN privilege 15 secret 0 PASS
 +
!
 +
interface Vlan11
 +
description "Kurchatova str."
 +
ip address 123.123.123.1 255.255.255.0
 +
no ip redirects
 +
ip route-cache policy
 +
ip route-cache flow
 +
ip policy route-map ACCESS-CLIENTS
 +
load-interval 30
 +
interface Loopback0
 +
no ip address
 +
!
 +
route-map ACCESS-CLIENTS permit 1
 +
match ip address 100
 +
set interface Loopback0 Null0
 +
!
 +
access-list 100 deny  ip 123.123.123.4 0.0.0.3 any
 +
access-list 100 permit ip any any
 +
!
 +
line vty 0 15
 +
exec-timeout 0 0
 +
privilege level 15
 +
logging synchronous
 +
transport input telnet ssh
 +
transport output telnet ssh
 +
</pre>
 +
Line vty 0 15 - рекомендую поставить именно столько, потому что если поставить меньше то при массовом отключении или подключении некоторых клиентов не прописывало на цыске ввиду ограниченного количества терминалов...<br>
 +
Небольшие пояснения к логике работы цыски:<br>
 +
Существует роут-мап ACCESS-CLIENTS который вешается на IP интерфейс клиента (в примере vlan11), в данном роут-мапе сказано что любой трафик который попадает в акцесс-лист 100 стоит уничтожать (кстати тут можно прописать редирект на страницу, где сказано что доступ отсутствует из-за блокировки - пока не реализовано).<br>
 +
В акцесс-листе 100 мы прописываем всех кому нужен инет как DENY (этим как раз и занимается мой скрипт), тем самым их трафик не попадёт в роут-мап ACCESS-CLIENTS.<br>
 +
Так как последним правилом в данном листе стоит permit ip any any, то любой тарфик который не DENY будет уничтожен.<br>
 +
Необходимо обязательно в ручную прописать все ваши сервера ДНС и хосты которые должны быть доступны клиентам до подключения как DENY!!!<br>
 +
 
 +
Код скрипта логики ACC:
 +
<source lang="perl">
 +
#!/usr/bin/perl
 +
#edit by 06.01.2009 18:26 Max
 +
 
 +
$ip=@ARGV[0];
 +
$netmask=@ARGV[1];
 +
$nas=@ARGV[2];
 +
$status=@ARGV[3];
 +
 
 +
#Wailcard netmask
 +
if($netmask eq '255.255.255.255'){$wnetmask='0.0.0.0';}
 +
elsif($netmask eq '255.255.255.252'){$wnetmask='0.0.0.3';}
 +
elsif($netmask eq '255.255.255.248'){$wnetmask='0.0.0.7';}
 +
elsif($netmask eq '255.255.255.240'){$wnetmask='0.0.0.15';}
 +
elsif($netmask eq '255.255.255.224'){$wnetmask='0.0.0.31';}
 +
elsif($netmask eq '255.255.255.192'){$wnetmask='0.0.0.63';}
 +
elsif($netmask eq '255.255.255.128'){$wnetmask='0.0.0.127';}
 +
elsif($netmask eq '255.255.255.0'){$wnetmask='0.0.0.255';}
 +
elsif($netmask eq '255.255.254.0'){$wnetmask='0.0.1.255';}
 +
elsif($netmask eq '255.255.252.0'){$wnetmask='0.0.3.255';}
 +
elsif($netmask eq '255.255.248.0'){$wnetmask='0.0.7.255';}
 +
elsif($netmask eq '255.255.240.0'){$wnetmask='0.0.15.255';}
 +
elsif($netmask eq '255.255.224.0'){$wnetmask='0.0.31.255';}
 +
else{&error;}
 +
 
 +
if($status eq 0){&auth;}
 +
    elsif($status eq 1){&no_auth;}
 +
    elsif($status eq 2){&no_auth;}
 +
    elsif($status eq 3){&no_auth;}
 +
    elsif($status eq 4){&no_auth;}
 +
    else{&error;}
 +
 
 +
###########################################################
 +
#AUTHORIZED################################################
 +
###########################################################
 +
sub auth{
 +
#NAS
 +
if($nas eq '10.11.0.6'){&cisco_2600;}
 +
if($nas eq '10.11.0.10'){&cisco_2600;}
 +
if($nas eq '10.11.0.14'){&cisco_2600;}
 +
if($nas eq '10.11.0.1'){&cisco;}
 +
&error;
 +
}
 +
 
 +
sub cisco{
 +
    use Net::Telnet ();
 +
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
 +
    $t->open("$nas") || die("False\n");
 +
    $t->login("LOGIN", "PASS");
 +
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
 +
    $t->cmd("ip access-list extended 100");
 +
    $t->cmd("deny ip $ip $wnetmask any");
 +
    $t->cmd("no permit ip any any");
 +
    $t->cmd("permit ip any any");
 +
    $t->cmd("$cmd");
 +
    $t->cmd("exit");
 +
exit 0;
 +
}
 +
 
 +
sub cisco_2600{
 +
    use Net::Telnet ();
 +
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
 +
    $t->open("$nas") || die("False\n");
 +
    $t->login("LOGIN", "PASS");
 +
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
 +
    $t->cmd("ip access-list extended 100");
 +
    $t->cmd("permit ip $ip $wnetmask any");
 +
    $t->cmd("no deny ip any any");
 +
    $t->cmd("deny ip any any");
 +
    $t->cmd("$cmd");
 +
    $t->cmd("exit");
 +
exit 0;
 +
}
 +
 
 +
 
 +
###########################################################
 +
#NOAUTH####################################################
 +
###########################################################
 +
 
 +
sub no_auth{
 +
#NAS
 +
if($nas eq '10.11.0.6'){&no_cisco_2600;}
 +
if($nas eq '10.11.0.10'){&no_cisco_2600;}
 +
if($nas eq '10.11.0.14'){&no_cisco_2600;}
 +
if($nas eq '10.11.0.1'){&no_cisco;}
 +
&error;
 +
}
 +
 
 +
sub no_cisco{
 +
    use Net::Telnet ();
 +
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
 +
    $t->open("$nas") || die("False\n");
 +
    $t->login("LOGIN", "PASS");
 +
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
 +
    $t->cmd("ip access-list extended 100");
 +
    $t->cmd("no deny ip $ip $wnetmask any");
 +
    $t->cmd("$cmd");
 +
    $t->cmd("exit");
 +
exit 0;
 +
}
 +
 
 +
sub no_cisco_2600{
 +
    use Net::Telnet ();
 +
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
 +
    $t->open("$nas") || die("False\n");
 +
    $t->login("LOGIN", "PASS");
 +
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
 +
    $t->cmd("ip access-list extended 100");
 +
    $t->cmd("no permit ip $ip $wnetmask any");
 +
    $t->cmd("$cmd");
 +
    $t->cmd("exit");
 +
exit 0;
 +
}
 +
 
 +
 
 +
 
 +
 
 +
#НЕ ОПРЕДЕЛЁН NAS#########################################################################
 +
sub error{
 +
    open(ERR,">>/usr/local/BGBillingServer/log/err.connect.log");
 +
    print ERR "ERROR: CONNECT ip=$ip, netmask=$netmask|$wnetmask, nas=$nas, status=$status\n";
 +
    close ERR;
 +
    exit 1;
 +
}
 +
##########################################################################################
-
[/code]
+
</source>
 +
Все скрипты взяты с рабочей системы!<br>
 +
Скрипт может быть написан на чём угодно, хоть на шеле.<br>
 +
Для новичков и тех кто не знаком с перлом поясню:<br>
 +
Логика такая: скрипту АСС от биллинга передаютя параметры вида IP МАСКА НАС СТАТУС например (123.123.123.0 255.255.255.252 10.10.0.1 0)<br>
 +
Данная строка означает что клиент с сетью 123.123.123.0/30 и шлюзом 10.10.0.1 пытается авторизоваться.<br>
 +
Скрипт будет выполнятся столько раз, сколько диапазонов сетей у клиента.<br>
 +
Мой скрипт решает следующие проблемы:<br>
 +
1. Опеределяет подключается или отключается клиент по флагу СТАТУС, флаг статус может меняться с 0 на 4.<br>
 +
2. Все цыски при заведнии записи в акцесс листах требуют ввода вайлкардовой маски, а биллинг передаёт её в десятичном виде.<br>
 +
3. Позволяет выбирать нас и профайл шлюза.<br>
 +
В моём примере описано два типа шлюза 6509 - cisco и 2620 - cisco_2600 суть их видна в реализации.<br>
 +
У 6509 задействован роут-мап, так как его использование снижает нагрузку по сравнению с методом навешивания на каждый интерфейс акцесс-листа и даёт очень широкое поле для манёвра с клиентским трафиком.<br>
 +
У 2620 задействован только акцесс-лист ввиду малого количества абонентов за данным железом, и простотой использования.<br>
 +
<br>
 +
Для тех кому есть что обсудить или спросить велкам в http://bgbilling.ru/forum/viewtopic.php?p=10713#10713

Текущая версия на 07:25, 14 января 2009

Стоит задача привязки CISCO Catalyst 6509 SUP-2/MSFC-2/PFC2 IOS (c6sup2_rp-JK2O3SV-M), Version 12.1(26)E9, RELEASE SOFTWARE (fc1) к БГ-биллингу версии 4.5
Так как весия IOS 12.1 для коммутаторов не поддерживает нумерацию правил акцесс-листа то из за этого стандартные шлюзы которые описаны в инструкции типа CISCO и CISCO2 не могут быть использованы для привязки данного железа к биллингу.
В версии 4.5 разработчиком по моей просьбе был написан интерфейс и скрипт (JAVA) вызова файла с логикой шлюза (ACC) который позволяет использовать внешние скрипты, куда собственно я и вынес логику общения биллинга с моей цыской.
Рекомендую перед началом действий сначала всё прочитать, а только потом что то делать, так как структура файлов очень мудрённая.


И так, заходим в настройки модуля IPN
1. Создаём тип шлюза - Script-perl Закладка "Конфигурация" типа шлюза:

user_rule.editor.class=bitel.billing.module.services.ipn.editor.ManadContractRuleEditor
gate_manager.class=bitel.billing.server.ipn.ManadGateWorker
use.script=1

Закладка "Комманды" - оставляем пустой.
Закладка "Типы правил" - оставляем пустой.
В закладке "Скрипт" пишем следующее:

import bitel.billing.server.ipn.bean.AddressRange;
import bitel.billing.server.ipn.UserStatus;
import bitel.billing.server.ipn.bean.AddressRangeManager;
import bitel.billing.server.util.DefaultServerSetup;
import bitel.billing.server.util.Utils;
import bitel.billing.common.IPUtils;
 
protected void doSync()
{
    date = new GregorianCalendar();
    gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" 
);                               
    script = gateSetup.getStringValue( "script");
 
    //цикл по всем договорам на этом шлюзе
    for( UserStatus status : statusList )
    {
        cid = status.contractId;
        //
        AddressRangeManager man = new AddressRangeManager( con, mid );
        addressList = man.getContractAddressRange( cid, date, -1 );
        for ( AddressRange range : addressList)
        {
            ip = getIP( range);
            mask = getMask ( range) ;
            String host = gate.getHost();
            if ( mask == null )
            {
                log.info( "Incorrect range  for cid = " + cid );
                continue;
            }
            log.info( "script = " + script );
            log.info( "ip = " + ip );   
            log.info( "mask = " + mask );   
            log.info( "host = " + host );   
 
 
            String [] arguments = { script, ip, mask, host, String.valueOf( status.status ) };
 
            //выполняем команду
            Process process = Runtime.getRuntime().exec( arguments );
               //ждем окончания работы процесса ..Это не обязательно
            process.waitFor();
            log.info( "exitCode=" + process.exitValue() );       
 
        }
    }
}
 
getIP ( range )
{
    return IPUtils.convertIpToString( range.getAddr1() );
}
getMask ( range )
{
    result = null;
    delta = range.getAddr2() - range.getAddr1() + 1;
    pow = getPow( delta );
    log.info( "pow = " + pow );
 
 
    //махинация для того чтоб получить 0xFFFFFFFF -в beanshell не 
//получилось задать такое большое число и модификатор l в конце не работает
    ffMask = (0xFFFFFFF);
    ffMask = (ffMask << 8 ) | 0xFF;
 
    if ( pow >= 0 )
    {           
        mask = ffMask;
        mask = (mask << pow) & ffMask;       
        result = IPUtils.convertIpToString( mask );
    }   
    return result;
}
 
//находим разницу между двумя ip(она должна быть степеью двойки) и 
//возращаем эту степень
getPow( long delta )
{
    idx = 0;
    count = 0;
    pow = -1;
    while (  delta > 0 )
    {
 
        if ( (delta  &  1 ) == 1 )
        {
            count ++;
            pow = idx;
            if ( count > 1)
            {
                break;
            }                           
        }
        delta = (delta >> 1);
 
        idx++;
 
    }
    //если не одна единица в числе, значит это не степень двойки и 
//диапазон задан неверно 
    if ( count != 1 )
    {
          pow = -1;           
    }
    return pow;
}

За данный код спасибо разработчикам.
Нажимаем ОК.
Тип шлюза создан!

---

2. Идём в закладку Шлюзы.
Создаём шлюз:
В параметры Хост и порт шлюза, а так же Ключевое слово можно написать что угодно, оно для нас не имеет значения.
В "Тип шлюза" - указываем созданный нами тип шлюза - Script-perl
Комментарий оставляем пустым.
В конфигурацию пишем следующее:

script=/usr/local/BGBillingServer/ACC

В переменную script пишем путь до нашего скрипта с логикой, а скрипт АСС - есть мой скрипт на перле с логикой связи, спасибо Мне!
Нажимаем ОК
Шлюз создан!

---

3. Мой скрипт ACC написан на PERL и использует телнет для управления железом.
Для его работы необходим модуль NET:TELNET который можно взять из CPAN.
На цыске должен быть создан пользователь LOGIN с паролем PASS (крупные буквы заменить своими значениями).
Для уменьшения проблем вот конфиг цыски оптимизированной под данную связку:

aaa new-model
username LOGIN privilege 15 secret 0 PASS
!
interface Vlan11
 description "Kurchatova str."
 ip address 123.123.123.1 255.255.255.0
 no ip redirects
 ip route-cache policy
 ip route-cache flow
 ip policy route-map ACCESS-CLIENTS
 load-interval 30
interface Loopback0
 no ip address
!
route-map ACCESS-CLIENTS permit 1
 match ip address 100
 set interface Loopback0 Null0
!
access-list 100 deny   ip 123.123.123.4 0.0.0.3 any
access-list 100 permit ip any any
!
line vty 0 15
 exec-timeout 0 0
 privilege level 15
 logging synchronous
 transport input telnet ssh
 transport output telnet ssh

Line vty 0 15 - рекомендую поставить именно столько, потому что если поставить меньше то при массовом отключении или подключении некоторых клиентов не прописывало на цыске ввиду ограниченного количества терминалов...
Небольшие пояснения к логике работы цыски:
Существует роут-мап ACCESS-CLIENTS который вешается на IP интерфейс клиента (в примере vlan11), в данном роут-мапе сказано что любой трафик который попадает в акцесс-лист 100 стоит уничтожать (кстати тут можно прописать редирект на страницу, где сказано что доступ отсутствует из-за блокировки - пока не реализовано).
В акцесс-листе 100 мы прописываем всех кому нужен инет как DENY (этим как раз и занимается мой скрипт), тем самым их трафик не попадёт в роут-мап ACCESS-CLIENTS.
Так как последним правилом в данном листе стоит permit ip any any, то любой тарфик который не DENY будет уничтожен.
Необходимо обязательно в ручную прописать все ваши сервера ДНС и хосты которые должны быть доступны клиентам до подключения как DENY!!!

Код скрипта логики ACC:

#!/usr/bin/perl
#edit by 06.01.2009 18:26 Max
 
$ip=@ARGV[0];
$netmask=@ARGV[1];
$nas=@ARGV[2];
$status=@ARGV[3];
 
#Wailcard netmask
if($netmask eq '255.255.255.255'){$wnetmask='0.0.0.0';}
elsif($netmask eq '255.255.255.252'){$wnetmask='0.0.0.3';}
elsif($netmask eq '255.255.255.248'){$wnetmask='0.0.0.7';}
elsif($netmask eq '255.255.255.240'){$wnetmask='0.0.0.15';}
elsif($netmask eq '255.255.255.224'){$wnetmask='0.0.0.31';}
elsif($netmask eq '255.255.255.192'){$wnetmask='0.0.0.63';}
elsif($netmask eq '255.255.255.128'){$wnetmask='0.0.0.127';}
elsif($netmask eq '255.255.255.0'){$wnetmask='0.0.0.255';}
elsif($netmask eq '255.255.254.0'){$wnetmask='0.0.1.255';}
elsif($netmask eq '255.255.252.0'){$wnetmask='0.0.3.255';}
elsif($netmask eq '255.255.248.0'){$wnetmask='0.0.7.255';}
elsif($netmask eq '255.255.240.0'){$wnetmask='0.0.15.255';}
elsif($netmask eq '255.255.224.0'){$wnetmask='0.0.31.255';}
else{&error;}
 
if($status eq 0){&auth;}
    elsif($status eq 1){&no_auth;}
    elsif($status eq 2){&no_auth;}
    elsif($status eq 3){&no_auth;}
    elsif($status eq 4){&no_auth;}
    else{&error;}
 
###########################################################
#AUTHORIZED################################################
###########################################################
sub auth{
#NAS
if($nas eq '10.11.0.6'){&cisco_2600;}
if($nas eq '10.11.0.10'){&cisco_2600;}
if($nas eq '10.11.0.14'){&cisco_2600;}
if($nas eq '10.11.0.1'){&cisco;}
&error;
}
 
sub cisco{
    use Net::Telnet ();
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
    $t->open("$nas") || die("False\n");
    $t->login("LOGIN", "PASS");
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
    $t->cmd("ip access-list extended 100");
    $t->cmd("deny ip $ip $wnetmask any");
    $t->cmd("no permit ip any any");
    $t->cmd("permit ip any any");
    $t->cmd("$cmd");
    $t->cmd("exit");
exit 0;
}
 
sub cisco_2600{
    use Net::Telnet ();
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
    $t->open("$nas") || die("False\n");
    $t->login("LOGIN", "PASS");
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
    $t->cmd("ip access-list extended 100");
    $t->cmd("permit ip $ip $wnetmask any");
    $t->cmd("no deny ip any any");
    $t->cmd("deny ip any any");
    $t->cmd("$cmd");
    $t->cmd("exit");
exit 0;
}
 
 
###########################################################
#NOAUTH####################################################
###########################################################
 
sub no_auth{
#NAS
if($nas eq '10.11.0.6'){&no_cisco_2600;}
if($nas eq '10.11.0.10'){&no_cisco_2600;}
if($nas eq '10.11.0.14'){&no_cisco_2600;}
if($nas eq '10.11.0.1'){&no_cisco;}
&error;
}
 
sub no_cisco{
    use Net::Telnet ();
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
    $t->open("$nas") || die("False\n");
    $t->login("LOGIN", "PASS");
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
    $t->cmd("ip access-list extended 100");
    $t->cmd("no deny ip $ip $wnetmask any");
    $t->cmd("$cmd");
    $t->cmd("exit");
exit 0;
}
 
sub no_cisco_2600{
    use Net::Telnet ();
    $t = new Net::Telnet (Timeout => 30, Prompt => '/#/');
    $t->open("$nas") || die("False\n");
    $t->login("LOGIN", "PASS");
    $t->cmd(String => 'conf t', Cmd_remove_mode => 0);
    $t->cmd("ip access-list extended 100");
    $t->cmd("no permit ip $ip $wnetmask any");
    $t->cmd("$cmd");
    $t->cmd("exit");
exit 0;
}
 
 
 
 
#НЕ ОПРЕДЕЛЁН NAS#########################################################################
sub error{
    open(ERR,">>/usr/local/BGBillingServer/log/err.connect.log");
    print ERR "ERROR: CONNECT ip=$ip, netmask=$netmask|$wnetmask, nas=$nas, status=$status\n";
    close ERR;
    exit 1;
}
##########################################################################################

Все скрипты взяты с рабочей системы!
Скрипт может быть написан на чём угодно, хоть на шеле.
Для новичков и тех кто не знаком с перлом поясню:
Логика такая: скрипту АСС от биллинга передаютя параметры вида IP МАСКА НАС СТАТУС например (123.123.123.0 255.255.255.252 10.10.0.1 0)
Данная строка означает что клиент с сетью 123.123.123.0/30 и шлюзом 10.10.0.1 пытается авторизоваться.
Скрипт будет выполнятся столько раз, сколько диапазонов сетей у клиента.
Мой скрипт решает следующие проблемы:
1. Опеределяет подключается или отключается клиент по флагу СТАТУС, флаг статус может меняться с 0 на 4.
2. Все цыски при заведнии записи в акцесс листах требуют ввода вайлкардовой маски, а биллинг передаёт её в десятичном виде.
3. Позволяет выбирать нас и профайл шлюза.
В моём примере описано два типа шлюза 6509 - cisco и 2620 - cisco_2600 суть их видна в реализации.
У 6509 задействован роут-мап, так как его использование снижает нагрузку по сравнению с методом навешивания на каждый интерфейс акцесс-листа и даёт очень широкое поле для манёвра с клиентским трафиком.
У 2620 задействован только акцесс-лист ввиду малого количества абонентов за данным железом, и простотой использования.

Для тех кому есть что обсудить или спросить велкам в http://bgbilling.ru/forum/viewtopic.php?p=10713#10713

Личные инструменты