The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Создание BRAS/SSG на базе Cisco 7206 и FreeRADIUS (cisco pppoe ssg shper bandwidth ios mysql radius)


<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>
Ключевые слова: cisco, pppoe, ssg, shper, bandwidth, ios, mysql, radius,  (найти похожие документы)
From: Alex/AT <alex@net13.info.> Newsgroups: email Date: Mon, 24 Dec 2009 17:02:14 +0000 (UTC) Subject: Создание BRAS/SSG на базе Cisco 7206 и FreeRADIUS Оригинал: http://alex-at.ru/cisco/ssg-cisco-7206-pppoe Внедряем профили SSG на Cisco 7206 с целью ограничения скорости и организации псевдо-локалки абонентам PPPoE В этой статье я вкратце расскажу вам о том, как правильно организовать управление абонентами с помощью SSG на Cisco 7206. Фактически Cisco 7206 с IOS 12.2SR является полнофункциональным BRAS и SSG (Subscriber Service Gateway), на котором мы можем тонко управлять обслуживанием абонентов, используя функции SSG. Итак, поставленная задача: 1. Организовать доступ абонентов, приходящих на Q-in-Q VLAN'ах, к сети по протоколу PPPoE. 2. Организовать авторизацию доступа абонентов по протоколу CHAP, используя для авторизации сервер RADIUS. 3. Организовать возможность управления скоростью пропускания трафика для каждого абонента, причем: 3а. Скорость доступа в Internet должна жестко ограничиваться заданным параметром (для каждого абонента в отдельности). 3б. Скорость доступа между абонентами, а также к заданным сетям и ресурсам, должна иметь общее для всех и достаточно высокое ограничение ("локальная" скорость). 4. Организовать возможность независимого отключения каждого конкретного абонента, причем при этом должна сохраняться возможность доступа к отдельным ресурсам (к примеру - сайту и личному кабинету). 5. Организовать возможность учета внешнего трафика абонентов средствами RADIUS, причем трафик пункта 3б ("локальный трафик") учитываться не должен. Если вас заинтересовало решение поставленной задачи, то читайте далее. Часть 1: FreeRADIUS. Начинаем действовать Нам потребуются: * Cisco 7206 NPE-G2 (в принципе, любая Cisco 7200 серии должна подойти) с IOS 12.2SR. * Готовый к работе Linux-сервер (я строил все на CentOS 5) * Дистрибутивы FreeRadius 2.x и MySQL 5.x (первое я собирал из исходников, второе - ставил из RPM от разработчиков MySQL) * Свежая голова и прямые руки (или холодильник и плоскогубцы) 1. Установка и настройка RADIUS Вначале подготовим наш сервер RADIUS к работе. Как установить FreeRADIUS c MySQL, я описывать не буду - если уж решились взяться за Cisco 7206 и сервисные службы - значит вполне способны справиться с этой простейшей задачей. Я отмечу только отдельные тонкости установки FreeRADIUS, которые необходимы для корректной работы всей системы. В словарь FreeRADIUS придется добавить такую строчку: ATTRIBUTE Client-MAC-Address 3330 string Она нужна для того, чтобы MAC-адреса клиентов могли корректно записываться в базу данных. Идентификатор (3330) - не важен, этот атрибут определяется по строке в Acct-данных, присылаемой в Cisco-AVPair формате, главное, чтобы он ни с чем не пересекался. Модуль acct-unique настраиваем следующим образом: acct_unique { key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port" } В модуле preprocess не забудьте настроить: with_cisco_vsa_hack = yes Это позволит нам нормально аккаунтить Cisco VSA пары атрибут-значение. После того, как FreeRADIUS установлен и основательно настроен, надо связать его с MySQL (или другой базой на ваш вкус, я привожу конфигурацию для MySQL). Мы будем использовать следующую схему БД MySQL: -- -- База данных: 'radius' -- -- -------------------------------------------------------- -- -- Структура таблицы 'nas' -- CREATE TABLE 'nas' ( 'id' int(10) NOT NULL auto_increment, 'nasname' varchar(128) NOT NULL, 'shortname' varchar(32) default NULL, 'type' varchar(30) default 'other', 'ports' int(5) default NULL, 'secret' varchar(60) NOT NULL default 'secret', 'community' varchar(50) default NULL, 'description' varchar(200) default 'RADIUS Client', PRIMARY KEY ('id'), KEY 'nasname' ('nasname') ); -- -------------------------------------------------------- -- -- Структура таблицы 'radacct' -- CREATE TABLE 'radacct' ( 'RadAcctId' bigint(21) NOT NULL auto_increment, 'AcctSessionId' varchar(32) NOT NULL default '', 'AcctUniqueId' varchar(32) NOT NULL default '', 'UserName' varchar(64) NOT NULL default '', 'Realm' varchar(64) default '', 'NASIPAddress' varchar(15) NOT NULL default '', 'NASPortId' varchar(15) default NULL, 'NASPortType' varchar(32) default NULL, 'AcctStartTime' datetime default '0000-00-00 00:00:00', 'AcctStopTime' datetime default NULL, 'AcctSessionTime' int(12) default NULL, 'AcctAuthentic' varchar(32) default NULL, 'ConnectInfo_start' varchar(50) default NULL, 'ConnectInfo_stop' varchar(50) default NULL, 'AcctInputOctets' bigint(12) default NULL, 'AcctOutputOctets' bigint(12) default NULL, 'CalledStationId' varchar(50) NOT NULL default '', 'CallingStationId' varchar(50) NOT NULL default '', 'AcctTerminateCause' varchar(32) NOT NULL default '', 'ServiceType' varchar(32) default NULL, 'ServiceInfo' varchar(64) NOT NULL default '', 'FramedProtocol' varchar(32) default NULL, 'FramedIPAddress' varchar(15) NOT NULL default '', 'AcctStartDelay' int(12) default NULL, 'AcctStopDelay' int(12) default NULL, 'ClientMACAddress' varchar(24) NOT NULL default '', PRIMARY KEY ('RadAcctId'), KEY 'UserName' ('UserName'), KEY 'FramedIPAddress' ('FramedIPAddress'), KEY 'AcctSessionId' ('AcctSessionId'), KEY 'AcctUniqueId' ('AcctUniqueId'), KEY 'AcctStopTime' ('AcctStopTime'), KEY 'NASIPAddress' ('NASIPAddress'), KEY 'AcctStartTime_2' ('AcctStartTime','AcctStopTime'), KEY 'summary_index' ('UserName','ServiceInfo'(8),'AcctStartTime','AcctStopTime','AcctInp utOctets','AcctOutputOctets','AcctSessionTime') ); -- -------------------------------------------------------- -- -- Структура таблицы 'radcheck' -- CREATE TABLE 'radcheck' ( 'id' int(11) unsigned NOT NULL auto_increment, 'UserName' varchar(64) NOT NULL default '', 'Attribute' varchar(32) NOT NULL default '', 'op' char(2) NOT NULL default '==', 'Value' varchar(253) NOT NULL default '', PRIMARY KEY ('id'), KEY 'UserName' ('UserName'(32)), KEY 'UserAttr' ('UserName','Attribute') ); -- -------------------------------------------------------- -- -- Структура таблицы 'radgroupcheck' -- CREATE TABLE 'radgroupcheck' ( 'id' int(11) unsigned NOT NULL auto_increment, 'GroupName' varchar(64) NOT NULL default '', 'Attribute' varchar(32) NOT NULL default '', 'op' char(2) NOT NULL default '==', 'Value' varchar(253) NOT NULL default '', PRIMARY KEY ('id'), KEY 'GroupName' ('GroupName'(32)) ); -- -------------------------------------------------------- -- -- Структура таблицы 'radgroupreply' -- CREATE TABLE 'radgroupreply' ( 'id' int(11) unsigned NOT NULL auto_increment, 'GroupName' varchar(64) NOT NULL default '', 'Attribute' varchar(32) NOT NULL default '', 'op' char(2) NOT NULL default '=', 'Value' varchar(253) NOT NULL default '', PRIMARY KEY ('id'), KEY 'GroupName' ('GroupName'(32)) ); -- -------------------------------------------------------- -- -- Структура таблицы 'radpostauth' -- CREATE TABLE 'radpostauth' ( 'id' int(11) NOT NULL auto_increment, 'user' varchar(64) NOT NULL default '', 'pass' varchar(64) NOT NULL default '', 'reply' varchar(32) NOT NULL default '', 'reply_message' varchar(255) NOT NULL, 'date' timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY ('id') ); -- -------------------------------------------------------- -- -- Структура таблицы 'radreply' -- CREATE TABLE 'radreply' ( 'id' int(11) unsigned NOT NULL auto_increment, 'UserName' varchar(64) NOT NULL default '', 'Attribute' varchar(32) NOT NULL default '', 'op' char(2) NOT NULL default '=', 'Value' varchar(253) NOT NULL default '', PRIMARY KEY ('id'), KEY 'UserName' ('UserName'(32)) ); -- -------------------------------------------------------- -- -- Структура таблицы 'usergroup' -- CREATE TABLE 'usergroup' ( 'UserName' varchar(64) NOT NULL default '', 'GroupName' varchar(64) NOT NULL default '', 'priority' int(11) NOT NULL default '1', KEY 'GroupName' ('GroupName'), KEY 'UserGroup' ('UserName','GroupName'), KEY 'UserName' ('UserName','priority') ); Не будем обсуждать здесь выбор конкретных значений и оптимальность базы - если вас что-то не устраивает - вы всегда можете поменять все, что захотите. В моем случае именно такая структура базы оказалась субоптимальной, хотя поле для деятельности, конечно же, еще имеется. Для работы с этой схемой нам потребуется файл-описатель модуля sql для FreeRADIUS . И вот тут-то кроется самое интересное. Дело в том, что FreeRADIUS по умолчанию не соблюдает разумный порядок атрибутов, назначенных абоненту. По уму, хотелось бы видеть сначала атрибуты всех групп, назначенных абоненту, и только после - атрибуты самого абонента (чтобы можно было там оверрайдить что-нибудь из групп). Алгоритмы работы с группами в FreeRADIUS нам этого не позволяют. Поэтому придется извращаться. Не волнуйтесь, данное извращение ни капельки не ухудшает (а может быть - даже улучшает) производительность, зато дает нам некоторую предсказуемость порядка возвращаемых атрибутов. sql sql_bras { database = "mysql" driver = "rlm_sql_${database}" server = "localhost" port = 3306 login = "сюда вставляем логин к БД" password = "сюда вставляем пароль к БД" radius_db = "сюда вставляем имя БД" acct_table1 = "radacct" acct_table2 = "radacct" postauth_table = "radpostauth" authcheck_table = "radcheck" authreply_table = "radreply" groupcheck_table = "radgroupcheck" groupreply_table = "radgroupreply" usergroup_table = "usergroup" deletestalesessions = yes sqltrace = no num_sql_socks = 8 connect_failure_retry_delay = 15 lifetime = 3600 max_queries = 1024 nas_table = "nas" sql_user_name = "%{User-Name}" nas_query = "SELECT 'id', 'nasname', 'shortname', 'type', 'secret' FROM '${nas_table}'" authorize_check_query = "( \ SELECT 1 , '%{SQL-User-Name}', 'rgc'.'Attribute' , 'rgc'.'Value' , 'rgc'.'op' \ FROM '${usergroup_table}' AS 'ug' \ INNER JOIN '${groupcheck_table}' AS 'rgc' ON 'rgc'.'GroupName' = 'ug'.'GroupName' \ WHERE 'ug'.'UserName' = '%{SQL-User-Name}' \ ORDER BY 'ug'.'priority' ASC \ ) \ UNION \ ( \ SELECT 1 , 'rc'.'UserName' , 'rc'.'Attribute' , 'rc'.'Value' , 'rc'.'op' \ FROM '${authcheck_table}' AS 'rc' \ WHERE 'rc'.'UserName' = '%{SQL-User-Name}' \ )" authorize_reply_query = "( \ SELECT 1 , '%{SQL-User-Name}', 'rgc'.'Attribute' , 'rgc'.'Value' , 'rgc'.'op' \ FROM '${usergroup_table}' AS 'ug' \ INNER JOIN '${groupreply_table}' AS 'rgc' ON 'rgc'.'GroupName' = 'ug'.'GroupName' \ WHERE 'ug'.'UserName' = '%{SQL-User-Name}' \ ORDER BY 'ug'.'priority' ASC \ ) \ UNION \ ( \ SELECT 1 , 'rc'.'UserName' , 'rc'.'Attribute' , 'rc'.'Value' , 'rc'.'op' \ FROM '${authreply_table}' AS 'rc' \ WHERE 'rc'.'UserName' = '%{SQL-User-Name}' \ )" accounting_onoff_query = "\ UPDATE '${acct_table1}' \ SET \ 'AcctStopTime' = '%S', \ 'AcctSessionTime' = unix_timestamp('%S') - unix_timestamp('AcctStartTime'), \ 'AcctTerminateCause' = '%{Acct-Terminate-Cause}', \ 'AcctStopDelay' = %{%{Acct-Delay-Time}:-0} \ WHERE 'AcctStopTime' IS NULL \ AND 'NasIPAddress' = '%{NAS-IP-Address}' \ AND 'AcctStartTime' <= '%S'" accounting_update_query = " \ UPDATE '${acct_table1}' \ SET \ 'FramedIPAddress' = '%{Framed-IP-Address}', \ 'ClientMACAddress' = '%{Client-MAC-Address}', \ 'AcctSessionTime' = '%{Acct-Session-Time}', \ 'AcctInputOctets' = '%{%{Acct-Input-Gigawords}:-0}' " 32 | '%{%{Acct-Input-Octets}:-0}', \ 'AcctOutputOctets' = '%{%{Acct-Output-Gigawords}:-0}' " 32 | '%{%{Acct-Output-Octets}:-0}' \ WHERE 'AcctSessionId' = '%{Acct-Session-Id}' \ AND 'UserName' = '%{SQL-User-Name}' \ AND 'NasIPAddress' = '%{NAS-IP-Address}'" accounting_update_query_alt = " \ INSERT INTO '${acct_table1}' \ ('AcctSessionId', 'AcctUniqueId', 'UserName', \ 'Realm', 'NASIPAddress', 'NASPortId', \ 'NASPorttype', 'AcctStartTime', 'AcctSessionTime', \ 'AcctAuthentic', 'ConnectInfo_Start', 'AcctInputOctets', \ 'AcctOutputOctets', 'CalledStationId', 'CallingStationId', \ 'ServiceType', 'FramedProtocol', 'FramedIPAddress', \ 'AcctStartDelay', 'ServiceInfo', 'ClientMACAddress') \ VALUES \ ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \ '%{SQL-User-Name}', \ '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \ '%{NAS-Port-Type}', \ DATE_SUB('%S', \ INTERVAL (%{%{Acct-Session-Time}:-0} + \ %{%{Acct-Delay-Time}:-0}) SECOND), \ '%{Acct-Session-Time}', \ '%{Acct-Authentic}', '', \ '%{%{Acct-Input-Gigawords}:-0}' " 32 | \ '%{%{Acct-Input-Octets}:-0}', \ '%{%{Acct-Output-Gigawords}:-0}' " 32 | \ '%{%{Acct-Output-Octets}:-0}', \ '%{Called-Station-Id}', '%{Calling-Station-Id}', \ '%{Service-Type}', '%{Framed-Protocol}', \ '%{Framed-IP-Address}', \ '0', SUBSTRING('%{Cisco-Service-Info}', 2)), \ '%{Client-MAC-Address}'" accounting_start_query = " \ INSERT INTO '${acct_table1}' \ ('AcctSessionId', 'AcctUniqueId', 'UserName', \ 'Realm', 'NASIPAddress', 'NASPortId', \ 'NASPortType', 'AcctStartTime', 'AcctStopTime', \ 'AcctSessionTime', 'AcctAuthentic', 'ConnectInfo_Start', \ 'ConnectInfo_Stop', 'AcctInputOctets', 'AcctOutputOctets', \ 'CalledStationId', 'CallingStationId', 'AcctTerminateCause', \ 'ServiceType', 'FramedProtocol', 'FramedIPAddress', \ 'AcctStartDelay', 'AcctStopDelay', 'ClientMACAddress', \ 'ServiceInfo') \ VALUES \ ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \ '%{SQL-User-Name}', \ '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \ '%{NAS-Port-Type}', '%S', NULL, \ '0', '%{Acct-Authentic}', '%{Connect-Info}', \ '', '0', '0', \ '%{Called-Station-Id}', '%{Calling-Station-Id}', '', \ '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', \ '%{%{Acct-Delay-Time}:-0}', '0', '%{Client-MAC-Address}', \ SUBSTRING('%{Cisco-Service-Info}', 2))" accounting_start_query_alt = " \ UPDATE '${acct_table1}' SET \ 'AcctStartTime' = '%S', \ 'AcctStartDelay' = '%{%{Acct-Delay-Time}:-0}', \ 'ConnectInfo_Start' = '%{Connect-Info}', \ 'FramedIPAddress' = '%{Framed-IP-Address}' \ 'ClientMACAddress' = '%{Client-MAC-Address}' \ WHERE 'AcctSessionId' = '%{Acct-Session-Id}' \ AND 'UserName' = '%{SQL-User-Name}' \ AND 'NASIPAddress' = '%{NAS-IP-Address}'" accounting_stop_query = " \ UPDATE '${acct_table2}' SET \ 'AcctStopTime' = '%S', \ 'AcctSessionTime' = '%{Acct-Session-Time}', \ 'AcctInputOctets' = '%{%{Acct-Input-Gigawords}:-0}' " 32 | '%{%{Acct-Input-Octets}:-0}', \ 'AcctOutputOctets' = '%{%{Acct-Output-Gigawords}:-0}' " 32 | '%{%{Acct-Output-Octets}:-0}', \ 'AcctTerminateCause' = '%{Acct-Terminate-Cause}', \ 'AcctStopDelay' = '%{%{Acct-Delay-Time}:-0}', \ 'ConnectInfo_Stop' = '%{Connect-Info}', \ 'FramedIPAddress' = '%{Framed-IP-Address}' \ WHERE 'AcctSessionId' = '%{Acct-Session-Id}' \ AND 'UserName' = '%{SQL-User-Name}' \ AND 'NASIPAddress' = '%{NAS-IP-Address}'" accounting_stop_query_alt = " \ INSERT INTO '${acct_table2}' \ ('AcctSessionId', 'AcctUniqueId', 'UserName', \ 'Realm', 'NASIPAddress', 'NASPortId', \ 'NASPortType', 'AcctStartTime', 'AcctStopTime', \ 'AcctSessionTime', 'AcctAuthentic', 'ConnectInfo_Start', \ 'ConnectInfo_Stop', 'AcctInputOctets', 'AcctOutputOctets', \ 'CalledStationId', 'CallingStationId', 'AcctTerminateCause', \ 'ServiceType', 'FramedProtocol', 'FramedIPAddress', \ 'AcctStartDelay', 'AcctStopDelay', 'ServiceInfo') \ VALUES \ ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \ '%{SQL-User-Name}', \ '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \ '%{NAS-Port-Type}', \ DATE_SUB('%S', \ INTERVAL (%{%{Acct-Session-Time}:-0} + \ %{%{Acct-Delay-Time}:-0}) SECOND), \ '%S', '%{Acct-Session-Time}', '%{Acct-Authentic}', '', \ '%{Connect-Info}', \ '%{%{Acct-Input-Gigawords}:-0}' " 32 | \ '%{%{Acct-Input-Octets}:-0}', \ '%{%{Acct-Output-Gigawords}:-0}' " 32 | \ '%{%{Acct-Output-Octets}:-0}', \ '%{Called-Station-Id}', '%{Calling-Station-Id}', \ '%{Acct-Terminate-Cause}', \ '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', \ '0', '%{%{Acct-Delay-Time}:-0}', \ SUBSTRING('%{Cisco-Service-Info}', 2))" simul_count_query = "SELECT COUNT(*) \ FROM '${acct_table1}' \ WHERE 'UserName' = '%{SQL-User-Name}' \ AND 'AcctStopTime' IS NULL" simul_verify_query = "SELECT 'RadAcctId', 'AcctSessionId', 'UserName', \ 'NASIPAddress', 'NASPortId', 'FramedIPAddress', \ 'CallingStationId', 'FramedProtocol' \ FROM '${acct_table1}' \ WHERE 'UserName' = '%{SQL-User-Name}' \ AND 'AcctStopTime' IS NULL" postauth_query = "INSERT INTO ${postauth_table} \ ('user', 'pass', 'reply', 'reply_message', 'date') \ VALUES ( \ '%{User-Name}', \ '%{%{User-Password}:-%{Chap-Password}}', \ '%{reply:Packet-Type}', '%{reply:Reply-Message}', NOW())" Хитрые UNION'ы в начале как раз и нужны для "эмуляции" групп. После того, как FreeRADIUS у вас заработает (radtest вам в руки :) ) - пора перейти к настройке Cisco. Часть 2: Cisco 7206 BRAS/SSG Фактически Cisco 7206 с IOS 12.2SR является полнофункциональным BRAS и SSG (Subscriber Service Gateway), на котором мы можем тонко управлять обслуживанием абонентов, используя функции SSG. Настройка функционала BRAS/SSG на Cisco 7206 не так сложна, как может показаться на первый взгляд. Достоинство предлагаемой схемы в том, что она минимизирует нагрузку на CPU Cisco, при использовании максимума удобных функций BRAS/SSG на этой железке. Дабы не быть голословным, скажу, что нагрузка в этой конфигурации почти не зависит от числа абонентов - только от проходящего трафика (PPS). Начнем с общей конфигурации. service password-encryption hostname <доменное имя браса> aaa new-model aaa nas port extended aaa session-id common clock timezone MSK 3 clock summer-time MSK recurring last Sun Mar 3:00 last Sun Oct 3:00 ip subnet-zero ip cef ip multicast-routing no ip domain lookup ip domain name <ваш домен> ip name-server <ваш DNS-сервер, возможно даже не один> ip accounting-threshold 200000 multilink bundle-name authenticated vpdn enable ip classless ip dhcp relay information option ip dhcp relay information policy keep ip dhcp relay information trust-all no ip dhcp use vrf connected Далее вам потребуется настроить основные интерфейсы, роутинг, NTP и прочую мелочь - но это выходит за рамки данной статьи. Опять же - если уж взялись за BRAS/SSG - значит знаете, что делаете. Настраиваем связочку с RADIUS для авторизации абонентов. Сначала атрибуты. radius-server attribute 44 include-in-access-req radius-server attribute 44 extend-with-addr radius-server attribute 6 on-for-login-auth radius-server attribute 8 include-in-access-req radius-server attribute 32 include-in-access-req radius-server attribute 32 include-in-accounting-req radius-server attribute 55 include-in-acct-req radius-server attribute 55 access-request include radius-server attribute 25 access-request include Теперь сервер. radius-server host <IP RADIUS-сервера> \ auth-port <порт авторизации,обычно 1812> \ acct-port <порт аккаунтинга, обычно 1813> \ key <ключ RADIUS-сервера для BRAS> Теперь группу AAA. aaa group server radius MY_RADIUS server <IP RADIUS-сервера> \ auth-port <порт авторизации, обычно 1812> \ acct-port <порт аккаунтинга, обычно 1813> \ ip radius source-interface <интерфейс, который смотрит на RADIUS> Ну и собственно авторизацию. aaa authentication ppp PPPOE group MY_RADIUS aaa accounting network PPPOE start-stop group MY_RADIUS aaa accounting update newinfo periodic 5 Теперь приступаем к определению темплейта для пользователей. interface Virtual-Template1 ip unnumbered <интерфейс, который смотрит в глобальную сеть, не принципиален> no logging event link-status no peer default ip address ppp authentication chap PPPOE ppp authorization PPPOE ppp accounting PPPOE Создаем BRAS-сервис для PPPOE. bba-group pppoe BRAS-PPPOE virtual-template 1 sessions-per-vlan limit 1000 sessions auto cleanup Окей, теперь пришла пора определить наши интерфейсы, где приходит Q-in-Q, для работы с PPPOE. interface <ваш интерфейс.ваш VLAN> encapsulation dot1q <внешний тег> second-dot1q any pppoe enable group BRAS-PPPOE no cdp enable Если очень хочется определить что-то не Q-in-Q-шное для PPPOE, делается это аналогично, только encapsulation меняется. Теперь создадим основной пул адресов для назначения нашим пользователям. Мы будем "использовать" пул 64.64.64.128-64.64.64.250 (адреса взяты "с потолка", у вас адреса клиентов должны быть свои). Назовем наш пул "users". ip local pool users 64.64.64.128 64.64.64.250 Сервисные группы в RADIUS являются "обычными" пользователями с предзаданным на концентраторе доступа паролем. Зададим этот пароль на Cisco. subscriber service password <пароль сервисных групп> Вот и все - наш BRAS готов к приему абонентов (фактически). Теперь необходимо создать конфигурацию, которая позволила бы нам организовать и разграничить доступ абонентов согласно поставленной задаче. Проектируем сервисные группы: Пропускать этап проектирования нельзя - именно на этом этапе могут быть сделаны ошибки, исправление которых займет много времени. Поэтому, прежде чем создавать дальнейшую конфигурацию - давайте сядем, и немного подумаем. Согласно поставленной задаче, наши абоненты могут быть подключены и отключены (виртуально - нет доступа в Internet, но есть доступ к определенной группе серверов). Оптимально для этих целей создать две сервисных группы (причем SSG_OFFLINE должна быть более приоритетна, чем SSG_ONLINE). Для каждой скорости абонента придется городить отдельную сервисную группу, однако это к лучшему. Итак: 1. Набор групп SSG_ONLINE_<скорость>, приоритет 100 2. SSG_OFFLINE, приоритет 50 Поскольку доступ к серверам является по сути независимой сущностью (отдельный список узлов) - для него тоже сделаем отдельную сервисную группу, более приоритетную, чем SSG_OFFLINE. 3. SSG_SERVERS, приоритет 25 У нас есть еще и локальная сеть, для нее понадобится отдельная сервисная группа. Разумно в случае отключения абонента доступа к локальной сети не давать, а то позаводят прокси. 4. SSG_LAN, приоритет 75 Настраиваем списки доступа: Начнем с того, что настроим списки доступа для каждой из наших сервисных групп. Тут легко нарваться на очень хитрое ограничение Cisco - каждый ACL в сервисных группах должен использоваться только один раз. Создаем список доступа для трафика пользователей в онлайне (SSG_ONLINE_*). Он прост - разрешить доступ везде. Не советую использовать здесь более сложных списков, дабы не нагружать железку без надобности - лучше делайте это на внешних интерфейсах. ip access-list extended Service_Any_Online permit ip any any Теперь создаем список доступа для трафика пользователей в оффлайне (SSG_OFFLINE). Он не менее прост. ip access-list extended Service_Any_Offline permit ip any any Создаем списки доступа на вход и выход для трафика локальной сети (SSG_LOCAL). Я напишу здесь 64.64.64.0/24, обозначая абонентскую сеть, и 64.64.65.0/24, обозначая локальную сеть, а также сервис 123.123.123.16/28, некоторый сайт, доступный на скорости локальной сети. Адреса взяты случайно, кроме того, у вас оных может быть больше. ip access-list extended Service_LAN_In remark Clients permit ip 64.64.64.0 0.0.0.255 any remark Local permit ip 64.64.65.0 0.0.0.255 any remark Services permit ip 123.123.123.16 0.0.0.15 any ip access-list extended Service_LAN_Out remark Clients permit ip any 64.64.64.0 0.0.0.255 remark Local permit ip any 64.64.65.0 0.0.0.255 remark Services permit ip any 123.123.123.16 0.0.0.15 Осталась мелочь - создать список доступа для серверов, доступных абонентам в оффлайне. Мы запихаем туда наш DNS - 64.64.65.12, и Web - 64.64.65.111. IP взяты случайно, у вас этот список будет отличаться. ip access-list extended Service_Servers_In remark DNS permit ip host 64.64.65.12 any remark WWW permit ip host 64.64.65.111 any ip access-list extended Service_Servers_Out remark DNS permit ip any host 64.64.65.12 remark WWW permit ip any host 64.64.65.111 Опять же - я не рекомендую делать, допустим, фильтрации по портам, хотя если очень хочется - то можно. Еще один access-list понадобится нам для блокировки доступа оффлайновым пользователям (не для классификации трафика, а именно для блокировки). Он очень простой: ip access-list extended Service_Deny_Any deny ip any any И вот - все access-list'ы созданы, сервисные группы спроектированы, можно перейти к заполнению базы RADIUS корректными параметрами. Часть 3: заполняем базу, начинаем работу Прежде чем сесть пить кофе и смотреть на клиентов, ходящих в Internet и меняющихся свежескачанным Linux'ом в локалке через наш BRAS, нам необходимо завести этих клиентов и сопоставленные сервисные группы в базу RADIUS. Особое внимание заострим на заведении сервисных групп, но и про заведение клиента я тоже в этой расскажу. Эта часть - последняя в статье о настройке связки Cisco BRAS/SSG + RADIUS. Однако она не последняя в цикле статей про Cisco BRAS/SSG. В следующих статьях я расскажу вам, как перенаправлять "проштрафившихся" абонентов на определенный Web-сервер при заходе на любой сайт, а также - как динамически управлять скоростью и включением/отключением абонентов без разрыва их сессии PPPOE. "Ни единого разрыва" - утопия? Ни разу. Немного отвлекшись и забежав вперед, давайте все-таки вернемся к теме этой статьи. В предыдущей части статьй мы спроектировали сервисные группы и ACL, которые будем использовать. Вкратце напомню: 1. Набор групп SSG_ONLINE_<скорость>, приоритет 100 - для каждой скорости абонента 2. SSG_OFFLINE, приоритет 50 - для абонентов, ушедших в оффлайн по причине отрицательного баланса или еще чего 3. SSG_SERVERS, приоритет 25 - для доступа к серверам ушедших в оффлайн абонентов 4. SSG_LAN, приоритет 75 - для доступа к локальным ресурсам на локальной скорости Для SSG_ONLINE мы используем именованный ACL - Service_Any_Online Для SSG_OFFLINE мы используем именованный ACL - Service_Any_Offline Для SSG_LAN мы используем именованные ACL - Service_LAN_In и Service_LAN_Out Для SSG_SERVERS мы используем именованные ACL - Service_Servers_In и Service_Servers_Out В описании заполнения базы мы будем активно пользоваться концепцией пользователей и групп RADIUS. Это очень сильно упрощает конфигурацию. Еще раз напоминаю, что каждая сервисная группа SSG является отдельным пользователем RADIUS. Первым делом подготовим конфигурацию наших сервисных групп в RADIUS. Все сервисные группы должны "отзываться" на один пароль, а значит - самое время завести группу RADIUS для сервисных групп. Заводим. INSERT INTO 'radgroupcheck' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_GROUP', 'Password', '==', '<тот самый пароль, который мы в предыдущей части задали на Cisco для сервисных групп>'); Эта запись говорит нам о том, что у всех пользователей, принадлежащий группе SVC_GROUP, пароль сверяется с заданным нами в этой записи. Теперь определим прочие группы RADIUS для разных сервисных групп SSG. Я предпочел использование концепта групп RADIUS для сервисных групп SSG, чтобы не захламлять таблицу radreply записями сервисных групп. Начнем с групп SVC_ONLINE_* (скоростных групп). У этих групп SSG есть ряд общих параметров, которые мы вынесем в общую группу RADIUS SVC_ONLINE. INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_ONLINE', 'Cisco-AVPair', '+=', 'ip:traffic-class=in access-group name Service_Any_Online priority 100'), (NULL, 'SVC_ONLINE', 'Cisco-AVPair', '+=', 'ip:traffic-class=out access-group name Service_Any_Online priority 100'), (NULL, 'SVC_ONLINE', 'Cisco-AVPair', '+=', 'subscriber:accounting-list=PPPOE'), (NULL, 'SVC_ONLINE', 'Acct-Interim-Interval', ':=', '300'); Что мы видим? А видим то, что мы задали время периодического обновления аккаунтинга, и то, что надо собственно вести аккаунтинг (PPPOE - это название AAA-группы, созданной нами ранее). ip:traffic-class - это параметр, позволяющий идентифицировать трафик, попадающий в данную сервисную группу. Все классы проверяются в порядке приоритета (priority), меньше значение приоритета - раньше проверка. Первая же найденная подходящая сервисная группа используется для определения параметров трафика. Теперь создадим на базе группы SVC_ONLINE сервисные группы для наших абонентов. Предположим, что у нас есть абоненты со скоростью 1024/512 Кбит, и абоненты со скоростью 4096/4096 Кбит (здесь создавайте те варианты, что имеются у вас). INSERT INTO 'radreply' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_ONLINE_1M_512K', 'Cisco-Service-Info', '+=', 'QU;1024000;D;512000'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('SVC_ONLINE_1M_512K', 'SVC_GROUP', 1), ('SVC_ONLINE_1M_512K', 'SVC_ONLINE', 2); INSERT INTO 'radreply' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_ONLINE_4M_4M', 'Cisco-Service-Info', '+=', 'QU;4096000;D;4096000'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('SVC_ONLINE_4M_4M', 'SVC_GROUP', 1), ('SVC_ONLINE_4M_4M', 'SVC_ONLINE', 2); Логика проста - мы заводим по пользователю для каждой сервисной группы SSG, запихиваем его в группы SVC_GROUP и SVC_ONLINE, а после - в radreply добавляем собственный параметр скорости для каждой сервисной группы. Это единственное место, где мы используем radreply для параметров сервисных групп SSG. Если есть особое желание - можно и этот момент переписать на группы RADIUS, в radgroupreply/usergroup, но у меня его в процессе не возникло :) Итого мы создали двух пользователей сервисных групп (две сервисные группы SSG) - SVC_ONLINE_1M_512K и SVC_ONLINE_4M_4M - по одной на каждый набор скоростных параметров пользователей. Обращаю особое внимание на то, что скорость входящего трафика к абоненту задается как UP (U), а исходящего от абонента - как DOWN (D) - мы смотрим на трафик со стороны Cisco. Теперь займемся группой оффлайновых пользователей, а также доступом к локальной сети. INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_OFFLINE', 'Cisco-AVPair', '+=', 'ip:traffic-class=in access-group name Service_Any_Offline priority 50'), (NULL, 'SVC_OFFLINE', 'Cisco-AVPair', '+=', 'ip:traffic-class=out access-group name Service_Any_Offline priority 50'), (NULL, 'SVC_OFFLINE', 'Cisco-AVPair', '+=', 'ip:inacl=Service_Deny_Any'), (NULL, 'SVC_OFFLINE', 'Cisco-AVPair', '+=', 'ip:outacl=Service_Deny_Any'), (NULL, 'SVC_OFFLINE', 'Cisco-Service-Info', '+=', 'QU;10000;D;10000'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('SVC_OFFLINE', 'SVC_GROUP', 1), ('SVC_OFFLINE', 'SVC_OFFLINE', 2); Пилим все на 10 килобит (бессмысленно, все равно все заденаено ip:inacl/ip:outacl, но подстраховываемся). С помощью ip:inacl и ip:outacl блокируем весь проходящий через эту сервисную группу трафик - здесь нам пригождается access-list для блокировки трафика, который мы заблаговременно создали. Не забываем, что сервисная группа SSG - это тоже пользователь в RADIUS, и вешаем на этого "пользователя" наши группы SVC_GROUP и SVC_OFFLINE. INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_LAN', 'Cisco-AVPair', '+=', 'ip:traffic-class=in access-group name Service_LAN_Out priority 75'), (NULL, 'SVC_LAN', 'Cisco-AVPair', '+=', 'ip:traffic-class=out access-group name Service_LAN_In priority 75'), (NULL, 'SVC_LAN', 'Cisco-Service-Info', '+=','QU;50000000;D;50000000'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('SVC_LAN', 'SVC_GROUP', 1), ('SVC_LAN', 'SVC_LAN', 2); Весь локальный трафик пилится на 50 Мбит для каждого абонента. Возможности пилить "на всех" пока что не требовалось, когда потребуется - напишу отдельной статьей, как это делается. Заметьте, что ACL тоже повешены инверсно - опять же, ACL поименованы In/Out с точки зрения абонента (так удобнее воспринимать их наименования), но мы-то смотрим со стороны Cisco. Осталось создать группу доступа к серверам для заблокированных (оффлайновых) пользователей. Это так же просто: INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'SVC_OFFLINE_SERVERS', 'Cisco-AVPair', '+=', 'ip:traffic-class=in access-group name Service_Servers_Out priority 25'), (NULL, 'SVC_OFFLINE_SERVERS', 'Cisco-AVPair', '+=', 'ip:traffic-class=out access-group name Service_Servers_In priority 25'), (NULL, 'SVC_OFFLINE_SERVERS', 'Cisco-Service-Info', '+=', 'QU;1000000;D;1000000'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('SVC_OFFLINE_SERVERS', 'SVC_GROUP', 1), ('SVC_OFFLINE_SERVERS', 'SVC_OFFLINE_SERVERS', 2); В целом аналогично локалке, только ACL другие, и пилим на мегабит - чтобы избежать DOS-атаки на серверы от "обиженных" и "ущемленных" пользователей, вовремя не пополнивших баланс. Вот и все. Теперь все наши параметры сервисных групп готовы. Осталось только развесить сами сервисные группы и несколько прочих параметров по пользователям, для чего необходимо создать несколько RADIUS-групп, которые позволят это делать легко, и не напрягаясь. Первая группа - группа User_ONLINE, для обычных подключенных пользователей. INSERT INTO 'radgroupcheck' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User_ONLINE', 'Auth-Type', ':=', 'Chap'), (NULL, 'User_ONLINE', 'Simultaneous-Use', ':=', '1'); INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User_ONLINE', 'Session-Timeout', ':=', '3456000'), (NULL, 'User_ONLINE', 'Acct-Interim-Interval', ':=', '300'), (NULL, 'User_ONLINE', 'Cisco-Account-Info', '+=', 'ASVC_LAN'); Вешаем на онлайновых пользователей время сессии в 40 дней (больше месяца), время обновления общего аккаунтинга в 300 секунд (5 минут), и сервисную группу локальной сети. Заодно устанавливаем тип авторизации CHAP и запрещаем авторизоваться более 1 раза (правило 1 пользователь = 1 сессия). Скоростные сервисные группы на каждого пользователя надо вешать отдельно, поэтому это оставим на потом, в группу их не включить. Теперь - группа для "проштрафившихся" пользователей, ушедших в оффлайн. INSERT INTO 'radgroupcheck' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User_OFFLINE', 'Auth-Type', ':=', 'Chap'), (NULL, 'User_OFFLINE', 'Simultaneous-Use', ':=', '1'); INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User_OFFLINE', 'Acct-Interim-Interval', ':=', '900'), (NULL, 'User_OFFLINE', 'Cisco-Account-Info', '+=', 'ASVC_OFFLINE'), (NULL, 'User_OFFLINE', 'Cisco-Account-Info', '+=', 'ASVC_OFFLINE_SERVERS'), (NULL, 'User_OFFLINE', 'Session-Timeout', ':=', '604800'); С оффлайновыми юзерами проще - на них вешаем группы оффлайна и оффлайновых серверов, интервал аккаунтинга - побольше - 15 минут, все равно там аккаунтить нечего, ну и более 7 дней так сидеть без разрыва не даем (это уже по вкусу). Опять же - CHAP и ограничение в 1 сессию. Не забываем про то, что адреса пользователям надо выдавать из пула. INSERT INTO 'radgroupreply' ('id', 'GroupName', 'Attribute', 'op', 'Value') VALUES (NULL, 'Pool_USERS', 'Cisco-AVPair', '+=', 'ip:addr-pool=users'), Создаем группу пула адресов для юзеров, мало ли - вдруг надо будет всем разом пул сменить. А пока назначаем всех в созданный нами пул users. Ура! Теперь осталось только завести наших пользователей. Процесс не сложный, но все равно опишем его - есть некоторые тонкости. Кого заводим? Для примера, заведем нескольких пользователей с разными параметрами: Пользователь User1 (пароль Test1): 1024K/512K, онлайн Пользователь User2 (пароль Test2): 4M/4M, оффлайн Пользователь User3 (пароль Test3): 4M/4M, статический IP 64.64.64.111, онлайн Заводим первого юзера. INSERT INTO 'radcheck' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User1', 'User-Password', '==', 'Test1'); INSERT INTO 'radreply' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User1', 'Cisco-Account-Info', '+=', 'ASVC_ONLINE_1M_512K'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('User1', 'User_ONLINE', 1), ('User1', 'Pool_USERS', 1); Обратите внимание - как все просто. Заводим пароль пользователя в radcheck. В radreply вешаем пользователю соответствующую скоростную сервисную группу SSG. В usergroup говорим, что пользователь принадлежит группе User_ONLINE, и берет пул согласно группе Pool_USERS. Вуаля. Он уже может логиниться. Перейдем ко второму, "проштрафившемуся" пользователю. INSERT INTO 'radcheck' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User2', 'User-Password', '==', 'Test2'); INSERT INTO 'radreply' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User2', 'Cisco-Account-Info', '+=', 'ASVC_ONLINE_4M_4M'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('User2', 'User_OFFLINE', 1), ('User2', 'Pool_USERS', 1); Отличия минимальны. Другая скоростная группа (4096/4096), да вместо User_ONLINE ставим User_OFFLINE, указывая на отключение пользователя. Просто? Третий пользователь у нас онлайн, однако ему мы хотим выдать статический IP-адрес 64.64.64.111. Заметьте, что этот адрес не входит в наш пул - выдаваемые IP-адреса не обязаны входить в какие-либо пулы адресов. Заводим. INSERT INTO 'radcheck' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User3', 'User-Password', '==', 'Test3'); INSERT INTO 'radreply' ('id', 'UserName', 'Attribute', 'op', 'Value') VALUES (NULL, 'User3', 'Cisco-Account-Info', '+=', 'ASVC_ONLINE_4M_4M'), (NULL, 'User3', 'Framed-IP-Address', ':=', '64.64.64.111'); INSERT INTO 'usergroup' ('UserName', 'GroupName', 'priority') VALUES ('User3', 'User_ONLINE', 1), Основное отличие в том, что мы не назначаем группу пула адресов в usergroup, а вместо этого - назначаем статический IP в radreply. Не пытайтесь совмещать пул и статический IP для одного пользователя - работать не будет, пользователь не сможет залогиниться - особенность Cisco IOS. Вот и все - наслаждаемся работающим BRAS'ом и простотой его дальнейшей конфигурации под новых пользователей. Можно автоматизировать заведение пользователей, приделать личный кабинет - словом - реализовать все, что есть в ваших планах. Система получилась структурной и понятной интуитивно. Аккаунтинг в этой системе тоже очевиден - взглянув в таблицу RadAcct во время работы пользователей, вы быстро разберетесь, что к чему. Хочу отметить одну особенность (глюк) Cisco IOS - общий аккаунтинг (с ServiceInfo = '') не учитывает дропнутые пакеты, а аккаунтинг по сервисным группам (ServiceInfo = 'SVC_ONLINE_*' в нашем случае) - учитывает. Поэтому трафик "внешний" легко может получаться немножко большим, чем трафик "общий" - будьте осторожны, отображая обе части информации клиенту - разница очень мала (обычно), но она все-таки может быть. На этом хочу завершить данную статью. Надеюсь, она поможет вам создать или оптимизировать собственную систему доступа. Осталось лишь пожелать всем работающим инженерами в провайдерах успехов в их нелегкой деятельности. Ждите обещанных продолжений. Sincerely, Alex/AT.

<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>

Обсуждение [ RSS ]
  • 1.1, Orion55 (?), 06:35, 29/12/2009 [ответить]  
  • +/
    "Как установить FreeRADIUS c MySQL, я описывать не буду - если уж решились взяться за Cisco 7206 и сервисные службы - значит вполне способны справиться с этой простейшей задачей."
    Будь душкой опиши решение этой "простейшей" задачи. Во время установки freeradius из исходников, особенно с настройкой по-умолчанию отключенного шифрования - есть ряд подводных камушков. Будет интересно как ты их обошел.
    Лично у меня "волшебная комбинация" ./configure && make && make install с первого раза с полпинка не заработала.
     
  • 1.2, Alex (??), 10:59, 29/12/2009 [ответить]  
  • +/
    Эм... на крайний случай - есть репозитории, допустим, в CentOS. И ничего компилить не надо. Хотя 2.1 собирается неплохо и в дефолте, главное все зависимости учесть.
     
  • 1.3, Orion55 (?), 06:17, 30/12/2009 [ответить]  
  • +/
    Не все так просто и пушисто, по умолчанию пакет скомпилирован с отключенной сильной криптографией из-за патентных ограничений. И еще морока с сертификатами, корневой юзерский, их подпись и т.д. (Надо генерировать специальные сертификаты для юзеров winXp.) Я собрал freeradius_1.1.7 из исходников - но при сборке есть ряд подводных камушков.
    Официальный сайт freeradius молчит как партизан по этому поводу.
     
  • 1.4, Alex (??), 13:00, 31/12/2009 [ответить]  
  • +/
    Эм... а при чем тут вообще криптография? Зачем она нужна FreeRadius, тем более в связке с PPPoE, притом, что BRAS связан с FR и системой управления через изолированную подсеть?
     
  • 1.5, FValeriy (ok), 13:42, 10/08/2011 [ответить]  
  • +/
    C маршрутизаторами Cisco вообще все не пушисто ) http://www.nstor.ru/ru/catalog/473/2044.html
     
  • 1.6, c_thief (?), 01:10, 23/10/2011 [ответить]  
  • +/
    Спасибо за статейку,достаточно все внятно,но все же вопрос господа,никто не пробовал сабж,только с динамическим применением атрибутов radius'а?
     
     
  • 2.7, AlexAT (ok), 14:05, 23/10/2011 [^] [^^] [^^^] [ответить]  
  • +/
    > Спасибо за статейку,достаточно все внятно,но все же вопрос господа,никто не пробовал сабж,только с динамическим применением атрибутов radius'а?

    Что такое "динамическое применение атрибутов"?


     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру