Pppoe: відмінності між версіями

Матеріал з NoDeny
Перейти до навігації Перейти до пошуку
Немає опису редагування
Немає опису редагування
 
(Не показано 10 проміжних версій цього користувача)
Рядок 1: Рядок 1:
<h2>Pppoe на mikrotik</h2>
<h2>PPPoE на Mikrotik</h2>


На сервере NoDeny создадим пул ip адресов в количестве раз в 5-10 большим чем предполагаемое количество абонентов. Тип ip обязательно должен быть "динамический".
Возможна работа как со статическими (когда ip прописан явно в учетке абонента и никогда не меняется), так и с динамическими ip. Во втором случае в админке NoDeny создадим пул ip адресов в количестве раз в 5-10 большим чем предполагаемое количество абонентов. Тип ip - "динамический".


[[Файл:Mikrotik_radius.gif]]
[[Файл:Mikrotik_radius.gif]]
Рядок 62: Рядок 62:
</pre>
</pre>


<source lang="bash">
ee /usr/local/etc/raddb/sql.conf
</source>
Изменим postauth_query и accounting_update_query:
<pre>
        postauth_query = "call radupdate('%{User-Name}','%{reply:Framed-IP-Address}',\
                'nas=%{NAS-IP-Address}')"
        accounting_update_query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\
                'nas=%{NAS-IP-Address}')"}
</pre>
===Mysql процедуры===
===Mysql процедуры===


Рядок 85: Рядок 73:
CREATE PROCEDURE `radcheck` (IN login VARCHAR(64))
CREATE PROCEDURE `radcheck` (IN login VARCHAR(64))
BEGIN
BEGIN
   SELECT Null, login, 'Cleartext-Password' AS Attribute, '' AS Value,':=';
   SELECT id,name,'Password' AS Attribute,AES_DECRYPT(passwd,'hardpass') AS Value,'=='
    FROM users WHERE name=login;
END$$
END$$
DELIMITER ;
DELIMITER ;
Рядок 95: Рядок 84:
CREATE PROCEDURE `radreply`(IN login VARCHAR(64))
CREATE PROCEDURE `radreply`(IN login VARCHAR(64))
BEGIN
BEGIN
    DECLARE usr_mac VARCHAR(12);
  DECLARE usr_id INT;
    DECLARE usr_ip VARCHAR(15);
  DECLARE usr_ip VARCHAR(15) DEFAULT NULL;
    DECLARE usr_id INT;
 
    SELECT REPLACE(login, ':', '') INTO usr_mac;
  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
    SELECT uid INTO usr_id FROM mac_uid WHERE mac=usr_mac;
  SELECT get_ip(usr_id) INTO usr_ip;
    IF usr_id IS NOT NULL AND usr_id>0 THEN
 
        SELECT get_ip(usr_id) INTO usr_ip;
  SELECT NULL,login,'Framed-IP-Address',usr_ip,'=';
        UPDATE mac_uid SET ip=0 WHERE ip=INET_ATON(usr_ip) AND uid<>usr_id;
  SELECT NULL,login,'Framed-IP-Netmask','255.255.255.255','=';
        UPDATE mac_uid SET ip=INET_ATON(usr_ip), time=UNIX_TIMESTAMP() WHERE uid=usr_id;
  SELECT NULL,login,'Framed-Protocol','PPP','=';
    ELSE
        UPDATE mac_uid SET ip=0 WHERE uid=0 AND time<(UNIX_TIMESTAMP()-3600);
        START TRANSACTION;
        SELECT INET_NTOA(ip) INTO usr_ip FROM ip_pool p WHERE uid=0 AND type='dynamic'
            AND NOT EXISTS (SELECT ip FROM mac_uid WHERE ip=p.ip)
            ORDER BY RAND() LIMIT 1 FOR UPDATE;
        INSERT INTO mac_uid VALUES(
            NULL, usr_mac, INET_ATON(usr_ip), 0, UNIX_TIMESTAMP(), 0, 0, 0)
        ON DUPLICATE KEY
            UPDATE ip=IF(ip>0,ip,INET_ATON(usr_ip)), time=UNIX_TIMESTAMP();
        COMMIT;
        SELECT INET_NTOA(ip) INTO usr_ip FROM mac_uid WHERE mac=usr_mac;
    END IF;
    SELECT NULL, login, 'Framed-IP-Address', usr_ip, '=';
    SELECT NULL, login, 'Session-Timeout', '600', '=';
END$$
END$$
DELIMITER ;
DELIMITER ;
Рядок 126: Рядок 100:
DROP PROCEDURE IF EXISTS `radupdate`;
DROP PROCEDURE IF EXISTS `radupdate`;
DELIMITER $$
DELIMITER $$
CREATE PROCEDURE `radupdate`(
CREATE PROCEDURE `radupdate`(IN login VARCHAR(64), IN ip VARCHAR(16), IN properties VARCHAR(255))
    IN login VARCHAR(64), IN ipa VARCHAR(16), IN properties VARCHAR(255))
BEGIN
BEGIN
    DECLARE usr_mac VARCHAR(16);
  DECLARE usr_id INT;
    SELECT REPLACE(login, ':', '') INTO usr_mac;
  DECLARE usr_ip VARCHAR(15) DEFAULT NULL;
    CALL set_auth(ipa, CONCAT('mod=dhcp;user=', usr_mac, ';', REPLACE(properties,':','')));
  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
    UPDATE mac_uid SET time=UNIX_TIMESTAMP() WHERE ip=INET_ATON(ipa) LIMIT 1;
  SELECT get_ip(usr_id) INTO usr_ip;
  CALL set_auth(usr_ip, CONCAT('mod=pppoe;',REPLACE(properties,':','')));
END$$
DELIMITER ;
</pre>
 
<pre>
DROP PROCEDURE IF EXISTS `radstop`;
DELIMITER $$
CREATE PROCEDURE `radstop`(IN login VARCHAR(64))
BEGIN
  DECLARE usr_id INT;
  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
  DELETE FROM auth_now WHERE ip = get_ip(usr_id) LIMIT 1;
END$$
END$$
DELIMITER ;
DELIMITER ;
Рядок 140: Рядок 126:


<pre>
<pre>
CALL radreply('00:11:22:33:44:55');
CALL radreply('test');
</pre>
</pre>


Если получаем ошибку:
Где test - это логин существующего абонента. В ответе должны получить ip, который привязан к абоненту, либо, если ни один ip не привязан - будет выдан свободный из пула ip биллинга. Если получаем ошибку:


* ''ERROR 1146 (42S02): Table 'nodeny.mac_uid' doesn't exist'' - не установлен модуль dhcp
* ''ERROR 1048 (23000): Column 'ip' cannot be null'' - забыли создать пул ip адресов типа "динамический"
* ''ERROR 1267 (HY000): Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '=''' - выполним:
* ''ERROR 1267 (HY000): Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '=''' - выполним:
<pre>
<pre>
Рядок 162: Рядок 146:


<source lang='bash'>
<source lang='bash'>
radtest 00:11:22:33:44:55 '' 127.0.0.1 0 hardpass5
radtest login pass 127.0.0.1 0 hardpass5
</source>
</source>


Если получаем ошибку ''radclient:: Failed to find IP address for имя_нашего_сервера'' - в /etc/hosts не прописано имя нашего сервера.
где login и test соответственно логин и пароль реально существующей клиентской записи в NoDeny. Если получаем ошибку ''radclient:: Failed to find IP address for имя_нашего_сервера'' - в /etc/hosts не прописано имя нашего сервера.


Должны получить примерно такой ответ:
Должны получить примерно такой ответ:


<pre>
<pre>
rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=63, length=38
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=138, length=38
Framed-IP-Address = 10.0.4.175
Framed-IP-Address = 10.0.0.10
Session-Timeout = 600
Framed-IP-Netmask = 255.255.255.255
Acct-Interim-Interval = 60
Framed-Protocol = PPP
</pre>
</pre>


Рядок 191: Рядок 175:
Добавляем:
Добавляем:
<pre>
<pre>
client 10.1.0.11 {
client 1.1.1.1 {
         secret      = hardpass5
         secret      = hardpass5
         shortname  = Mikrotik
         shortname  = Mikrotik
Рядок 198: Рядок 182:
</pre>
</pre>


Здесь  1.1.1.1 - ip Микротика (тот ip, который смотрит на сервер NoDeny - смотрите схему выше)


<pre>
<pre>
Рядок 206: Рядок 191:
interface pppoe-server server add interface=ether1 service-name=pppoe-in authentication=chap
interface pppoe-server server add interface=ether1 service-name=pppoe-in authentication=chap
ip firewall nat add chain=srcnat action=src-nat to-addresses=2.2.2.2
ip firewall nat add chain=srcnat action=src-nat to-addresses=2.2.2.2
</pre>
==PPPoE с привязкой к мак==
<source lang='bash'>
ee /usr/local/etc/raddb/sql.conf
</source>
В конце файла находим строку ''authorize_check_query = ...'' и меняем ее на:
<pre>
authorize_check_query = "call radcheck('%{User-Name}', '%{Calling-Station-Id}')"
</pre>
Здесь мы добавили в процедуру radcheck параметр ''Calling-Station-Id'' - в этом параметре mikrotik передает мак абонента. Когда клиент пытается сконнектиться, radius запускает процедуру radcheck и передает ей логин и мак. В случае если логин существует в базе данных и к нему подвязан точно такой же мак - процедура должна вернуть radius-у пароль абонента. Радиус сверяет пароль полученный от клиента с его реальным и при совпадении создает pppoe-сессию. В случае, если мак иной - процедура ничего не должна возвращать, в этом случае radius будет считать, что такого логина не существует.
В mysql меняем процедуру radcheck:
<pre>
DROP PROCEDURE IF EXISTS `radcheck`;
DELIMITER $$
CREATE PROCEDURE `radcheck` (IN login VARCHAR(64), IN usr_mac VARCHAR(64))
BEGIN
  DECLARE usr_id INT;
  DECLARE usr_pass VARCHAR(64) DEFAULT NULL;
  SELECT LOWER(REPLACE(usr_mac, ':', '')) INTO usr_mac;
  SELECT id, AES_DECRYPT(passwd,'hardpass') INTO usr_id, usr_pass
    FROM users WHERE name=login;
  IF usr_id IS NOT NULL AND
    (SELECT 1 FROM mac_uid WHERE uid=usr_id AND mac=usr_mac)
  THEN
    SELECT usr_id, login, 'Password' AS Attribute, usr_pass AS Value, '==';
  END IF;
END$$
DELIMITER ;
</pre>
Проверим работоспособность:
<pre>
call radcheck('11', '00:11:22:33:44:55');
</pre>
Должны получить:
<pre>
+--------+-------+-----------+------------+----+
| usr_id | login | Attribute | Value      | == |
+--------+-------+-----------+------------+----+
|      1 | 11    | Password  | 2234157631 | == |
+--------+-------+-----------+------------+----+
</pre>
Здесь: 11 - логин абонента, 00:11:22:33:44:55 - мак адрес, 2234157631 - пароль
Проверим ситуацию, когда абонент сменил мак адрес
<pre>
call radcheck('11', '00:11:11:11:11:11');
</pre>
В ответ должны получить 0 строк.
Запускаем radius с выводом данных на консоль:
<source lang='bash'>
/usr/local/etc/rc.d/radiusd stop
radiusd -X
</source>
Пытаемся подсоединиться по pppoe и в консоли должны увидеть следующее:
<pre>
...
...
[sql]  expand: call radcheck('%{User-Name}', '%{Calling-Station-Id}') -> call radcheck('11', '00:11:22:33:44:55')
...
</pre>
</pre>

Поточна версія на 09:02, 21 квітня 2017

PPPoE на Mikrotik

Возможна работа как со статическими (когда ip прописан явно в учетке абонента и никогда не меняется), так и с динамическими ip. Во втором случае в админке NoDeny создадим пул ip адресов в количестве раз в 5-10 большим чем предполагаемое количество абонентов. Тип ip - "динамический".

Установка Radius

Поскольку понадобится radius с модулем mysql, установим его не из бинарных пакетов (pkg install freeradius), а из портов:

cd /usr/ports/net/freeradius2 && make install clean

Обязательно поставим галку напротив опции MYSQL

rm /usr/local/etc/raddb/sites-enabled/default 
ee /usr/local/etc/raddb/sites-enabled/nodeny

Вставляем следующий текст:

authorize {
        sql
}
authenticate {
        Auth-Type PAP {
                pap
        }
}
preacct {
        acct_unique
        preprocess
}
accounting {
        detail
        sql
        exec
}
session {
        radutmp
        sql
}
post-auth {
        sql
}


cp /usr/local/nodeny/etc/raddb/* /usr/local/etc/raddb/
echo radiusd_enable=YES >> /etc/rc.conf
ee /usr/local/etc/raddb/radiusd.conf

Раскомментируем строку (найти проще всего так: ctrl+y, затем текст "sql.conf", затем enter):

$INCLUDE sql.conf

Mysql процедуры

ALTER DATABASE nodeny CHARACTER SET utf8 COLLATE utf8_general_ci;
DROP PROCEDURE IF EXISTS `radcheck`;
DELIMITER $$
CREATE PROCEDURE `radcheck` (IN login VARCHAR(64))
BEGIN
  SELECT id,name,'Password' AS Attribute,AES_DECRYPT(passwd,'hardpass') AS Value,'=='
    FROM users WHERE name=login;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS `radreply`;
DELIMITER $$
CREATE PROCEDURE `radreply`(IN login VARCHAR(64))
BEGIN
  DECLARE usr_id INT;
  DECLARE usr_ip VARCHAR(15) DEFAULT NULL;

  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
  SELECT get_ip(usr_id) INTO usr_ip;

  SELECT NULL,login,'Framed-IP-Address',usr_ip,'=';
  SELECT NULL,login,'Framed-IP-Netmask','255.255.255.255','=';
  SELECT NULL,login,'Framed-Protocol','PPP','=';
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS `radupdate`;
DELIMITER $$
CREATE PROCEDURE `radupdate`(IN login VARCHAR(64), IN ip VARCHAR(16), IN properties VARCHAR(255))
BEGIN
  DECLARE usr_id INT;
  DECLARE usr_ip VARCHAR(15) DEFAULT NULL;
  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
  SELECT get_ip(usr_id) INTO usr_ip;
  CALL set_auth(usr_ip, CONCAT('mod=pppoe;',REPLACE(properties,':','')));
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS `radstop`;
DELIMITER $$
CREATE PROCEDURE `radstop`(IN login VARCHAR(64))
BEGIN
  DECLARE usr_id INT;
  SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
  DELETE FROM auth_now WHERE ip = get_ip(usr_id) LIMIT 1;
END$$
DELIMITER ;

Проверим:

CALL radreply('test');

Где test - это логин существующего абонента. В ответе должны получить ip, который привязан к абоненту, либо, если ни один ip не привязан - будет выдан свободный из пула ip биллинга. Если получаем ошибку:

  • ERROR 1267 (HY000): Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation '=' - выполним:
ALTER DATABASE nodeny CHARACTER SET utf8 COLLATE utf8_general_ci;

и пересоздаем процедуры

Запускам Radius

/usr/local/etc/rc.d/radiusd start

Проверяем:

radtest login pass 127.0.0.1 0 hardpass5

где login и test соответственно логин и пароль реально существующей клиентской записи в NoDeny. Если получаем ошибку radclient:: Failed to find IP address for имя_нашего_сервера - в /etc/hosts не прописано имя нашего сервера.

Должны получить примерно такой ответ:

rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=138, length=38
	Framed-IP-Address = 10.0.0.10
	Framed-IP-Netmask = 255.255.255.255
	Framed-Protocol = PPP

В ином случае тушим radius и запускаем в режиме детального вывода:

/usr/local/etc/rc.d/radiusd stop
radiusd -X

Продолжаем настройку. Добавим микротик (10.1.0.11) в настройки радиуса:

ee /usr/local/etc/raddb/clients.conf

Добавляем:

client 1.1.1.1 {
        secret      = hardpass5
        shortname   = Mikrotik
        nastype     = cisco
}

Здесь 1.1.1.1 - ip Микротика (тот ip, который смотрит на сервер NoDeny - смотрите схему выше)

radius add address=1.1.1.2 secret=hardpass5 service=ppp
radius incoming set accept=yes
ppp aaa set accounting=yes use-radius=yes interim-update=50
ppp profile set default local-address=2.2.2.2 dns-server=2.2.2.2
interface pppoe-server server add interface=ether1 service-name=pppoe-in authentication=chap
ip firewall nat add chain=srcnat action=src-nat to-addresses=2.2.2.2

PPPoE с привязкой к мак

ee /usr/local/etc/raddb/sql.conf

В конце файла находим строку authorize_check_query = ... и меняем ее на:

authorize_check_query = "call radcheck('%{User-Name}', '%{Calling-Station-Id}')"

Здесь мы добавили в процедуру radcheck параметр Calling-Station-Id - в этом параметре mikrotik передает мак абонента. Когда клиент пытается сконнектиться, radius запускает процедуру radcheck и передает ей логин и мак. В случае если логин существует в базе данных и к нему подвязан точно такой же мак - процедура должна вернуть radius-у пароль абонента. Радиус сверяет пароль полученный от клиента с его реальным и при совпадении создает pppoe-сессию. В случае, если мак иной - процедура ничего не должна возвращать, в этом случае radius будет считать, что такого логина не существует.

В mysql меняем процедуру radcheck:

DROP PROCEDURE IF EXISTS `radcheck`;
DELIMITER $$
CREATE PROCEDURE `radcheck` (IN login VARCHAR(64), IN usr_mac VARCHAR(64))
BEGIN
  DECLARE usr_id INT;
  DECLARE usr_pass VARCHAR(64) DEFAULT NULL;
  SELECT LOWER(REPLACE(usr_mac, ':', '')) INTO usr_mac;
  SELECT id, AES_DECRYPT(passwd,'hardpass') INTO usr_id, usr_pass
    FROM users WHERE name=login;
  IF usr_id IS NOT NULL AND
    (SELECT 1 FROM mac_uid WHERE uid=usr_id AND mac=usr_mac)
  THEN
    SELECT usr_id, login, 'Password' AS Attribute, usr_pass AS Value, '==';
  END IF;
END$$
DELIMITER ;

Проверим работоспособность:

call radcheck('11', '00:11:22:33:44:55');

Должны получить:

+--------+-------+-----------+------------+----+
| usr_id | login | Attribute | Value      | == |
+--------+-------+-----------+------------+----+
|      1 | 11    | Password  | 2234157631 | == |
+--------+-------+-----------+------------+----+

Здесь: 11 - логин абонента, 00:11:22:33:44:55 - мак адрес, 2234157631 - пароль

Проверим ситуацию, когда абонент сменил мак адрес

call radcheck('11', '00:11:11:11:11:11');

В ответ должны получить 0 строк.

Запускаем radius с выводом данных на консоль:

/usr/local/etc/rc.d/radiusd stop
radiusd -X

Пытаемся подсоединиться по pppoe и в консоли должны увидеть следующее:

...
...
[sql]   expand: call radcheck('%{User-Name}', '%{Calling-Station-Id}') -> call radcheck('11', '00:11:22:33:44:55')
...