Документация → make_config «один на порту» для isc-dhcpd

Задача: динамически формировать конфигурационный файл для dhcp-сервера isc-dhcpd. При этом, если в настройках учетной записи абонента стоит галка «один на порту», то не проверять его мак-адрес. В этом случае учитываются только порт подключения и мак-адрес свича. Как это будет выглядеть в сформированном конфиге:

class "host10.0.0.7" {match if suffix(option agent.circuit-id,1)=a and suffix(option agent.remote-id,6)=00:11:22:33:44:55;}

subnet 10.0.0.0 netmask 255.255.255.0 {
    option subnet-mask 255.255.255.0;
    option broadcast-address 10.0.0.255;
    host host10.0.0.6 { hardware ethernet 00:11:00:11:00:22; fixed-address 10.0.0.6; }
    pool { range 10.0.0.7; allow members of "host10.0.0.7"; }
}

Здесь мы видим, что абонент, подключенный к порту 10 («a» в 16-ричной системе счисления) свича с мак-адресом 00:11:22:33:44:55 получит ip 10.0.0.7. Абонент с мак-адресом 00:11:00:11:00:22 получит ip 10.0.0.6. У первого абонента в настройках стоит галка «один на порту».

Создаем файл /usr/local/nodeny/kernel/make_config_dhcp.cfg:

run     => 0,
period  => 60,
template  => {
            'dhcp_ok.tmpl' => {
                # куда будет записан сформированный конфиг
                file       => '/usr/local/etc/dhcpd.conf',

                # системная команда, которая будет выполнена перед записью конфига, можно ''
                cmd_before => '',

                # системная команда, которая будет выполнена после записи конфига, можно ''
                cmd_after  => '/usr/local/etc/rc.d/isc-dhcpd forcestart >/dev/null',

                # удалять пустые строки
                pretty => 1,
            },
},
subs    => {
            pretty_mac => sub {
                my $mac = shift;
                $mac =~ s/(..)/$1:/g;
                chop $mac;
                return $mac;
            },
            hex => sub {
                return sprintf('%x', $_[0]);
            }
}

Создаем /usr/local/nodeny/kernel/make_config/dhcp_ok.tmpl:

allow unknown-clients;
option domain-name-servers 1.1.1.1, 8.8.8.8;

default-lease-time 28800;
min-lease-time 10000;
max-lease-time 128800;

authoritative;

ddns-update-style interim;

log-facility local7;

{% for user in users %}
  {% if user.ips.0.ipa && user.ips.0.type eq 'static' && user.connection.0 && user.connection.0.oneconnect %}
    {% one_line %}
class "host{{user.ips.0.ipa}}" { match if suffix(option agent.circuit-id,1)={{user.connection.0.device_port|hex}}
    and suffix(option agent.remote-id,6)={{user.connection.0.device_mac|pretty_mac}}; }
    {% one_line_end %}
  {% endif %}
{% endfor %}

subnet 10.0.0.0 netmask 255.255.255.0 {
    option subnet-mask 255.255.255.0;
    option broadcast-address 10.0.0.255;
    interface em1;
    option routers 10.0.0.1;


{% for user in users %}
  {% if user.ips.0.ipa && user.ips.0.type eq 'static' && user.connection.0 %}
    {% if user.connection.0.oneconnect %}
        pool { range {{user.ips.0.ipa}}; allow members of "host{{user.ips.0.ipa}}"; }
    {% else %}
        host host{{user.ips.0.ipa}} { hardware ethernet {{user.connection.0.mac|pretty_mac}}; fixed-address {{user.ips.0.ipa}}; }
    {% endif %}
  {% endif %}
{% endfor %}

}

Запустим с выводом результата на экран:

perl /usr/local/nodeny/nokernel.pl -v -m=make_config -g=make_config_dhcp

Если конфиг сформирован правильно, добавим запуск make_config в автозагрузку:

echo '/usr/bin/perl /usr/local/nodeny/nokernel.pl -m=make_config -g=make_config_dhcp -d &' >> /etc/rc.local

Небольшие комментарии по шаблону: