Dhcp + Radius 3 (Linux)

Матеріал з NoDeny
Перейти до навігації Перейти до пошуку

Выдача ip может быть основана на разных критериях, например:

  • авторизация по мак-адресу клиента (преимущественно используется в неуправляемых сетях)
  • по комбинации мак клиента, мак свича, порт свича
  • по номеру vlan
  • по имени nas, vlan свича, vlan клиента
  • по имени nas, маку и vlan клиента

Вариантов может быть множество, в зависимости от того, что придумает админ. Но суть везде одна: на radius приходят параметры, с которыми подключается клиент, а radius возвращает обычно ip и множество иных параметров.

В данном документе будет описан самый простой вариант: авторизация по мак-адресу клиента. Потом сложнее.

Мы настраиваем Radius так, чтобы он "принимал" любого, в том числе неизвестного, клиента, поскольку неизвестным клиентам будет выдан ip из пула динамических адресов. После чего у клиента появится возможность через личный кабинет зарегистрировать свое подключение и данный мак-адрес перестанет быть неизвестным.

Установка Radius

apt install freeradius-mysql
rm /etc/freeradius/3.0/sites-enabled/default
cp /usr/local/nodeny/etc/raddb/clients.conf /etc/freeradius/3.0/

Конфигурирование

nano /etc/freeradius/3.0/sites-enabled/nodeny

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

server default {
    listen {
        type = auth
        ipaddr = *
        port = 1812
    }
    listen {
        type = acct
        ipaddr = *
        port = 0
    }
    authorize {
        sql
        update control {
          Auth-Type := Accept
        }
    }
    authenticate {
    }
    preacct {
        acct_unique
        preprocess
    }
    accounting {
        sql
    }
    session {
        radutmp
        sql
    }
    post-auth {
        sql
    }
    Post-Auth-Type ACCEPT {
        sql
    }
}

Sql конфиг

В консоли:

nano /etc/freeradius/3.0/mods-enabled/sql

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

sql {
    driver = "rlm_sql_mysql"
    mysql {
        warnings = auto
    }
    server = "localhost"
    port = 3306
    login = "nodeny"
    password = "hardpass"
    radius_db = "nodeny"

    read_groups = no
    authorize_reply_query = "call radreply('%{User-Name}', '%{NAS-IP-Address}')"
    accounting {
        reference = "%{tolower:type.%{Acct-Status-Type}.query}"
        type {
            start {
                query = "call radupdate('%{ERX-Dhcp-Mac-Addr}','%{Framed-IP-Address}',\
                        'nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}')"
            }
            interim-update {
                query = "${..start.query}"
            }
            stop {
                query = "call radstop('%{Framed-IP-Address}', '%{NAS-IP-Address}')"
            }
        }
    }
    post-auth {
        query = "call radupdate('%{ERX-Dhcp-Mac-Addr}','%{reply:Framed-IP-Address}',\
                'nas=%{NAS-IP-Address};ses=%{Acct-Session-Id};first_response=1')"
    }
    pool {
      start = 5
      min = 5
      max = 130
      spare = 30
      uses = 0
      retry_delay = 30
      lifetime = 0
      idle_timeout = 60
    }
}

Mysql процедуры

ALTER DATABASE nodeny CHARACTER SET utf8 COLLATE utf8_general_ci;
DROP PROCEDURE IF EXISTS `radreply`;
DELIMITER $$
CREATE PROCEDURE `radreply`(IN login VARCHAR(64))
BEGIN
    DECLARE usr_mac VARCHAR(12);
    DECLARE usr_ip VARCHAR(15);
    DECLARE usr_id INT;
    SELECT REPLACE(login, ':', '') INTO usr_mac;
    SELECT uid INTO usr_id FROM mac_uid WHERE mac=usr_mac;
    IF usr_id IS NOT NULL AND usr_id>0 THEN
        SELECT get_ip(usr_id) INTO usr_ip;
        UPDATE mac_uid SET ip=0 WHERE ip=INET_ATON(usr_ip) AND uid<>usr_id;
        UPDATE mac_uid SET ip=INET_ATON(usr_ip), time=UNIX_TIMESTAMP() WHERE uid=usr_id;
    ELSE
        START TRANSACTION;
        SELECT INET_NTOA(ip) INTO usr_ip FROM ip_pool
            WHERE uid=0 AND type='dynamic' AND `release` < UNIX_TIMESTAMP()
            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;
        UPDATE ip_pool SET `release` = UNIX_TIMESTAMP() + 3600
            WHERE ip = INET_ATON(usr_ip);
    END IF;
    SELECT NULL, login, 'Framed-IP-Address', usr_ip, '=';
    SELECT NULL, login, 'Session-Timeout', '600', '=';
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS `radupdate`;
DELIMITER $$
CREATE PROCEDURE `radupdate`(
    IN login VARCHAR(64), IN ipa VARCHAR(16), IN properties VARCHAR(255))
BEGIN
    DECLARE usr_mac VARCHAR(16);
    SELECT REPLACE(login, ':', '') INTO usr_mac;
    CALL set_auth(ipa, CONCAT('mod=dhcp;user=', usr_mac, ';', REPLACE(properties,';','')));
    UPDATE mac_uid SET time=UNIX_TIMESTAMP() WHERE ip=INET_ATON(ipa) LIMIT 1;
END$$
DELIMITER ;

Проверим:

CALL radreply('00:11:22:33:44:55');
Если получаем ошибку:
  • 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 '=' - выполним:
ALTER DATABASE nodeny CHARACTER SET utf8 COLLATE utf8_general_ci;

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

Запуск

freeradius -X


ipv6 + Radius 3 Development