DHCP MYSQL

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску

Конфиг для DHCP средсвами MYSQL

Есть желание уйти от всяких скриптов (php, bash, perl) для получения конфига из MySQL для dhcpd а так же с помошью представлений отказаться от привязки к конкретным таблицам. Заодно проверить какое из решений будет работать быстрее.
Это только черновик пока и я еще не использую это решение в продакшене
TODO

  • Проверить что бы использовалась только таблица mtraf_status

Создание представдения

Для того что бы не быть привязаным к структуре базы (которую программист биллинга вообще-то может менять по своему усмотрению) все данные для dhcp буду получать из view. Стараюсь хранить данные в виде их "физических сущностей" - а именно IP - как INT UNSIGNED. В некоторых случаях приходиться брать данные "как есть" и преобразовывать.

DROP view  mtraf_status;
CREATE VIEW
    mtraf_status
AS
    SELECT
        domain AS domain,
        IF( 0n_a<0 OR ( 0n_a=0 AND debt=0 )  ,0,1) AS status,
        ip AS ip,
        mac AS mac,
        IF( 0n_a<0 OR ( 0n_a=0 AND debt=0), inet_ntoa(inet_aton(ip)+6553600),ip) AS ip_dhcp,
        lower(substr(replace(concat(':', mac), ':0', ':') from 2)) AS  mac_dhcp
FROM
    mtraf;

Условие в IF - условие когда абонент "должен" - ему нужно дать другой IP (у меня вместо, например, 10.0.136.10 он получит 10,100,136,10) и соответвенно, пускать только на биллинг (если короко, то файрволл не пускает абонентов никуда кроме отдельного ДНСа (или отдельного view) который на все запросы отвечает адресом странички "дай денег, дорогой абонент" и собственно биллинга) Всем кто будет напоминать про dhcp snooping, opt 82 и прочее - это все делается для остатоков неуправляемых сегментов.

Дополнительные данные о сети

В биллинге (в моем случае) нет никакой информации о топологии сети). Нужно добавить данные о сетях, релеях, гейтвеях. Отмечу, что в сети есть как минимум 2 релея (т.к. сети 10.0... и 10.100... - алиасы ) и запрос прийти может через любой из них. В общем случае релеев может быть сколько угодно - по числу алиасов на интерфейсе.

DROP TABLE network_relay;
CREATE TABLE network_relay
(
    network int(64) UNSIGNED,
    relay int(64) UNSIGNED
);

INSERT into network_relay values(INET_ATON('10.0.135.0'), INET_ATON('10.0.135.1'));
INSERT into network_relay values(INET_ATON('10.0.135.0'), INET_ATON('10.0.135.254'));
INSERT into network_relay values(INET_ATON('10.0.135.0'), INET_ATON('10.100.135.1'));
INSERT into network_relay values(INET_ATON('10.0.135.0'), INET_ATON('10.100.135.254'));

INSERT into network_relay values(INET_ATON('10.0.136.0'), INET_ATON('10.0.136.1'));
INSERT into network_relay values(INET_ATON('10.0.136.0'), INET_ATON('10.0.136.254'));
INSERT into network_relay values(INET_ATON('10.0.136.0'), INET_ATON('10.100.136.1'));
INSERT into network_relay values(INET_ATON('10.0.136.0'), INET_ATON('10.100.136.254'));

INSERT into network_relay values(INET_ATON('10.0.137.0'), INET_ATON('10.0.137.1'));
INSERT into network_relay values(INET_ATON('10.0.137.0'), INET_ATON('10.0.137.254'));
INSERT into network_relay values(INET_ATON('10.0.137.0'), INET_ATON('10.100.137.1'));
INSERT into network_relay values(INET_ATON('10.0.137.0'), INET_ATON('10.100.137.254'));


DROP TABLE network_mask;
CREATE TABLE network_mask
(
    network int  UNSIGNED  NOT NULL UNIQUE,
    mask int  UNSIGNED,
    is_dhcp int DEFAULT 1
);

INSERT into network_mask(network,mask) values(INET_ATON('10.0.135.0'), INET_ATON('255.255.255.0'));
INSERT into network_mask(network,mask) values(INET_ATON('10.0.136.0'), INET_ATON('255.255.255.0'));
INSERT into network_mask(network,mask) values(INET_ATON('10.0.137.0'), INET_ATON('255.255.255.0'));


DROP TABLE network_gateway;
CREATE TABLE network_gateway
(
    network int UNSIGNED,
    gateway int  UNSIGNED
);

INSERT into network_gateway values(INET_ATON('10.0.135.0'), INET_ATON('10.0.135.254'));
INSERT into network_gateway values(INET_ATON('10.0.136.0'), INET_ATON('10.0.136.254'));
INSERT into network_gateway values(INET_ATON('10.0.137.0'), INET_ATON('10.0.137.254'));

INSERT into network_gateway values(INET_ATON('10.100.135.0'), INET_ATON('10.100.135.254'));
INSERT into network_gateway values(INET_ATON('10.100.136.0'), INET_ATON('10.100.136.254'));
INSERT into network_gateway values(INET_ATON('10.100.137.0'), INET_ATON('10.100.137.254'));


Процедуры и функции

Решил максимально разбить задачу на отдельные атомарные функции, MySQL к это теперь позволяет

Получение маски для IP

Зная IP получаем маску сети (которая в общем случае может отличаться от "255.255.255.0". Возвращаю первое вхождение.

DROP FUNCTION GetMaskForIP;
delimiter //
CREATE FUNCTION GetMaskForIP(ip1 int(64) UNSIGNED)  RETURNS INT UNSIGNED
BEGIN
    DECLARE mask1 INT UNSIGNED;
    SELECT mask  from network_mask WHERE ip1&mask=network LIMIT 1 INTO mask1;
    RETURN mask1;
END
//
delimiter ;

Пример:

mysql> SELECT INET_NTOA(GetMaskForIP(INET_ATON('10.0.136.12')));
+---------------------------------------------------+
| INET_NTOA(GetMaskForIP(INET_ATON('10.0.136.12'))) |
+---------------------------------------------------+
| 255.255.255.0                                     |
+---------------------------------------------------+
1 row in set (0.01 sec)

Аналогично для "неплатильщиков"

DROP FUNCTION GetMaskForNoPayIP;
delimiter //
CREATE FUNCTION GetMaskForNoPayIP(ip1 int(64) UNSIGNED)  RETURNS INT UNSIGNED
BEGIN
    DECLARE mask1 INT UNSIGNED;
    SELECT mask  from network_mask WHERE (ip1-6553600)&mask=network limit 1 INTO mask1;
    RETURN mask1;
END
//
delimiter ;

Получение списка relay для сети

В сети запрос может прийти от одного или нескольких возможных relay-агентов. Для каждой сети - определен список этих relay. Задача - сгенерировать часть конфига вида "запрос пришел через релей1 ИЛИ запрос пришел через релей2 ИЛИ ..."

DROP FUNCTION GetRelayForNet;
delimiter //
CREATE FUNCTION GetRelayForNet(n1 int UNSIGNED) RETURNS MEDIUMTEXT
BEGIN
-- done is "end of cycle" variable
    DECLARE done INT DEFAULT 0;
    DECLARE current_relay MEDIUMTEXT default "";
    DECLARE dhcp_relay MEDIUMTEXT;
    DECLARE dhcp_relay_res MEDIUMTEXT default "";
-- set done=1 when cusror ends
-- cursor for relay
    DECLARE cursor_relay CURSOR FOR  SELECT  relay from network_relay  WHERE network=n1 LIMIT 1,18446744073709551615;
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
    OPEN cursor_relay;
    SELECT INET_NTOA(relay) INTO dhcp_relay FROM network_relay WHERE network=n1 LIMIT 1;
    SELECT CONCAT("(  ( binary-to-ascii(10, 8, \".\", packet(24, 4))=\"", dhcp_relay, "\" ) ") INTO dhcp_relay_res;
    FETCH cursor_relay INTO current_relay;
    WHILE done = 0 DO
        SELECT INET_NTOA(relay) INTO dhcp_relay FROM network_relay WHERE relay = current_relay LIMIT 1;
        SELECT CONCAT(dhcp_relay_res, " or (binary-to-ascii(10, 8, \".\", packet(24, 4))=\"", dhcp_relay,"\")") INTO dhcp_relay_res;
        FETCH  cursor_relay INTO current_relay;
    END WHILE;
    CLOSE cursor_relay;
    RETURN CONCAT(dhcp_relay_res, ")");
END
//
delimiter ;

Пример:

SELECT  GetRelayForNet(INET_ATON('10.0.136.0'));
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| GetRelayForNet(INET_ATON('10.0.136.0'))                                                                                                                                                                                                                         |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (  ( binary-to-ascii(10, 8, ".", packet(24, 4))="10.0.136.1" )  or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.0.136.254") or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.100.136.1") or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.100.136.254")) |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

class для IP

Для простоты разделелил генерацию класса на несколько частей
Эта функция возващает заготовку класса (match mac-address) для определенного IP.

DROP FUNCTION GetClassForIP;
delimiter //
CREATE FUNCTION GetClassForIP(ip1 int UNSIGNED) RETURNS char(255)
BEGIN
    DECLARE mac_dhcp1 char(255) DEFAULT "";
    DECLARE ip_d char(255) DEFAULT "";
    SELECT ip_dhcp  INTO  ip_d FROM mtraf_status WHERE ip=INET_NTOA(ip1);
    SELECT mac_dhcp INTO mac_dhcp1 FROM mtraf_status WHERE mtraf_status.ip=ip_d LIMIT 1;
    RETURN  CONCAT("class \"",ip_d,"__",mac_dhcp1,"\" {  match if ( ( binary-to-ascii(16,  8, \":\", substring(hardware,1, 6)) = \"",mac_dhcp1,"\") and");
END
//
delimiter ;

Пример

mysql> SELECT GetClassForIP(INET_ATON('10.0.136.11'));
+------------------------------------------------------------------------------------------------------------------------------------+
| GetClassForIP(INET_ATON('10.0.136.11'))                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------+
| class "10.0.136.11__0:13:d4:5:d9:f4" {  match if(  ( binary-to-ascii(16,  8, ":", substring(hardware,1, 6)) = "0:13:d4:5:d9:f4 and |
+------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.10 sec)

Генерация полноценного класса

Собираем полноценный класс из частей.

DROP FUNCTION GetFullClassForIP;
delimiter //
CREATE FUNCTION GetFullClassForIP(ip1 int UNSIGNED) RETURNS TEXT
BEGIN
    RETURN  CONCAT( GetClassForIP(ip1), " " ,  GetRelayForNet(GetNetForIP(ip1)) ,"}\n" ) ;
END
//
delimiter ;

Пример (читать так: Классу соответвует запрос с маком $mac прошедьший через $relay[1] или $relay[2] или ... или relay[N] ). В такой конфигурации мак должен быть уникален в пределах сегмента а не в пределах всей сети:

mysql> SELECT GetFullClassForIP(INET_ATON('10.0.136.11'));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| GetFullClassForIP(INET_ATON('10.0.136.11'))                                                                                                                                                                                                                                                                                                                                                          |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| class "10.0.136.11__0:13:d4:5:d9:f4" {  match if(  ( binary-to-ascii(16,  8, ":", substring(hardware,1, 6)) = "0:13:d4:5:d9:f4 and (  ( binary-to-ascii(10, 8, ".", packet(24, 4))="10.0.136.1" )  or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.0.136.254") or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.100.136.1") or (binary-to-ascii(10, 8, ".", packet(24, 4))="10.100.136.254"))}
 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.08 sec)

Определить какой сети принадлежит IP

DROP FUNCTION GetNetForIP;
delimiter //
CREATE FUNCTION GetNetForIP(ip1 int UNSIGNED) RETURNS int UNSIGNED
BEGIN
    DECLARE net1 INT  UNSIGNED;
    SELECT network INTO net1 FROM network_mask  WHERE ip1&mask=network LIMIT 1;
    RETURN net1;

END
//
delimiter ;

Пример:

mysql> SELECT INET_NTOA(GetNetForIP(INET_ATON('10.0.136.11')));
+--------------------------------------------------+
| INET_NTOA(GetNetForIP(INET_ATON('10.0.136.11'))) |
+--------------------------------------------------+
| 10.0.136.0                                       |
+--------------------------------------------------+
1 row in set (0.00 sec)

создание пула для IP

DROP FUNCTION GetPoolForIP;
delimiter //
CREATE FUNCTION GetPoolForIP(ip1 int UNSIGNED) RETURNS MEDIUMTEXT
BEGIN
    DECLARE mac_dhcp1 VARCHAR(255);
    SELECT  mac_dhcp INTO mac_dhcp1 FROM mtraf_status WHERE INET_ATON(mtraf_status.ip)=ip1 LIMIT 1;
    RETURN   CONCAT(
            "pool { range ",
            INET_NTOA(ip1),
            "; allow members of \"",
            INET_NTOA(ip1),
            "__",
            mac_dhcp1,
            "\"; default-lease-time 36000; max-lease-time 72000; } "
            );
END
//
delimiter ;

создание пула для ip неплатильщика

DROP FUNCTION GetPoolForNoPayIP;
delimiter //
CREATE FUNCTION GetPoolForNoPayIP(ip1 int UNSIGNED) RETURNS MEDIUMTEXT
BEGIN
    DECLARE ip_dhcp1 VARCHAR(32) DEFAULT "";
    DECLARE mac_dhcp1 VARCHAR(255) DEFAULT "";
    SELECT INET_NTOA(ip1) INTO ip_dhcp1;
    SELECT  mac_dhcp INTO mac_dhcp1 FROM mtraf_status WHERE INET_ATON(mtraf_status.ip)=ip1-6553600 LIMIT 1;
    RETURN CONCAT(
            "pool { range ",
            ip_dhcp1,
            "; allow members of \"",
            ip_dhcp1,
            "__",
            mac_dhcp1,
            "\"; default-lease-time 36000; max-lease-time 72000; } "
        );
END
//
delimiter ;
SELECT GetPoolForNoPayIP(INET_ATON('10.100.136.84'));

Пример:

mysql> SELECT GetPoolForNoPayIP(INET_ATON('10.100.136.84'));
+---------------------------------------------------------------------------------------------------------------------------------+
| GetPoolForNoPayIP(INET_ATON('10.100.136.84'))                                                                                   |
+---------------------------------------------------------------------------------------------------------------------------------+
| pool { range 10.100.136.84; allow members of 10.100.136.84__0:1d:92:58:27:cf default-lease-time 36000; max-lease-time 72000; }  |
+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)


Полные пулы для тех кто платит и тех кто нет (из одного сегмента)

DROP FUNCTION GetPoolForIP;
delimiter //
CREATE FUNCTION GetPoolForIP(ip1 int UNSIGNED) RETURNS MEDIUMTEXT
BEGIN
    DECLARE mac_dhcp1 VARCHAR(255);
    SELECT  mac_dhcp INTO mac_dhcp1 FROM mtraf_status WHERE INET_ATON(mtraf_status.ip)=ip1 LIMIT 1;
    RETURN   CONCAT(
            "pool { range ",
            INET_NTOA(ip1),
            "; allow members of \"",
            INET_NTOA(ip1),
            "__",
            mac_dhcp1,
            "\"; default-lease-time 36000; max-lease-time 72000; } "
            );
END
//
delimiter ;

Пример

mysql> SELECT GetPoolForIP(INET_ATON('10.0.136.11'));
+-------------------------------------------------------------------------------------------------------------------------------+
| GetPoolForIP(INET_ATON('10.0.136.11'))                                                                                        |
+-------------------------------------------------------------------------------------------------------------------------------+
| pool { range 10.0.136.11; allow members of "10.0.136.11__0:13:d4:5:d9:f4"; default-lease-time 36000; max-lease-time 72000; }  |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.11 sec)


DROP FUNCTION GetAllPoolsForNoPayNet;
delimiter //
CREATE FUNCTION GetAllPoolsForNoPayNet(n1 int UNSIGNED) RETURNS TEXT
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE mask1 int UNSIGNED;
    DECLARE current_ip int UNSIGNED DEFAULT 0;
    DECLARE pools TEXT DEFAULT "";

    DECLARE cursor_ip CURSOR FOR  SELECT INET_ATON(ip_dhcp) from mtraf_status  WHERE (INET_ATON(mtraf_status.ip_dhcp))&mask1=(n1+6553600);

    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

    SELECT mask from network_mask WHERE network=n1 INTO mask1;

    OPEN cursor_ip;
    FETCH cursor_ip INTO current_ip;
    WHILE done = 0 DO
        SELECT  CONCAT(GetPoolForNoPayIP(current_ip),"  \n",pools) INTO pools;
        FETCH  cursor_ip INTO current_ip;
    END WHILE;
    CLOSE cursor_ip;
    RETURN pools;
END
//
delimiter ;

Пример (поскипано):

mysql> SELECT GetAllPoolsForNet(INET_ATON('10.0.136.0'));
...
pool { range 10.0.136.154; allow members of 10.0.136.154__0:e:2e:98:32:c default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.153; allow members of 10.0.136.153__0:15:f2:5:44:29 default-lease-time 36000; max-lease-time 72000; }                                                                                                                  
pool { range 10.0.136.152; allow members of 10.0.136.152__0:e0:1c:3c:33:cd default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.151; allow members of 10.0.136.151__0:e0:1c:3b:d6:39 default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.150; allow members of 10.0.136.150__0:19:d1:e6:1e:2c default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.149; allow members of 10.0.136.149__0:18:f3:fb:fe:b6 default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.174; allow members of 10.0.136.174__0:26:2d:5f:97:c1 default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.148; allow members of 10.0.136.148__0:26:9e:75:50:d2 default-lease-time 36000; max-lease-time 72000; }                                                                                                                 
pool { range 10.0.136.147; allow members of 10.0.136.147__0:a0:d1:ca:47:b default-lease-time 36000; max-lease-time 72000; }                                                                                                                  
pool { range 10.0.136.145; allow members of 10.0.136.145__0:e0:4c:3:d7:55 default-lease-time 36000; max-lease-time 72000; }                                                                                                                  
pool { range 10.0.136.146; allow members of 10.0.136.146__0:1f:c6:4f:ed:7a default-lease-time 36000; max-lease-time 72000; }           
...
1 row in set (13.79 sec)

Конфиг SUBNET

Для того что бы выдавать статические маршруты (и не говорите мне что при правильном дизайне сети это не нужно=) ) нужно gateway разбивать на октеты и писать в виде 192, 168, 0, 1 что вносит приятное разнообразие программирование. Ну, и еще - рассчитвать btoadcast зная netmask и network (спасибо дяде Кораблеву за наше счастливое детство лекции )
Строка с маршрутами получилась довольно длинная.

DROP FUNCTION GetSubnet;
delimiter //
CREATE FUNCTION GetSubnet(n1 int UNSIGNED) RETURNS TEXT
BEGIN
-- broacast
    DECLARE b1 INT UNSIGNED;
    DECLARE m1 INT UNSIGNED;
    DECLARE g1 INT UNSIGNED;
    DECLARE oct_1 INT UNSIGNED;
    DECLARE oct_2 INT UNSIGNED;
    DECLARE oct_3 INT UNSIGNED;
    DECLARE oct_4 INT UNSIGNED;
    DECLARE gateway_dhcp VARCHAR(255);

    DECLARE prefix TEXT default "";
    DECLARE pools TEXT default "";

    SELECT GetMaskForIP(n1) INTO m1;
    SELECT GetBroadcast(n1,m1)  INTO b1;
    SELECT GetGateway(n1) INTO g1;
    SELECT (g1 & INET_ATON('255.0.0.0')) >> 24 INTO oct_1;
    SELECT (g1 & INET_ATON('0.255.0.0')) >> 16 INTO oct_2;
    SELECT (g1 & INET_ATON('0.0.255.0')) >> 8  INTO oct_3;
    SELECT (g1 & INET_ATON('0.0.0.255')) >> 0  INTO oct_4;

    SELECT CONCAT(oct_1,",",oct_2,",",oct_3,",",oct_4) INTO gateway_dhcp;

    SELECT CONCAT("subnet ",INET_NTOA(n1)," netmask ",INET_NTOA(m1),"  { \n              option subnet-mask         ",INET_NTOA(m1),";\n        option broadcast-address   ",INET_NTOA(b1),";\n        option routers ",INET_NTOA(g1),";\n  \n        ddns-update-style none;\n        option domain-name \"airbites.kh.ua\";\n        option domain-name-servers    193.33.48.33,   193.33.49.160,    195.69.244.7,        195.69.244.2,      193.33.48.1,    193.33.49.1;\n        option ms-classless-static-routes  4, 224, ",gateway_dhcp,", 8, 10, ",gateway_dhcp,", 12, 172,16, ",gateway_dhcp,", 16, 192,168, ",gateway_dhcp,", 17, 95,69,128, ",gateway_dhcp,", 32, 193, 33, 48, 1, ",gateway_dhcp,", 32, 193, 33, 48, 33, ",gateway_dhcp,", 32, 193, 33, 49, 1, ",gateway_dhcp,", 32, 193, 33, 49, 160, ",gateway_dhcp,", 17, 188, 230, 0, ",gateway_dhcp,";\n         option rfc3442-classless-static-routes 4, 224, ",gateway_dhcp,", 8, 10, gateway_dhcp, 12, 172,16, ",gateway_dhcp,", 16, 192,168, ",gateway_dhcp,", 17, 95,69,128, ",gateway_dhcp,", 32, 193, 33, 48, 1, ",gateway_dhcp,", 32, 193, 33, 48, 33, ",gateway_dhcp,", 32, 193, 33, 49, 1, ",gateway_dhcp,", 32, 193, 33, 49, 160, ",gateway_dhcp,", 17, 188, 230, 0, ",gateway_dhcp,";") INTO prefix;

    SELECT GetAllPoolsForNet(n1) INTO pools;
    RETURN CONCAT(prefix,"\n\n",pools,"\n\n }");
    END
//
delimiter ;


Пример:

subnet 10.0.136.0 netmask 255.255.255.0  {                                                                                                                                                                                                 
              option subnet-mask         255.255.255.0;                                                                                                                                                                                      
        option broadcast-address   10.0.136.255;                                                                                                                                                                                             
        option routers 10.0.136.254;                                                                                                                                                                                                         
                                                                                                                                                                                                                                             
        ddns-update-style none;                                                                                                                                                                                                              
        option domain-name "airbites.kh.ua";                                                                                                                                                                                                 
        option domain-name-servers    193.33.48.33,   193.33.49.160,    195.69.244.7,        195.69.244.2,      193.33.48.1,    193.33.49.1;                                                                                                 
        option ms-classless-static-routes  4, 224, 10,0,136,254, 8, 10, 10,0,136,254, 12, 172,16, 10,0,136,254, 16, 192,168, 10,0,136,254, 17, 95,69,128, 10,0,136,254, 32, 193, 33, 48, 1, 10,0,136,254, 32, 193, 33, 48, 33, 10,0,136,254, 32, 193, 33, 49, 1, 10,0,136,254, 32, 193, 33, 49, 160, 10,0,136,254, 17, 188, 230, 0, 10,0,136,254;                                                                                                                                         
         option rfc3442-classless-static-routes 4, 224, 10,0,136,254, 8, 10, gateway_dhcp, 12, 172,16, 10,0,136,254, 16, 192,168, 10,0,136,254, 17, 95,69,128, 10,0,136,254, 32, 193, 33, 48, 1, 10,0,136,254, 32, 193, 33, 48, 33, 10,0,136,254, 32, 193, 33, 49, 1, 10,0,136,254, 32, 193, 33, 49, 160, 10,0,136,254, 17, 188, 230, 0, 10,0,136,254;                                                                                                                                    

pool { range 10.0.136.154; allow members of 10.0.136.154__0:e:2e:98:32:c default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.153; allow members of 10.0.136.153__0:15:f2:5:44:29 default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.152; allow members of 10.0.136.152__0:e0:1c:3c:33:cd default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.151; allow members of 10.0.136.151__0:e0:1c:3b:d6:39 default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.150; allow members of 10.0.136.150__0:19:d1:e6:1e:2c default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.149; allow members of 10.0.136.149__0:18:f3:fb:fe:b6 default-lease-time 36000; max-lease-time 72000; }   
pool { range 10.0.136.174; allow members of 10.0.136.174__0:26:2d:5f:97:c1 default-lease-time 36000; max-lease-time 72000; }   
...поскипано ...
1 row in set (14.09 sec)