Пример реализации скриптового универсального шлюза
Материал из BiTel WiKi
Max (Обсуждение | вклад) (Новая: Стоит задача привязки CISCO 6509 SUP-2/MSFC-2/PFC2 IOS (c6sup2_rp-JK2O3SV-M), Version 12.1(26)E9, RELEASE SOFTWARE (fc1) Так как весия IOS 12.1 поддер...) |
Stark (Обсуждение | вклад) (убрал типизацию (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 разработчиком по моей просьбе был написан интерфейс и скрипт (JAVA) вызова файла с логикой шлюза (ACC) который позволяет использовать внешние скрипты, куда собственно я и вынес логику общения биллинга с моей цыской.<br> | |
- | + | Рекомендую перед началом действий сначала всё прочитать, а только потом что то делать, так как структура файлов очень мудрённая. | |
+ | |||
+ | ---- | ||
+ | |||
+ | И так, заходим в настройки модуля IPN<br> | ||
1. Создаём тип шлюза - Script-perl | 1. Создаём тип шлюза - Script-perl | ||
- | Конфигурация: | + | Закладка "Конфигурация" типа шлюза: |
- | + | <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 | ||
- | + | </pre> | |
- | + | В переменную script пишем путь до нашего скрипта с логикой, а скрипт АСС - есть мой скрипт на перле с логикой связи, спасибо Мне!<br> | |
- | [ | + | Нажимаем ОК<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; | ||
+ | } | ||
+ | ########################################################################################## | ||
- | + | </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