Перейти к содержимому
Калькуляторы

DHCP server with SQL support on Perl DHCP сервер с базой SQL на Perl, с опцией 82, маршрутами и прочим

Если использовать пул, то получается нельзя скрипт запускать несколькими процессами, т.к есть маленькая вероятность выдачи 1-го и того же адреса двум абонентам разными процесами.

lock-и юзать... хотя у меня - он многопоточный (перепиливал немного), можете зять за основу, выкладывал раньше, но - только настатику заточен...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Кто-то реально мерял у себя скорость работы с mysql?

А смысл?

У всех разные запросы по сложности, разные сервера по скорости.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

коннект к базе ни разу не падал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

а никто не доделывал пул адресов?

Что то мой метод не очень корректно работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

я все пул мучаю, как у меня работает не очень мне нравится.

Сейчас хочу вставить условие на проверку. Мучал вчера то что мы добавляли новую db_get_offer_data

но потом подумал может проще вставить условие в handle_discover.

 

Сейчас оно выглядит у меня так:

 

sub handle_discover {#my $dbh = $_[0];#my $fromaddr  = $_[1];#my $dhcpreq = $_[2];my ($dhcpresp);$dhcpresp = GenDHCPRespPkt($_[2]);$dhcpresp->{options}->{DHO_DHCP_MESSAGE_TYPE()} = pack('C', DHCPOFFER);if (db_get_offer_data($_[0], $_[2], $dhcpresp) == 1) {	send_reply($_[1], $_[2], $dhcpresp, $_[0]);	#db_lease_offered($_[0], $_[2]);}else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addrif (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {	$dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);	send_reply($_[1], $_[2], $dhcpresp, $_[0]);}}}

 

в версии БЕЗ пула так:

 

sub handle_discover {#my $dbh = $_[0];#my $fromaddr  = $_[1];#my $dhcpreq = $_[2];my ($dhcpresp);$dhcpresp = GenDHCPRespPkt($_[2]);$dhcpresp->{options}->{DHO_DHCP_MESSAGE_TYPE()} = pack('C', DHCPOFFER);if (db_get_requested_data($_[0], $_[2], $dhcpresp) == 1) {	send_reply($_[1], $_[2], $dhcpresp, $_[0]);	db_lease_offered($_[0], $_[2]);}else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addrif (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {	$dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);	send_reply($_[1], $_[2], $dhcpresp, $_[0]);}}}

 

хочу добавить запрос к базе который возвращает либо число строк (колличество ИП на порту) или массив строк этих адресов (ИД строк)

Нужно вставить запрос, потом условие что то типо:

 

 

			$sth = $_[0]->prepare("SELECT `cl_id` ... "); // возвратит массив строк 	//или такой запрос$sth = $_[0]->prepare("SELECT count(`cl_id`) ..."); // вернет 1 значение count(`cl_id`)смотря с чем проще оперироватьif (полученное >1){тут код если пул на выбранном портуif (db_get_offer_data($_[0], $_[2], $dhcpresp) == 1) {	send_reply($_[1], $_[2], $dhcpresp, $_[0]);	#db_lease_offered($_[0], $_[2]);}else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addrif (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {	$dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);	send_reply($_[1], $_[2], $dhcpresp, $_[0]);}}}else{тут код если 1 ип на портуif (db_get_requested_data($_[0], $_[2], $dhcpresp) == 1) {	send_reply($_[1], $_[2], $dhcpresp, $_[0]);	db_lease_offered($_[0], $_[2]);}else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addrif (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {	$dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);	send_reply($_[1], $_[2], $dhcpresp, $_[0]);}}}

 

 

единственное для запроса нужны

$dhcp_opt82_port_id

$dhcp_opt82_chasis_id'

$dhcp_opt82_vlan_id

 

которые возвращает, как я понимаю

my ($dhcp_opt82_vlan_id, $dhcp_opt82_unit_id, $dhcp_opt82_port_id, $dhcp_opt82_chasis_id);

if (GetRelayAgentOptions($_[1], $dhcp_opt82_vlan_id, $dhcp_opt82_unit_id, $dhcp_opt82_port_id, $dhcp_opt82_chasis_id))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Должно получится что то типо:

 

 

sub handle_discover {       #my $dbh = $_[0];       #my $fromaddr  = $_[1];       #my $dhcpreq = $_[2];       my ($dhcpresp);       my ($dhcp_opt82_vlan_id, $dhcp_opt82_unit_id, $dhcp_opt82_port_id, $dhcp_opt82_chasis_id);       $dhcpresp = GenDHCPRespPkt($_[2]);       $dhcpresp->{options}->{DHO_DHCP_MESSAGE_TYPE()} = pack('C', DHCPOFFER);       if (GetRelayAgentOptions($_[1], $dhcp_opt82_vlan_id, $dhcp_opt82_unit_id, $dhcp_opt82_port_id, $dhcp_opt82_chasis_id))        {       $sth = $dbh->prepare("SELECT `cl_id` ... where ...=$dhcp_opt82_port_id ...=$dhcp_opt82_chasis_id' ..=$dhcp_opt82_vlan_id"); //вернет массив cl_id       $sth->execute();if ($sth->rows()>1) //Если на порту больше 1 ИП{       if (db_get_offer_data($_[0], $_[2], $dhcpresp) == 1) {               send_reply($_[1], $_[2], $dhcpresp, $_[0]);               #db_lease_offered($_[0], $_[2]);       }else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addr       if (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {               $dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);               send_reply($_[1], $_[2], $dhcpresp, $_[0]);       }}}else {       if (db_get_requested_data($_[0], $_[2], $dhcpresp) == 1) {               send_reply($_[1], $_[2], $dhcpresp, $_[0]);               db_lease_offered($_[0], $_[2]);       }else{# if AUTO_CONFIGURE (116) supported - send disable generate link local addr       if (defined($_[2]->getOptionRaw(DHO_AUTO_CONFIGURE)) && $_[2]->getOptionValue(DHO_AUTO_CONFIGURE()) != 0) {               $dhcpresp->addOptionValue(DHO_AUTO_CONFIGURE(), 0);               send_reply($_[1], $_[2], $dhcpresp, $_[0]);       }}}       } //if (GetRelayAgentOptions}

 

 

Поправьте меня

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Cramac, а какая у вас задача? Т.е. что имеете ввиду под работой с пулом адресов? Адреса должны выдваться из пула свободных адресов? Так эта задача решается скорее запросами к БД, а не ковырянием скрипта. Вот чего я ни у кого не увидел, так это кэширования лиз в самом перле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Задача простая, сейчас выдаем адреса по опции, в некоторых местах поставили вифи, хочу чтоб он же выдавал клиентам вифи из пула адресов. Сейчас у меня так работает но не очень корректно. Вот и хочу поправить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Потихоньку разбираюсь в коде. Не знаю баг или фича, но вот:

в send_reply()

if ($_[1]->flags() == 0 || 1) {# send unicast XXXXXXXXX - flags ignored!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Потому что оно отправляет релей агенту, а броадкаст там не реализован, насколько помню.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

выражение в скобках всегда истинно - я про это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

конечно всегда истинно, Иван ведь сказал что бродкаст не реализован, вот и шлем все юникастом в любом случае.. А условие сделано на всяк случай, вдруг ктото прикрутит работу без релея )

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Работа без релея прикрутилась одной строкой в send_reply():

setsockopt($SOCKET_RCV, SOL_SOCKET, SO_BROADCAST, $toaddr eq $ADDR_BCAST ? 1 : 0);

Всовывать перед отправкой пакета:

send($SOCKET_RCV, $dhcpresppkt, 0, $toaddr) || logger(0, "send error: $!");

 

Вроде все четко работает, но только с одним потоком. Если делать несколько, то каждый поток зависать секунд на 10 перед ответом на запрос. Даже не знаю куда смотреть. Может потому что под виндой (dwimperl) тестирую?

 

И еще вопрос: зачем к ответам сервера прикручивать 82 опцию? Без них свитч или релей не поймет куда релеить? Я это убрал, никаких побочных эфектов не заметил.

Изменено пользователем lamka

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

если в запросе есть опт82 - то и в ответе она должна быть

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да, почитал уже RFC 3046

DHCP servers claiming to support the Relay Agent Information option

SHALL echo the entire contents of the Relay Agent Information option

in all replies.

 

If a server is unable to copy a full Relay

Agent Information field into a response, it SHALL send the response

without the Relay Information Field, and SHOULD increment an error

counter for the situation.

Хотя, видимо, это не так уж и страшно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Хотя, видимо, это не так уж и страшно.

То, что не по RFC - рулетка: на одном вендоре заработает, на другом - встанет раком...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Работа без релея прикрутилась одной строкой в send_reply():

Там было следующее.

1. Приём без релей агента вроде не работал в ряде случаев

2. Если клиент не выставил броадкаст флаг то ему нужно отправлять ответ юникастом на его мак адрес, а для этого нужно весь пакет ручками собирать, включая юдп заголовок

 

Выставлять/снимать флаг с сокета - НЕ ПРАВИЛЬНО.

С этим сокетом работает много потоков одновременно, и пока может возникнуть ситуация когда один поток выставил флаг, другой его тут же снял, а первый поток только поставил на отправку, в итоге каша вместо результата.

Правильным решением будет создание ещё одного сокета для отправки броадкастов.

И ещё один для отправки юникастом "сырых" пакетов собранных руками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

то ему нужно отправлять ответ юникастом на его мак адрес, а для этого нужно весь пакет ручками собирать, включая юдп заголовок

Не понял как можно послать ip пакет на мак адрес? Если у клиента нет ciaddr в запросе, то только бродкаст. Иначе как без ip слать? Мне кажется, что если у клиента нет ciaddr и флага бродкаста, то пошел он нафиг. Вообще такое часто встречается?

 

Правильным решением будет создание ещё одного сокета для отправки броадкастов.

И ещё один для отправки юникастом "сырых" пакетов собранных руками.

А клиенты не проверяют исходящий порт сервера? Ведь придется сокеты вешать на разные исходящие порты, не только 68?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не понял как можно послать ip пакет на мак адрес? Если у клиента нет ciaddr в запросе, то только бродкаст. Иначе как без ip слать? Мне кажется, что если у клиента нет ciaddr и флага бродкаста, то пошел он нафиг. Вообще такое часто встречается?

Да легко.

Заполняем L2 заголовок правильно и пакет уходит кому надо.

Вон PPPoE шлёт же на мак клиента, без всяких IP адресов, чем я хуже?)

Мак клиента есть в запросе.

Броадкаст флаг - вроде как костыль, который позже появился.

 

А клиенты не проверяют исходящий порт сервера? Ведь придется сокеты вешать на разные исходящие порты, не только 68?

Нужно уточнять документацию.

Есть ещё REUSEPORT флаг на сокет, но тогда пакеты будут дублироватся и их нужно будет или вычитывать из сокета или забить на это и после заполнения буфера они сами начнут дропатся.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Заполняем L2 заголовок правильно и пакет уходит кому надо.

Вон PPPoE шлёт же на мак клиента, без всяких IP адресов, чем я хуже?)

Мак клиента есть в запросе.

Видимо я чего-то не понимаю. PPPoE - не относится к IP-протоколам, он сам по себе. И в заголовке IP-пакета нет данных о мак-адресе. Клепать ethernet фреймы - как-то уж слишком экстремально.

 

Есть ещё REUSEPORT флаг на сокет, но тогда пакеты будут дублироватся и их нужно будет или вычитывать из сокета или забить на это и после заполнения буфера они сами начнут дропатся.

Пожалуй, логично было бы вынести работу с сокетом из потоков в основной и сделать очередь (благо что udp - пакеты улетают мгновенно), . Т.е. в потоках читаются запросы, идет обращение к БД и т.п., а ответы суются в очередь, которую обслуживает отдельный поток.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Видимо я чего-то не понимаю. PPPoE - не относится к IP-протоколам, он сам по себе.

Это я к тому, что отправить на мак можно любой пакет и IP тут никаким боком.

 

И в заголовке IP-пакета нет данных о мак-адресе.

Мак адрес у дхцп сервера есть из запроса, клиент сам присылает свой мак.

Можно было бы и в л2 пакета смотреть, но это не нужно, разве что для секурности, чтобы подавлять работу подавителей дхцп серверов. :)

 

Клепать ethernet фреймы - как-то уж слишком экстремально.

Там сложного ничего нет. Совсем ничего.

Единственная замута это вланы и дополнение конфига.

IP/UDP сложнее - для них нужно суммы считать.

 

 

Пожалуй, логично было бы вынести работу с сокетом из потоков в основной и сделать очередь (благо что udp - пакеты улетают мгновенно), . Т.е. в потоках читаются запросы, идет обращение к БД и т.п., а ответы суются в очередь, которую обслуживает отдельный поток.

Нет.

Чтобы был полноценный сервер без релея нужно принимать и отправлять прямо с интерфейса через BPF прослойку.

Те не городить дрочиво броадкаст опции сокета, а собирать л2+л3+л4+дхцп пакет самому и слать в сеть. Тогда и очереди никакие не нужны.

Я заглядывал в dnsmasq там вроде именно так и сделано было, помню видел программы-фильтры дхцп запросов для BPF. (а может это dhcpdump был)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Иван - все правильно говоришь, все работает. Написал от нечего делать более развернутый ДХЦП, дергает пакеты из ядра, разбирает все сам , проверяет в базе и отдает назад собирая полный эзернет заголовок и отправляет на мак юзера и юникаст и броадкаст. Причем добавил даже unnumbered туда , осталось шейпер прикрутить и вебку хоть какую то сделать... Ну и получится какой то аналог то ли циски, то ли акселя ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Аксель, емнип, модуль ядерный, а это чистой воды юзерленд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

а причем тут это ? я в юзерленде только дхцп пакеты разгребаю и собираю, всей маршрутизацией занимается ядро как и раньше..

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Аксель, емнип, модуль ядерный, а это чистой воды юзерленд.

там тот модуль нужен только для псевдоинтерфейсов...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.