Требуется запретить выдачу динамического адреса для заданного MAC адреса (точнее некого списка mac-адресов) в локальной сети.
На машине, где и пытаемся настроить блокировку, стоит dhcp-сервер, который выдает всем желающим адреса из пула 10.0.0.0/24.
Предположительно, правило вида
iptables -I INPUT -i eth0 -p udp --sport 68 --dport 67 -m mac --mac-source 11:22:33:44:55:66 -j DROP
в iptables должно бы заблокировать для MAC адреса 112233445566 выдачу ему динамического адреса от dhcpd,
стоящего на той же машине. Ан нет, адреса продолжают выдаваться,
хотя счетчик в iptables, говорящий о том, что правило сработало, исправно увеличивается:
iptables -nxvL INPUT
Chain INPUT (policy DROP 13 packets, 668 bytes)
pkts bytes target prot opt in out source destination
3 1728 DROP udp -- eth0 * 0.0.0.0/0 0.0.0.0/0 udp spt:68 dpt:6
7 MAC 11:22:33:44:55:66
Более того, прописав правило вида
iptables -I INPUT -m mac --mac-source 11:22:33:44:55:66 -j DROP
(т.е. уничтожаем вообще все пакеты с этого MAC-адреса), тоже не приводит к блокировки выдачи
этому хосту динамического IP, в логах DHCP наблюдаем:
dhcpd: DHCPDISCOVER from 11:22:33:44:55:66 via eth0
dhcpd: DHCPOFFER on 10.0.0.63 to 11:22:33:44:55:66 via eth0
dhcpd: DHCPREQUEST for 10.0.0.63 (10.0.0.1) from 11:22:33:44:55:66 via eth0
dhcpd: DHCPACK on 10.0.0.63 to 11:22:33:44:55:66 via eth0
хотя по iptables -nxvL видно, что счетчик пакетов/байтов для этого правила после каждого
запроса увеличивается, т.е. правило (теоретически?) работает.
Да и практически оно тоже работает, так как после ввода второго правила с того хоста с MAC-ом 11:22:33:44:55:66
мы таже пинговать машину, где стоит dhcp-сервер не можем.
Тем не менее, можем исправно получать от нее адрес по dhcp :(
Получается, что dhcp сервер получает пакеты раньше, чем срабатывает iptables?
К сожалению, я не нашел в iptables возможности создать правила,
где можно было бы анализировать исходящий MAC адрес, например
iptables -I OUTPUT -o eth0 -p udp --sport 67 --dport 68 -m mac --mac-destination 11:22:33:44:55:66 -j DROP
Эта ситуация проверялась на трех машинах
dhcp-3.0_p2-r6 и dhcpcd-1.3.22_p4-r5 (Gentoo Linux)
Linux kernel 2.6.9
iptables v1.2.11
Зачем резать таблесам, настрой DHCP сервер. Создай какой-нибудь класс и запрети выдавать адреса тем кто в него попадает. На худой конец по МАС выдай 127.0.0.1 :))) интересно что получиться?
Можно, наверное и через dhcp решить вопрос, вот только список этих, требующих блокировки на локальном dhcp-сервере, MAC-адресов меняется, поэтому жестко вбить в dhcpd.conf их не получится. Можно, конечно, генерить нужный кусок конфига для dhcp, но тогда придется при каждой смене списка мак-ов перегружать dhcp-сервер...
В общем, хотелось бы решить вопрос как то элегантнее, с помощью iptables.
Выдавать тем MAC-адресам какие то IP-шники нельзя, ибо они получают их с другого DHCP сервера, который находится значительно дальше первого и поэтому не успевает прислать ответ во-время (эти мак-и подхватывают адреса от ближайшего, т.е. обсуждаемого, dhcp).
попробовал написать в dhcpd.conf следующее:
group {
deny unknown-clients;
host tmp
{
hardware ethernet 11:22:33:44:55:66;
}
}
рассчитывая на то, что раз для данного MAC-а ничего не указано, значит и адрес ему выдан не будет,
а в основной пул адресов этот MAC не попадет, так как есть группа, где он явно описан.
Hе помогло - dhcpd все равно выдает IP на этот MAC-адрес из основного пула
(если в этой группе в разделе host прописать другой ип, то конечно же dhcpd этот "другой" ип и выдаст.
В общем, извечный вопрос - что делать? :)
Но, скорее всего это не поможет, так как, наверное, dhcpd работате через socket(PF_PACKET, ...) и получает пакеты до их поступления в цепочки iptables... Наверное надо копать в сторону настроек dhcp, а не iptables.
А если попробовать как в man dhcpd.conf:
class "blocked-macs" {
match pick-first-value (option dhcp-client-identifier, hardware);
}
subclass "blocked-macs" 1:8:0:2b:4c:39:ad;
subclass "blocked-macs" 1:8:0:2b:a9:cc:e3;
subclass "blocked-macs" 1:0:0:c4:aa:29:44;
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
deny members of "blocked-macs";
range 10.0.0.11 10.0.0.50;
}
...
}
Спасибо, spirit, заработало :)
Теперь dhcpd не реагирует перечисленные субклассе MAC-и.
Не подскажешь, а что означает первая еденичка в записи:
subclass "blocked-macs" 1:8:0:2b:4c:39:ad;
^^^
остальные цифры - это mac-адрес, т.е. запись вида
subclass "blocked-macs" 1:11:22:33:44:55:66;
позволяет отправить клиента с MAC="11:22:33:44:55:66"
в класс blocked-macs, но если впереди не поставить эту единичку (т.е. "1:", то dhcp клиента не ловит).
В man dhcpd.conf о субклассах и о match-конструкциях вообще,
сказано очень туманно, я не понял принцип - вроде как можно отловить клиента по MAC или ClientID,
но на конструкции вида
class "blocked-macs"
{
match pick-first-value (option dhcp-client-identifier, hardware) = "11:22:33:44:55:66";
}
или
class "blocked-macs"
{
match if (option dhcp-client-identifier) = "11:22:33:44:55:66";
}
dhcp ругается (говорит неверный синтаксис).
Описания правильного синтаксиса там не приводится, только два скупых примера :(
> Не подскажешь, а что означает первая еденичка в записи:
Если честно - без понятия, просто взял пример из manual-а :-)
(Когда-то сталкивался с похожей проблемой, но не точно такой)
Можно конечно посмотреть "man dhcp-eval" про параметр hardware, но там тоже мутновато написано :-) да еще ссылка на RFC.
> Описания правильного синтаксиса там не приводится, только два скупых примера :(
Попробуйте посмотреть другие man-ы, их там несколько: man dhcp-eval, man dhcp-options.
> говорит неверный синтаксис
Может так попробовать ? (нет dhcpd под рукой, не могу проверить)
class "blocked-macs"
{
match if pick-first-value (option dhcp-client-identifier, hardware) = "11:22:33:44:55:66";
}
или
class "blocked-macs"
{
match if option dhcp-client-identifier = "11:22:33:44:55:66";
}
Всем огромное спасибо! Разобрался :)
man dhcp-eval несколько прояснил ситуацию, но не до конца.
В общем, задавать ловлю MAC можно вот так
class "blocked-macs"
{
match if pick-first-value (option dhcp-client-identifier, hardware) = 1:11:22:33:44:55:66;
}
(правило сработает по первому встреченному совпадению ClientID или MAC addr)
или так
class "blocked-macs"
{
match if hardware = 1:11:22:33:44:55:66;
}
Но так и не получилось построить конструкцию из ловли нескольких MAC-адресов в одном классе,
нечто вроде этого:
class "blocked-macs"
{
match if hardware = 1:11:22:33:44:55:10
elsif hardware = 1:11:22:33:44:55:20
elsif hardware = 1:11:22:33:44:55:30;
}
dhcpd ругается на неверный синтаксис, то ему требуется точка с запятой после строчки
(при поставлении который он начинает ожидать "expecting a parameter or declaration").
Различные модификации синтаксиса не помогли (правда я не долго разбирался).
Так как в man dhcpd.conf рекомендуют использовать конструкцию subclass-ов для ускорения поиска совпадений,
вернулся к ней, т.е. тому, что и предложил spirit:
class "blocked-macs"
{
match pick-first-value (option dhcp-client-identifier, hardware);
}
subclass "blocked-macs" 1:11:22:33:44:55:10;
subclass "blocked-macs" 1:11:22:33:44:55:20;
subclass "blocked-macs" 1:11:22:33:44:55:30;
Единичка в начале MAC-адреса задает тип интерфейса (ethernet)
из man dhcp-eval:
The hardware operator returns a data string whose first element is the type of network interface
indicated in packet being considered, and whose subsequent elements are client's link-layer address.
If there is no packet, or if the RFC2131 hlen field is invalid, then
the result is null.
Hardware types include ethernet (1) <...>
2jackill: я пробовал в правилах iptables задавать только MAC (и более никаких других фильтров),
это не помогает, вне зависимости от того, в какой цепочке или таблице это правило было
(в т.ч. и в -t mangle PREROUTING)
Вот развернутое объяснение от Eugene B. Berdnikov, почему не срабатывает iptables
(тоже самое, что сказал mky, только более развернуто):
-------------
Таким образом, dhcp-сервер должен уметь получать "сырой" пакет вместе с изернетовским хедером.
Очевидно, API сокетов IPv4 этого дать не может, просто потому что он относится
к другому уровню стэка протоколов. Следовательно, эта информация может быть добыта лишь
в обход IP-стэка. Стандартный способ в линуксе - через PF_PACKET.
Пакеты, вычитываемые таким образом, попадают в программу ДО пакетного фильтра
(поэтому, например, их видят tcpdump и вообще все pcap-based снифферы).
То, что пакетник сработает потом - на результат повлиять уже не может.
-------------