====== Mini FAQ ======
Q: Що потрібно від свіча, щоб запрацювала option 82? \\
A: Мати налаштований і працюючий dhcp relay з увімкненою option 82, dhcp snooping, що не пропускає клієнтські запити в обхід рілею, та ip source guard, що дропає пакети для айпішок, які не отримано крізь рілей.\\.
Q: На яких свічах має бути рілей? \\
A: На всіх - рівня доступу.\\
Q: У нас тут пів мережі на мильницях, це буде працювати? А можна тримати частину мережі на IP+MAC та іншу частину на option 82? \\
A: Сталася критична помилка - у вас недостатньо грошей для використання цього функціоналу.\\
====== Налаштування Ubilling та DHCP option 82 ======
Для того, щоб усе запрацювало в базовому варіанті, нам потрібно виконати шість простих кроків:
1. Підмережу користувачів додано як:
^ ID ^ Початкова ІР ^ Остання ІР ^ Мережа/CIDR ^ Тип мережі ^
| 1 | 172.16.0.0 | 172.16.0.255 | 172.16.0.0/24 | dhcp82 |
2. /etc/rc.conf виглядає наступним чином
ifconfig_em0="inet 172.16.0.1 netmask 255.255.255.0"
ifconfig_em0_alias0="inet 172.32.0.1 netmask 255.255.240.0"
ifconfig_em0_alias1="inet 192.168.94.1 netmask 255.255.255.0"
3. Шаблон config/dhcp/global.template
option domain-name "ourisp";
option domain-name-servers 172.16.0.1;
default-lease-time 3600;
max-lease-time 43200;
authoritative;
ddns-update-style none;
log-facility local7;
one-lease-per-client true;
deny duplicates;
shared-network ourisp {
{SUBNETS}
subnet 192.168.94.0 netmask 255.255.255.0 {
}
subnet 172.32.0.0 netmask 255.255.240.0 {
default-lease-time 3600;
option domain-name "isp";
option subnet-mask 255.255.240.0;
option domain-name-servers 172.32.0.1;
option routers 172.32.0.1;
pool {
range 172.32.0.100 172.32.0.254;
{DENYMEMBERS}
}
log(info, "==");
if exists agent.remote-id and exists agent.circuit-id {
if binary-to-ascii(16, 8, "", substring(option agent.remote-id, 2, 1)) = "0" {
set switch-mac = concat("0", binary-to-ascii(16, 8, "", substring(option agent.remote-id, 2, 1)), ":", binary-to-ascii(16, 8, ":", substring(option agent.remote-id, 3, 6)));
# log(info,concat("SWITCH-MAC1:",switch-mac));
} else {
# set switch-mac = binary-to-ascii(16, 8, ":", substring(option agent.remote-id, 2, 6));
# log(info,concat("SWITCH-MAC2:",switch-mac));
set switch-mac = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,6,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,7,1))),2)
);
# log(info,concat("SWITCH-MAC3:",switch-mac3));
}
set clip = binary-to-ascii(10,8,".",leased-address);
set clremote = binary-to-ascii(16,8,"",option agent.remote-id);
set clcircuit = binary-to-ascii(10,8,"",option agent.circuit-id);
set switch-port = binary-to-ascii(10, 8, "", substring(option agent.circuit-id, 5, 1));
set switch-port-vlan = binary-to-ascii(10, 16, "", substring(option agent.circuit-id, 2, 2));
log( info,concat("OPTION82 INFO - SWITCHMAC: ",switch-mac," PORTSW: ",switch-port," VLAN: ",switch-port-vlan));
log( info,concat("*Leased IP: ",clip, " SWITCH: ",clremote," PORT: ",clcircuit," SWITCHMAC: ",switch-mac," PORTSW: ",switch-port," VLAN: ",switch-port-vlan," (with opt82)") );
} else {
set clhw = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
log( info,concat("*Leased IP: ",binary-to-ascii(10,8,".",leased-address), " MAC: ", clhw," (without opt82)") );
}
log(info, "==");
}
}
4. Шаблон config/dhcp/option82.template перебуває в дефолтному стані ([[templating#dhcp_option82|підтримувані макроси]])\\
5. У конфізі alter.ini встановлено опцію NMLEASES = /var/log/dhcpd.log і налаштовано [[bsddhcpd|правильне логування ISP-DHCPD]] \\
6. В OnConnect вимкнено прибивання за MAC-у. Тепер це проблема ip source guard і dhcp snooping вашого свіча (192.168.94.4 у прикладі).
Виходячи з усього вищевказаного, не складно зробити висновок, що прив'язка планується за парою повних remote-id/circuit-id. Перевірити поведінку такого конфіга не складно за допомогою наступних нехитрих рухів тіла
====== Відлагодження scapy======
p="\x01\x01\x05\x02\x06\x11\x22\x34\x44\x55\x66"
dhcp_discover = Ether(src=RandMAC(),dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=RandString(12,'0123456789abcdef'))/DHCP(options=[("message-type","discover"),("relay_agent_Information",p),"end"])
sendp(dhcp_discover)
у відповідь на що ми маємо отримати щось на кшталт:
Oct 15 00:38:20 test dhcpd: Wrote 0 class decls to leases file.
Oct 15 00:38:20 test dhcpd: Wrote 1 leases to leases file.
Oct 15 00:38:34 test dhcpd: ==
Oct 15 00:38:34 test dhcpd: *Leased IP: 172.16.0.2 SWITCH: 112234445566 PORT: 5 (with opt82)
Oct 15 00:38:34 test dhcpd: ==
Oct 15 00:38:34 test dhcpd: ==
Oct 15 00:38:34 test dhcpd: *Leased IP: 172.16.0.2 SWITCH: 112234445566 PORT: 5 (with opt82)
Oct 15 00:38:34 test dhcpd: ==
Oct 15 00:38:34 test dhcpd: DHCPDISCOVER from 30:32:63:30:35:62 via em0
Oct 15 00:38:35 test dhcpd: DHCPOFFER on 172.16.0.2 to 30:32:63:30:35:62 via em0
а також під час прослуховування за допомогою
tcpdump -n -i em0 -s 0 -v -vv
ми спостерігатимемо прилітаючі до нас
Agent-Information Option 82, length 13:
Remote-ID........
Circuit-ID.......
====== Особливості роботи на комутаторах Zyxel ======
GS-4012, GS-3012 взагалі не повертають remote-id. Тому орієнтуватися варто тільки на sub-option 1 (Agent Circuit ID). Тож при побудові шаблону потрібно керуватися ось цим: http://zyxel.ru/kb/2030
{{ :zyxelopt82.png?400 |}}
У чорновому варіанті можна оформити це приблизно так:
set clremote = binary-to-ascii(10,16,"",substring(option agent.circuit-id,4,2));
set clcircuit = binary-to-ascii(10,16,"",substring(option agent.circuit-id,1,2));
а також виправити option82.template відповідно до цих реалій
що в результаті дає нам такий лог
Oct 15 16:52:00 test dhcpd: ==
Oct 15 16:52:00 test dhcpd: *Leased IP: 172.32.0.100 SWITCH: 18259 PORT: 768 (with opt82)
Oct 15 16:52:00 test dhcpd: ==
Приклад конфігурації Zyxel GS-3012:
ip address inband-default 192.168.94.4 255.255.255.0
ip address default-gateway 192.168.94.1
interface port-channel 12
dhcp snooping trust
exit
dhcp smart-relay
dhcp smart-relay helper-address 192.168.94.1
dhcp smart-relay option
dhcp smart-relay information
dhcp snooping
dhcp snooping vlan 1
dhcp snooping vlan 1 option
dhcp snooping vlan 1 information
dhcp dhcp-vlan 1
====== Спрощення життя ======
Для зручнішого виловлювання пар remote-id і circuit-id існує сервіс аналогічний [[uhw|UHW]], що знаходиться в **docs/opt82_uhw**. Налаштування в основному аналогічне такому в оригінального сервісу. Ходять чутки, що погрожували дописати ще й самостійну активацію абонентом ;)
====== Патч для isc-dhcp44-server ======
Для того, щоб користувачі могли змінювати свої пристрої скільки завгодно разів, і не чекати, поки на сервері закінчиться ліза під їхню адресу, - до DHCP-сервера потрібно застосувати патч і перезібрати пакет із вихідного коду.
--- server/dhcp.c.orig 2017-07-25 16:39:54.000000000 +0300
+++ server/dhcp.c 2017-09-13 00:26:29.330284000 +0300
@@ -31,6 +31,7 @@
#include
#include
+extern int flag_dd_option;
static void maybe_return_agent_options(struct packet *packet,
struct option_state *options);
static int reuse_lease (struct packet* packet, struct lease* new_lease,
@@ -4900,8 +4901,13 @@
{
if (LEASE_NOT_EMPTY(pool->free))
candl = LEASE_GET_FIRST(pool->free);
- else
+ else if (LEASE_NOT_EMPTY(pool->abandoned))
candl = LEASE_GET_FIRST(pool->abandoned);
+ else if (flag_dd_option)
+ {
+ candl = LEASE_GET_FIRST(pool->active);
+ candl -> ends = cur_time;
+ }
}
/*
--- server/dhcpd.c.orig 2017-07-25 16:39:54.000000000 +0300
+++ server/dhcpd.c 2017-09-13 03:25:44.556962000 +0300
@@ -57,6 +57,7 @@
gid_t set_gid = 0;
#endif /* PARANOIA */
+int flag_dd_option = 0;
struct iaddr server_identifier;
int server_identifier_matched;
@@ -184,6 +185,7 @@
" [-play trace-input-file]\n"
#endif /* TRACING */
" [-pf pid-file] [--no-pid] [-s server]\n"
+ " [-dd] - enable dd mode\n"
" [if0 [...ifN]]",
isc_file_basename(progname));
}
@@ -329,6 +331,8 @@
usage(use_noarg, argv[i-1]);
set_chroot = argv [i];
#endif /* PARANOIA */
+ } else if (!strcmp (argv [i], "-dd")) {
+ flag_dd_option = 1;
} else if (!strcmp (argv [i], "-cf")) {
if (++i == argc)
usage(use_noarg, argv[i-1]);
Після того, як перезібрали пакет та встановили його в системі, необхідно через rc.conf ввімкнути даний функціонал, додавши опцію ''-dd'' до параметрів запуску, наприклад:
dhcpd_flags="-q -dd"