Ubuntu as a Gateway
Contents
Tested on: Ubuntu 20.04
Обозначения:
$ timedatactl- запуск от пользователяroot> timedatactl- запуск от суперпользователяsome text- вывод программы#- комментарий...- пропуск не нужной информации
Сервер времени chrony
Установка часового пояса
$ sudo timedatectl status
$ sudo timedatectl list-timezones
$ sudo timedatectl set-timezone Europe/Moscow
$ ls -l /etc/localtime
lrwxrwxrwx 1 root root 35 апр 6 19:00 /etc/localtime -> ../usr/share/zoneinfo/Europe/MoscowУстановка и настройка chrony
Установим:
$ sudo apt install chronyПроверим, что запущен и работает:
$ sudo systemctl status chrony
$ sudo systemctl is-enabled chrony
$ sudo systemctl enable --now chronyРазбор параметров:
$ chronyc trackingReference ID- идентификатор и имя, с которым компьютер в настоящее время синхронизирован.Stratum- количество переходов к компьютеру с установленными основными часами.Ref time- это время по Гринвичу, в которое было выполнено последнее измерение из эталонного источника.System time- задержка системных часов от синхронизированного сервера.Last offset- расчетное смещение последнего обновления часов.RMS offset- долгосрочное среднее арифметическое значения смещения.Frequency- это частота, на которой часы системы будут работать неправильно, если хронограф не проведет - коррекцию. Она выражена в ppm - ч/м (частей на миллион).Residual freq- остаточная частота указывает на разницу между измерениями от опорного источника и используемой в настоящее время частотой.Skew- расчетная погрешность, связанная с погрешностью частоты.Root delay- суммарная задержка сетевого пути к опорному серверу, с которым синхронизируется компьютер.Leap status- это статус, который может иметь одно из следующих значений - нормальное, добавить второй, удалить второй или не синхронизироваться.
Получим информацию об источниках:
$ chronyc sources
# с комментариями :)
$ chronyc sources -vВыберем ближайшие сервера времени к нашему серверу и добавим их в конфиг:
$ sudo vi /etc/chrony/chrony.confПо-умолчанию chrony работает как клиент, чтобы работал как сервер времени добавим в конфигурационный файл разрешение с какими сетями можно работать:
allow 192.168.8.0/24
allow 172.16.8.0/24Если добавить просто
allow, тоchronyбудет отвечать всем. Подробнее об опциях здесь
Перезапустим демона:
$ sudo systemctl restart chronydПосмотрим логи chrony:
$ journalctl --unit=chronyНастройка сетевых интерфейсов
Есть 2 интерфейса, enp6s0 и enp7s0.
В enp7s0 будет подключен интернет, а в enp6s0 локальные сети.
$ ip -c a | grep enp -A 4
2: enp6s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 00:e0:4c:2a:3d:70 brd ff:ff:ff:ff:ff:ff
3: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 50:3e:aa:1f:6e:fc brd ff:ff:ff:ff:ff:ff
inet 192.168.3.54/24 brd 192.168.3.255 scope global dynamic enp7s0
valid_lft 76623sec preferred_lft 76623sec
inet6 fe80::523e:aaff:fe1f:6efc/64 scope link
valid_lft forever preferred_lft foreverНастроим интерфейсы с помощью netplan. Все конфигурационные файлы Netplan хранятся в директории /etc/netplan, имя файла может быть любым, расширение должно быть .yaml. Если файлов конфигурации несколько, то они обрабатываются в алфавитном порядке.
У меня получился такой конфиг:
$ sudo cat /etc/netplan/manual.yaml
network:
ethernets:
enp6s0:
dhcp4: false
addresses:
- 192.168.8.1/24
- 172.16.8.1/24
enp7s0:
dhcp4: true
nameservers:
addresses:
- 127.0.0.1
search:
- zavod.lan
version: 2
renderer: networkdТак же можно прописать статические маршруты в .yaml-файлах и настройки wi-fi. Куча примеров на офиц. сайте
Перед применением конфигурации, проверим её:
$ sudo netplan generateЕсли команда generate не выдала ничего, значит конфиг написан без ошибок.
Я удалил все автоматически сгенерированные файлы, оставил только свой.
Применить изменения можно либо командой netplan apply, либо netplan try, которая вернёт прежние настройки, если новые вы не подтвердите за 120 сек.
Теперь, подключив сетевой кабель, проверим адреса на сетевой карте:
$ ip -c a | grep enp -A 6
2: enp6s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:e0:4c:2a:3d:70 brd ff:ff:ff:ff:ff:ff
inet 192.168.8.1/24 brd 192.168.8.255 scope global enp6s0
valid_lft forever preferred_lft forever
inet 172.16.8.1/24 brd 172.16.8.255 scope global enp6s0
valid_lft forever preferred_lft forever
inet6 fe80::2e0:4cff:fe2a:3d70/64 scope link
valid_lft forever preferred_lft forever
3: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 50:3e:aa:1f:6e:fc brd ff:ff:ff:ff:ff:ff
inet 192.168.3.54/24 brd 192.168.3.255 scope global dynamic enp7s0
valid_lft 86518sec preferred_lft 86518sec
inet6 fe80::523e:aaff:fe1f:6efc/64 scope link
valid_lft forever preferred_lft forever
$ ip route
default via 192.168.3.1 dev enp7s0 proto dhcp src 192.168.3.54 metric 100
172.16.8.0/24 dev enp6s0 proto kernel scope link src 172.16.8.1
192.168.3.0/24 dev enp7s0 proto kernel scope link src 192.168.3.54
192.168.3.1 dev enp7s0 proto dhcp scope link src 192.168.3.54 metric 100
192.168.8.0/24 dev enp6s0 proto kernel scope link src 192.168.8.1Настройка dns (bind)
Устанавливаем необходимое:
$ sudo apt install bind9 bind9utils bind9-doc bind9-hostВерсия с доп. информацией:
$ named -VВ Ubuntu 20.04 пакет bind использует корневые сервера из /usr/share/dns/root.hints, вместо db.root
Добавим в автозагрузку и запустим:
$ sudo systemctl enable bind9
$ sudo systemctl start bind9Bind работает от пользователя bind:bind, который создался автоматически во время установки.
В основном используется udp/53, но так же и tcp/53 используется для больших ответов сервера и для передачи зоны.
Посмотрим, запустился ли:
$ sudo lsof -i -P -n | grep bind-Pпараметр указывает показывать номера портов-nпараметр указывает показывать ip-адреса
Для управления используется rndc, подключается к TCP-порту 953:
$ sudo rndc status
...
server is up and runningДля описания своих зон нужно использовать файл
/etc/bind/named.conf.local, а для настройки bind -/etc/bind/named.conf.options.
DNS-resolver
Посмотрим какой используется resolver в системе:
$ sudo systemd-resolve --status
# or
$ sudo resolvectl statusЧтобы установить наш DNS-сервер как resolver по-умолчанию, необходимо добавить следующую строку в файл /etc/systemd/resolved.conf в секцию [Resolve]:
$ cat /etc/systemd/resolved.conf
...
DNS=127.0.0.1
...Ну и нужно перезапустить:
$ sudo systemctl restart systemd-resolvedНаблюдаем в секции Global DNS Servers: 127.0.0.1:
$ sudo systemd-resolve --status | grep -i "DNS Servers" -B 8
Global
LLMNR setting: no
MulticastDNS setting: no
DNSOverTLS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNS Servers: 127.0.0.1
--
Link 3 (enp7s0)
Current Scopes: DNS
DefaultRoute setting: yes
LLMNR setting: yes
MulticastDNS setting: no
DNSOverTLS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNS Servers: 127.0.0.1Ещё посмотрим на файл:
$ cat /etc/resolv.conf
nameserver 127.0.0.53
search lan
options edns0 trust-adИсправим, чтобы указывало на наш dns-server:
$ sudo apt install resolvconf
$ sudo systemctl enable named-resolvconf.service
$ sudo systemctl start named-resolvconf.serviceПроверим, что теперь указывает на наш dns-server:
$ cat /etc/resolv.conf
nameserver 127.0.0.1
search lan
options edns0 trust-adПосмотреть логи можно 2мя способами:
$ sudo journalctl -e --unit=named
$ sudo journalctl -xe | grep namedНастройка dns-зон
Вот так выглядят конфиг-файлы.
Конфиг-файл настроек bind:
/etc/bind/named.conf.options
$ sudo cat /etc/bind/named.conf.options
acl "lan" {
192.168.8.0/24;
172.16.8.0/24;
localhost;
};
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
forwarders {
1.1.1.1;
8.8.8.8;
8.8.4.4;
};
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
auth-nxdomain no;
listen-on { lan; };
listen-on-v6 { none; };
recursion yes;
allow-recursion { lan; };
allow-query { lan; };
version "NOT CURRENTLY AVAILABLE";
querylog yes;
};Файл для описания зон. Тут умышленно выдаём неправильный адрес для имени vk.com:
ВНИМАНИЕ! Стандартный путь хранения dns зон
/var/lib/bind/
/etc/bind/named.conf.local
$ cat /etc/bind/named.conf.local
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
zone "vk.com" { type master; notify no; file "/etc/bind/db.127"; };
zone "zavod.lan" {
type master;
file "/etc/bind/dynamic/zavod.lan";
notify no;
};
zone "8.168.192.in-addr.arpa" {
type master;
file "/etc/bind/dynamic/8.168.192.in-addr.arpa";
notify no;
};
zone "8.16.172.in-addr.arpa" {
type master;
file "/etc/bind/dynamic/8.16.172.in-addr.arpa";
notify no;
};Сами файлы зон. @ означает имя из строки zone "zavod.lan" в файле /usr/bind/named.conf.local.
/etc/bind/dynamic/zavod.lan
$ sudo cat /etc/bind/dynamic/zavod.lan
$TTL 604800
@ IN SOA puma.zavod.lan. root.localhost. (
13 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name Server Information
; @ = name of zone from named.conf.local
@ IN NS ns1.zavod.lan.
@ IN NS ns2.zavod.lan.
; IP address of Name Server
ns1 IN A 192.168.8.1
ns2 IN A 172.16.8.1
; Mail Exchanger
; zavod.lan. IN MX 10 mail.zavod.lan.
; A – Record HostName To Ip Address
puma IN A 192.168.8.1
router IN A 192.168.8.1
www IN A 192.168.8.88
wind IN A 172.16.8.88
; CNAME record
ftp IN CNAME www.zavod.lan./etc/bind/dynamic/8.168.192.in-addr.arpa
$ sudo cat /etc/bind/dynamic/8.168.192.in-addr.arpa
;
; BIND reverse data file for local loopback interface
;
$TTL 604800
@ IN SOA puma.zavod.lan. root.localhost. (
5 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name Server Information
@ IN NS ns1.zavod.lan.
@ IN NS ns2.zavod.lan.
; Reverse lookup for Name Server
1 IN PTR ns1.zavod.lan.
;PTR Record IP address to HostName
88 IN PTR www.zavod.lan.
1 IN PTR puma.zavod.lan./etc/bind/dynamic/8.16.172.in-addr.arpa
$ sudo cat cat /etc/bind/dynamic/8.16.172.in-addr.arpa
;
; BIND reverse data file for local loopback interface
;
$TTL 604800
@ IN SOA puma.zavod.lan. root.localhost. (
5 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name Server Information
@ IN NS ns1.zavod.lan.
@ IN NS ns2.zavod.lan.
; Reverse lookup for Name Server
1 IN PTR ns2.zavod.lan.
;PTR Record IP address to HostName
88 IN PTR wind.zavod.lan.
1 IN PTR puma.zavod.lan.Вынесем логирование в отдельные файлы
Логи будут писаться в директорию /var/log/named, поэтому её необходимо создать и дать права пользователю bind писать в неё:
$ sudo mkdir /var/log/named
$ sudo chown bind:bind /var/log/namedseverity — указывает уровень логирования. Варианты: critical, error, warning, notice, info, debug, dynamic.
Теперь остаётся добавить в конфиг named следующие директивы:
/etc/bind/named.conf
cat <<- EOF | sudo tee --append /etc/bind/named.conf
logging {
channel "misc" {
// file "/var/lib/bind/misc.log" versions 4 size 4m;
file "/var/log/named/misc.log" versions 4 size 4m;
print-time YES;
print-severity YES;
print-category YES;
severity info;
};
channel "query" {
// file "/var/lib/bind/query.log" versions 4 size 4m;
file "/var/log/named/query.log" versions 4 size 4m;
print-time YES;
print-severity NO;
print-category NO;
severity info;
};
category default {
"misc";
};
category queries {
"query";
};
};
EOFПроверим настройки и перезапустим:
$ sudo named-checkconf /etc/bind/named.conf
$ sudo systemctl restart namedГотово, логи теперь здесь /var/log/named/ и в /var/log/syslog будет чище.
Настроим управление через утилиту rndc, а так же дадим возможность isc-dhcp-server обновлять dns-зоны.
Для этого нужно сгенерировать rndc.key, а так же добавить его в конфиги bind и isc-dhcp-server.
Сгенерируем rndc.key:
rndc-confgen -a
wrote key file "/etc/bind/rndc.keyДобавим rndc.key в /etc/bind/named.conf и проверим конфиг:
$ echo "include \"/etc/bind/rndc.key\";" | sudo tee --append /etc/bind/named.conf
include "/etc/bind/rndc.key";
$ sudo named-checkconfДобавим возможность управления только с localhost:
cat <<- EOF | tee --append /etc/bind/named.conf
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
EOF
$ sudo named-checkconfТак же в файлах зон named.conf.local нужно указать строку allow-update { key rndc-key; };, благодая ей будет возможно обновление файла через rndc.
$ cat /etc/bind/named.conf.local | grep -Ei "zone|allow-update"
// Consider adding the 1918 zones here, if they are not used in your
//include "/etc/bind/zones.rfc1918";
zone "vk.com" { type master; notify no; file "/etc/bind/db.127"; };
zone "zavod.lan" {
allow-update { key rndc-key; };
zone "8.168.192.in-addr.arpa" {
allow-update { key rndc-key; };
zone "8.16.172.in-addr.arpa" {
allow-update { key rndc-key; };Проверим, нет ли ошибок в конфигах и зонах:
$ sudo named-checkconf /etc/bind/named.conf
$ named-checkzone zavod.lan /etc/bind/dynamic/zavod.lan
zone zavod.lan/IN: loaded serial 13
OK
$ named-checkzone 8.16.172.in-addr.arpa /etc/bind/dynamic/8.16.172.in-addr.arpa
zone 8.16.172.in-addr.arpa/IN: loaded serial 5
OK
$ named-checkzone 8.168.192.in-addr.arpa /etc/bind/dynamic/8.168.192.in-addr.arpa
zone 8.168.192.in-addr.arpa/IN: loaded serial 5
OKЕсли ошибок нет, то нужно перезапустить демон named:
$ sudo systemctl restart namedТеперь настроим связь между named и isc-dhcp-server, чтобы при выдаче адреса, этот адрес записывался в зоны dns.
Стандартный путь для хранения зон это
/var/lib/bind. Если хранить их в другом месте, то нужно добавить эту папку вapparmorи дать права на запись.
Так как у меня зоны лежат в /etc/bind/dynamic, придётся в apparmor разрешить named право на запись.
Убедимся, что named присутствует:
$ sudo apparmor_status | grep named
/usr/sbin/named
/usr/sbin/named (4764)Добавим после /etc/bind/** r в файле /etc/apparmor.d/usr.sbin.named строку:
/etc/bind/dynamic/** rw,Сохраним файл и рестартнём apparmor:
$ sudo systemctl restart apparmorУстановим bind:bind на директорию /etc/bind/dynamic:
$ sudo chown -R bind:bind /etc/bind/dynamicТеперь нужно подправить конфиг isc-dhcp-server, как его готовить описано ниже.
После настройки isc-dhcp-server следует вернуться сюда и применить эти настройки. Нужно добавить в файл /etc/dhcp/dhcpd.conf следующее:
ddns-updates on;
ddns-update-style interim;
update-static-leases on;
# Содержимое файла ключа /etc/bind/rndc.key
# Лучше его подключить с помощью директивы include /etc/bind/rndc.key
key "rndc-key" {
algorithm hmac-sha256;
secret "6p6yC7XOWuSp3I66vfmfoy1LjoFIUKypcjp935AUILI=";
};
# Зоны которые должен обновлять сервер:
zone zavod.lan. {
primary 127.0.0.1;
key rndc-key;
}
zone 8.168.192.in-addr.arpa. {
primary 127.0.0.1;
key rndc-key;
}
zone 8.16.172.in-addr.arpa. {
primary 127.0.0.1;
key rndc-key;
}Проверим что всё верно и перезапустим демон:
$ sudo dhcpd -t
$ sudo systemctl restart isc-dhcp-serverТеперь, когда в локально сети появится новый компьютер, isc-dhcp-server выдаст ему свободный ip-адрес и обновит dns-зоны. При этом в каталоге рядом с зонами будут добавлены соответствующие файлы с расширением .jnl.
Работа с rndc
Для того, чтобы вручную изменить файлы зоны нужно приостановить динамическое обновление зон:
# убедимся, что всё синхонизировано, т.е. перенесём все временные данные из файла .jnl в файл зоны:
$ sudo rndc sync
# приостановим динамическое обновление
$ sudo rndc freeze zavod.lan
# либо приостановим обновление всех зон
$ sudo rndc freezeПосле ручной правки зоны нужно сначала перечитать файлы зон:
$ sudo rndc reloadА затем восстановить работу динамического обновления:
$ sudo rndc thaw zavod.lan
# или для всех зон:
$ sudo rndc thawМожет сложиться такая ситуация: На компьютере в локальной сети поменяли сетевую карту (изменился MAC-адрес), а запись с этим именем компьютера осталась в файле зон. Тогда нужно описанным выше способом удалить старую запись, а новая будет добавлена автоматически. Сообщения такого вида в логах подскажут о такой ситуации:
Apr 15 14:01:15 puma dhcpd[6253]: Forward map from ubuntu.zavod.lan to 172.16.8.94 FAILED: Has an address record but no DHCID, not mine.Сменим ip-address у компьютера в сети:
$ $ ip -c link show enp2s0
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 00:e0:4c:52:79:8f brd ff:ff:ff:ff:ff:ff
$ sudo ip link set enp2s0 address bc:47:3a:ba:ae:76
$ sudo ip -c a
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether bc:47:3a:ba:ae:76 brd ff:ff:ff:ff:ff:ff
inet 192.168.8.88/24 brd 192.168.8.255 scope global dynamic noprefixroute enp2s0
valid_lft 164sec preferred_lft 164sec
inet6 fe80::51dd:19a6:7e53:e9a9/64 scope link noprefixroute
valid_lft forever preferred_lft foreverПо истечении valid_lft 164sec isc-dhcp-server почему-то новый ip-address не удалось получить.
Получим вручную:
user@Q3:~$ sudo dhclient -r
user@Q3:~$ sudo dhclient enp2s0Настройка isc-dhcp-server
Как и всегда, примеры конфигурации можно посмотреть здесь:
$ ls /usr/share/doc/
$ cat /usr/share/doc/isc-dhcp-server/examples/dhcpd.conf.exampleУстановим dhcp-server и укажем интерфейс для работы:
$ sudo apt install isc-dhcp-server
$ echo "INTERFACESv4=\"enp6s0\"" | sudo tee --append /etc/default/isc-dhcp-serverУ меня получился вот такой конфиг:
/etc/dhcp/dhcpd.conf
$ sudo cat /etc/dhcp/dhcpd.conf
# option definitions common to all supported networks...
option domain-name "puma.local1";
option domain-name-servers 1.1.1.1, 8.8.8.8, 8.8.4.4;
# default-lease-time 600;
# max-lease-time 7200;
# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# This is a very basic subnet declaration.
#subnet 10.254.239.0 netmask 255.255.255.224 {
# range 10.254.239.10 10.254.239.20;
# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
#}
# This declaration allows BOOTP clients to get dynamic addresses,
# which we don't really recommend.
#subnet 10.254.239.32 netmask 255.255.255.224 {
# range dynamic-bootp 10.254.239.40 10.254.239.60;
# option broadcast-address 10.254.239.31;
# option routers rtr-239-32-1.example.org;
#}
# Чтобы сделать несколько разных подсетей нужно использовть shared-network sharedname:
shared-network mynetwork {
# Описание сети, указывающее какая из подсетей будет
# обслуживаться. Указывается сетевой адрес и маска сети
subnet 192.168.8.0 netmask 255.255.255.0 {
# диапазон адресов для клиентов
# 192.168.8.33-192.168.0.254
range 192.168.8.33 192.168.8.254;
# адрес DNS сервера, который будут использовать клиенты
option domain-name-servers ns1.puma.local1;
# устанавка домена по-умолчанию (dns-suffix)
option domain-name "local1";
# маска подсети для клиетов
option subnet-mask 255.255.255.0;
# маршрутизатор по умолчанию
option routers 192.168.8.1; # or router.puma.local1
# определяем широковещательный адрес
option broadcast-address 192.168.8.255;
# сказать клиентам, чтобы отдали адрес через 21600 секунд (6 часов)
# после получения адреса
default-lease-time 600;
# забрать адрес самому через 28800 секунд (8 часов)
max-lease-time 7200;
# адрес ntp-сервера
option ntp-servers ntp.local1;
server-identifier puma.local1;
# 3 опции для samba, если нужно обеспечить поддержку WINS:
# option netbios-name-servers 192.168.0.1;
# option netbios-dd-server 192.168.0.1;
# option netbios-node-type 8;
# Описания хостов
group test { # Чтобы не было: WARNING: Host declarations are global.
host q3 {
hardware ethernet 00:e0:5c:52:79:8f;
fixed-address 192.168.8.55;
# filename "vmunix.passacaglia";
# server-name "toccata.example.com";
}
}
}
subnet 172.16.8.0 netmask 255.255.255.0 {
# диапазон адресов для клиентов
# 192.168.8.33-192.168.0.254
range 172.16.8.33 172.16.8.254;
# адрес DNS сервера, который будут использовать клиенты
option domain-name-servers ns1.puma.local1;
# устанавка домена по-умолчанию (dns-suffix)
option domain-name "local2";
# маска подсети для клиетов
option subnet-mask 255.255.255.0;
# маршрутизатор по умолчанию
option routers 172.16.8.1; # or router.puma.local2
# определяем широковещательный адрес
option broadcast-address 172.16.8.255;
# сказать клиентам, чтобы отдали адрес через 21600 секунд (6 часов)
# после получения адреса
default-lease-time 100;
# default-lease-time 600;
# забрать адрес самому через 28800 секунд (8 часов)
max-lease-time 200;
# max-lease-time 7200;
# адрес ntp-сервера
option ntp-servers ntp.local2;
server-identifier puma.local2;
# 3 опции для samba, если нужно обеспечить поддержку WINS:
# option netbios-name-servers 192.168.0.1;
# option netbios-dd-server 192.168.0.1;
# option netbios-node-type 8;
# Описания хостов
group test { # Чтобы не было: WARNING: Host declarations are global.
host q32 {
hardware ethernet 00:e0:4c:52:79:8f;
fixed-address 172.16.8.88;
# filename "vmunix.passacaglia";
# server-name "toccata.example.com";
}
}
}
}По-умолчанию логи будут писаться в /var/log/syslog, можно вывести их в отдельный файл. Для этого нужно в конфиге включить опцию log-facility local7;, а так же добавить в конец файла /etc/rsyslog.d/50-default.conf:
local7.* /var/log/dhcpd.log
& stopИ перезапустить:
$ sudo systemctl restart rsyslogТеперь логи будут добавляться в /var/log/dhcpd.log, но они так же будут и туда, куда раньше: /var/log/syslog. Для отключения этого нужно изменить строку в файле /etc/rsyslog.d/50-default.conf c (1) на (2):
(1) *.*;auth,authpriv.none -/var/log/syslog
(2) *.*;auth,authpriv.none;local7.none -/var/log/syslogНу и перезапустить демон:
$ sudo systemctl restart rsyslogТестируем конфиг и смотрим где лежит lease-файл:
$ dhcpd -tЗапускаем службу:
$ sudo systemctl start isc-dhcp-serverСмотрим status службы, если не она запустилась, ответы здесь:
/var/log/syslog/var/log/dhcpd.log
Итак, dhcpd работает, можно посмотреть какие адреса выданы:
$ dhcp-lease-listЧтобы пересоздать lease-file, нужно удалить старый и перезапустить демон isc-dhcpd. Проверим
lease-файлна ошибки:
$ dhcpd -TНужно не забыть отключить isc-dhcp-server6, если он не используется!
После перезагрузки я вызвал
journalctl -bи обнаружил ошибку:Can't create PID file /run/dhcp-server/dhcpd.pid: No such file or directory., а так же ошибки о неудачном запускеisc-dhcp-server6. Проблема решилась отключениемdhcpdдляipv6:
sudo systemctl disable isc-dhcp-server6
Настройка ipset
ipset нужен для создания списков, которые потом можно использовать в правилах iptables.
Для начала установим:
$ sudo apt install ipsetВозможные типы списков:
net- сети, например 192.168.8.0/24ip- только ip, например 192.168.8.55mac- MAC адреса, например 11:22:33:44:55:66port- порты, удобно при создании списков ip,portiface- сетевые интерфейсы, удобно при создании списков ip,iface
Примеры создания списков, где mylist - имя списка:
$ sudo ipset -N mylist nethash
$ sudo ipset create mylist nethash
$ sudo ipset create mylist hash:net
$ sudo ipset create mylist hash:ip
$ sudo ipset create mylist hash:ip,port
$ sudo ipset create mylist hash:ip,iface
$ sudo ipset create mylist hash:macУдалить список:
$ sudo ipset destroy mylistДобавить данные в спискок, учтите, данные должены соответствовать тому, какой список был создан.
$ sudo ipset add mylist 192.168.5.5/24
$ sudo ipset add mylist 192.168.5.5
$ sudo ipset add mylist 192.168.5.5,80
$ sudo ipset add mylist 192.168.5.5,udp:1812
$ sudo ipset add mylist 192.168.5.5,eth0
$ sudo ipset add mylist 11:22:33:44:55:66Удалить элемент из списка:
$ sudo ipset del mylist 192.168.5.5Переименовать список:
$ sudo ipset rename OLDNAME NEWNAMEПосмотреть содержимое все или конкретного списка:
$ sudo ipset -L
$ sudo ipset --list
$ sudo ipset -L mylistИспользование списков в iptables:
$ sudo iptables -I INPUT -m set --match-set mylist src -j DROP
# или так
$ sudo iptables -I INPUT -m set ! --match-set mylist src -j ACCEPTЧтобы после перезагрузки настройки ipset не превратились в тыкву:
$ sudo ipset save -file /etc/ipset.conf
$ sudo ipset restore -file /etc/ipset.confОпишем systemd сервис, который будет подгружать настроки ipset после загрузки системы и инициализации сети:
cat <<- EOF | sudo tee /etc/systemd/system/ipset.service
[Unit]
Description=Service to start ipset rules
Before=network.target
Before=netfilter-persistent.service
Before=ufw.service
ConditionFileNotEmpty=/etc/ipset.conf
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ipset restore -file /etc/ipset.conf
ExecStop=/sbin/ipset flush
ExecStopPost=/sbin/ipset destroy
[Install]
WantedBy=multi-user.target
RequiredBy=netfilter-persistent.service
RequiredBy=ufw.service
EOF$ sudo systemctl daemon-reload
$ sudo systemctl list-unit-files | grep ipset
$ sudo systemctl is-enabled ipset.service
$ sudo systemctl enable ipset.serviceНастройка iptables
Схема прохожения и подробное описание работы здесь.
enp6s0- внутренний интерфейсenp7s0- внешний интерфейс
Чтоб посмотреть правила (по-умолчанию таблица filter):
$ sudo iptables -nvLДля конкретной таблицы:
$ sudo iptables -nvL -t raw
$ sudo iptables -nvL -t mangle
$ sudo iptables -nvL -t nat
$ sudo iptables -nvL -t filter
$ sudo iptables -nvL -t securityЧтобы обнулить настройки iptables:
$ sudo iptables --flush
$ sudo iptables --table nat --flush
$ sudo iptables --delete-chainВключим ip forwarding:
$ sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
# либо
$ sudo sysctl --write net.ipv4.ip_forward=1
# чтобы после перезагрузки работало:
$ echo "net.ipv4.ip_forward = 1" | sudo tee --append /etc/sysctl.confКлюч -A добавляет правило в конец цепочки, ключ -I в начало
sudo iptables -A FORWARD -i eth0 -o eth1 -s 192.168.8.0/24 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A POSTROUTING -t nat -j MASQUERADEСохраним правила:
$ sudo apt-get install iptables-persistent
$ sudo netfilter-persistent save
# или сохранить по пути:
$ sudo netfilter-persistent save > /etc/iptables/rules.v4Здесь всякие бинарники для управления iptables:
ls /usr/sbin/iptables-*
Восстановим правила:
$ sudo iptables-restore /etc/iptables/rules.v4Чтобы вывести список всех активных правил iptables по спецификации, выполните команду iptables с параметром -S:
$ sudo iptables -SНа этом базовая настрока iptables окончена.
Скрипт iptables.sh с комментариями.
iptables.sh
#!/bin/bash
# external
extif=enp7s0
extip="192.168.3.54"
# internal
intif=enp6s0
intip1="192.168.8.1"
intip2="172.16.8.1"
intlan1="192.168.8.0/24"
intlan2="172.16.8.0/24"
# lan obj
nginx="192.168.8.55:80"
slow="192.168.8.55"
echo " -> Очистим все правила"
iptables --flush
iptables --table nat --flush
iptables --table mangle --flush
iptables --delete-chain # удаляем все таблицы пользователя
echo " -> Установим политику по-умолчанию"
iptables --policy INPUT DROP
iptables --policy FORWARD ACCEPT
iptables --policy OUTPUT ACCEPT
echo " -> Разрешим loopback интерфейс"
iptables -A INPUT -i lo -j ACCEPT
# iptables -A OUTPUT -o lo -j ACCEPT
# --- PREROUTING
echo ""
echo " --- PREROUTING"
# echo " -> Маркируем соединение компа из локальной сети"
# iptables -t mangle -A PREROUTING -s "$slow" -j CONNMARK --set-xmark 12
#
# echo " -> Маркируем пакеты в соединении компа из локальной сети"
# iptables -t mangle -A PREROUTING -m mark --mark 12 -j MARK --set-mark 87
# echo " -> Маркируем трафик компа из локальной сети"
# iptables -t mangle -A PREROUTING -s "$slow" -j MARK --set-mark 87
echo " -> Прокинем трафик с внешнего ip на внутренний (dnat)"
iptables -t nat -A PREROUTING -d "$extip" -p tcp -m tcp --dport 80 -j DNAT --to-destination "$nginx"
# echo " -> Завернём весь icmp-трафик на себя"
# iptables -t nat -A PREROUTING -d 0/0 -p icmp -j DNAT --to-destination "$intip1"
# echo " -> Завернём весь трафик по 53 порту из сети на себя"
# iptables -t nat -A PREROUTING -d 0/0 -s "$intlan1" -p udp -m udp --dport 53 -j DNAT --to-destination "$intip1"
# iptables -t nat -A PREROUTING -d 0/0 -s "$intlan1" -p tcp -m tcp --dport 53 -j DNAT --to-destination "$intip1"
#
# iptables -t nat -A PREROUTING -d 0/0 -s "$intlan2" -p udp -m udp --dport 53 -j DNAT --to-destination "$intip1"
# iptables -t nat -A PREROUTING -d 0/0 -s "$intlan2" -p tcp -m tcp --dport 53 -j DNAT --to-destination "$intip1"
# --- INPUT
echo ""
echo " --- INPUT"
echo " -> Правило без действия, только для счётчика"
iptables -A INPUT -s 192.168.8.55/32 -p tcp --dport 22
echo " -> Разрешаем established, related"
iptables -A INPUT -i "$extif" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
echo " -> Запрещаем invalid трафик"
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
echo " -> Разрешаем входящий SSH"
iptables -A INPUT -i "$extif" -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
# Разрешаем icmp-traffic идущий из сети
# iptables -A INPUT -s "$intlan1" -p icmp -j ACCEPT
# iptables -A INPUT -s "$intlan2" -p icmp -j ACCEPT
# Разрешаем доступ к указанным портам только из локальной сети
# iptables -A INPUT -s "$intlan1" -p tcp -m multiport --dport 22,53 -m conntrack --ctstate NEW -j ACCEPT
# iptables -A INPUT -s "$intlan2" -p tcp -m multiport --dport 22,53 -m conntrack --ctstate NEW -j ACCEPT
# iptables -A INPUT -s "$intlan1" -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
# iptables -A INPUT -s "$intlan2" -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
echo " -> Разрешаем любой траффик из локальной сети куда угодно"
iptables -A INPUT -s "$intlan1" -p all -j ACCEPT
iptables -A INPUT -s "$intlan2" -p all -j ACCEPT
# Запрещаем остальные входящие соединения (если политика по-умолчанию не DROP) на внешний интерфес
# iptables -A INPUT -j DROP
# --- FORWARD
echo ""
echo " --- FORWARD"
# echo " -> Маркируем соединение компа (на скачивание) $slow из локальной сети"
# iptables -t mangle -A FORWARD -d "$slow" -j CONNMARK --set-mark 12
#
# echo " -> Маркируем пакеты в соединении 12"
# iptables -t mangle -A FORWARD -m connmark --mark 12 -j MARK --set-mark 87
#
# echo " -> Маркируем соединение компа (на выгруз) $slow из локальной сети"
# iptables -t mangle -A FORWARD -s "$slow" -j CONNMARK --set-mark 13
#
# echo " -> Маркируем пакеты в соединении 13"
# iptables -t mangle -A FORWARD -m connmark --mark 13 -j MARK --set-mark 88
echo " -> Маркируем соединения из списка garant15peak30 (на скачивание) из локальной сети на ресурс vk.com (выполнится dns-запрос и в правила попадут ip адреса vk)"
iptables -t mangle -A FORWARD -m set --match-set garant15peak30 dst -s vk.com -j CONNMARK --set-mark 12
echo " -> Маркируем пакеты в соединении 12"
iptables -t mangle -A FORWARD -m connmark --mark 12 -j MARK --set-mark 87
echo " -> Маркируем соединения из списка garant15peak30 (на выгруз) из локальной сети на ресурс vk.com (выполнится dns-запрос и в правила попадут ip адреса vk)"
iptables -t mangle -A FORWARD -m set --match-set garant15peak30 src -d vk.com -j CONNMARK --set-mark 13
echo " -> Маркируем пакеты в соединении 13"
iptables -t mangle -A FORWARD -m connmark --mark 13 -j MARK --set-mark 88
echo " -> Маркируем исходящие соединения ip-телефонов Yealink SIP-T21 (default 46)"
iptables -t mangle -A FORWARD -m dscp --dscp 46 -j CONNMARK --set-mark 15
echo " -> Маркируем пакеты в соединении 15"
iptables -t mangle -A FORWARD -m connmark --mark 15 -j MARK --set-mark 90
echo " -> Маркируем входящие соединения ip-телефонов Yealink SIP-T21 (default 46)"
iptables -t mangle -A FORWARD -m dscp --dscp 46 -j CONNMARK --set-mark 16
echo " -> Маркируем пакеты в соединении 16"
iptables -t mangle -A FORWARD -m connmark --mark 16 -j MARK --set-mark 91
echo " -> Для теста можно установить dscp на клиенте, например:"
echo " -> $ sudo iptables -t mangle -A OUTPUT -j DSCP --set-dscp 46"
echo " -> Разрешаем уже установленные и связанные транзитные соединения WAN -> LAN"
iptables -A FORWARD -i "$extif" -o "$intif" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
echo " -> Запрещаем invalid трафик"
iptables -A FORWARD -m conntrack --ctstate INVALID -j DROP
# echo " -> Разрешим весь dnat-трафик"
# iptables -A FORWARD -i "$extif" -o "$intif" -m conntrack --ctstate DNAT -j ACCEPT
echo " -> Разрешим dnat-трафик на $nginx:80 внутрь сети"
iptables -A FORWARD -i "$extif" -o "$intif" -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
echo " -> Запрещаем остальные транзитные соединения WAN -> LAN"
iptables -A FORWARD -i "$extif" -o "$intif" -j DROP
echo " -> Разрешаем LAN -> WAN для локальных сетей"
iptables -A FORWARD -i "$intif" -o "$extif" -s "$intlan1","$intlan2" -p all -j ACCEPT
echo " -> Разрешаем трафик из $intlan1 в $intlan2"
iptables -A FORWARD -s "$intlan1" -d "$intlan2" -p all -j ACCEPT
echo " -> Разрешаем трафик из $intlan2 в $intlan1"
iptables -A FORWARD -s "$intlan2" -d "$intlan1" -p all -j ACCEPT
echo " -> Запрещаем весь проходящий трафик (можно просто политику DROP поставить)"
iptables -A FORWARD -j DROP
# --- OUTPUT
echo ""
echo " --- OUTPUT"
echo " -> Запрещаем invalid трафик"
iptables -A OUTPUT -m conntrack --ctstate INVALID -j DROP
# --- POSTROUTING
echo ""
echo " --- POSTROUTING"
echo " -> Прокинем трафик из локальной сети наружу (snat)"
# iptables -A POSTROUTING -t nat -o "$extif" -m conntrack --ctstate NEW -j MASQUERADE
iptables -t nat -A POSTROUTING -s "$intlan1" -d 0/0 -o "$extif" -m conntrack --ctstate NEW -j SNAT --to-source "$extip"
iptables -t nat -A POSTROUTING -s "$intlan2" -d 0/0 -o "$extif" -m conntrack --ctstate NEW -j SNAT --to-source "$extip"Шейпинг трафика
Описание(htb.init):
При помощи шейпинга мы можем управлять только исходящим из интерфейса трафиком. Тут возникает проблема с nat. Если нам нужно шейпировать трафик и натить на том же роутере, то в правилах нужно использовать MARK, чтобы маркировать пакеты, а затем использовать маркированные пакеты при шейпинге.
Общий алгоритм:
- Создаём корневую дисциплину для каждого интерфейса и указываем класс, куда будет попадать не классифицированный трафик
- Создаём корневой класс и устанавливаем ширину канала
- Создаём дочерний класс для абонента
- Создаём дисциплину шейпирования класса абонента
- Создаём фильтры, для определения трафика абонента
Например, есть 2 интерфейса:
$intif(enp6s0)- внутренний интерфейс$extif(enp7s0)- внешний интерфейс
Для компьютера внутри сети скорость скачивания нужно резать на $intif, а скорость отдачи на $extif.
Описание параметров:
rate- гарантированная полоса пропусканияceil- максимальная полоса которую может получить данный класс
rate не может быть больше ceil Параметры rate и ceil для корневого класса должны совпадать. Таким образом мы определяем общую полосу пропускания. Сумма rate’ов классов-потомков, не должна превышать rate родительского класса. Идентификаторы классов в пределах интерфейса должны быть уникальны.
Каждый конфигурационный файл описывает очередь, это заложено в самом названии файла, которое имеет формат:
$HTB_PATH/<ifname>-<clsid>(:<clsid>).<description>clsid- задается цифровыми значениями от 0x2 до 0xFFFF (записывается без приставки 0x)
Сам интерфейс описывается файлом только с именем
ifname. Напримерeth0и имеет идентификатор классаclsid=0.
-
eth0-2- основной (корневой) класс сclsid=2. -
eth0-2:3- класс очередиclsid=3, унаследует ограничения от родительскогоclsid=2. -
eth0-2:3:4- класс очередьclsid=4, унаследует ограничения от родительскогоclsid=3и 2, т.е. накладываются ее более жесткие ограничения. -
DEFAULT=30- указывает номер класса, куда попадает трафик не попавший ни под одно правило. Класс ‘по умолчанию’ задается без правила RULE (но это не значит, что туда будет автоматом попадать все, наоборот, в эту очередь ничего не пойдет). default 0 -
R2Q=100- точность шейпера. default 10
Точность 10 хороша для скорости 5-500kbps и должга быть увеличена, для больших скоростей.
-
DCACHE=no- Не знаешь не трогай. default “no” -
RATE=5Mbit- выделенная (гарантированная) пропускная способность очереди, задается в Kbit, Mbit или bps (bytes per second) -
CEIL=6MBit- максимальная пропускная способность очереди. default CEIL=RATE -
BURST=<bytes>- default computed -
CBURST=<bytes>- default computed -
PRIO=<number>- приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0 -
LEAF=none- правило распределения внутри самой очереди. default “none” -
LEAF=sfq- равномерное распределение между участниками очереди.
Возможные варианты LEAF=none|sfq|pfifo|bfifo optional, default “none”
-
MTU=<bytes>- default “1600” -
RULE=- правила, определяющий трафик, который должен проходить через данную очередь. В одном файле могут присутствовать сразу несколько правил.
RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]Если трафик попадает по условиям в очередь -2:10 (например, где правило задано по маске), то дальше он уже не будет проверять условия в -2:20 (где допустим будет описано правило с конкретно этим ip), -2:30 и т.д.
MARK=101: трафик имеющий метку. Метим в таблице mangle, либо в PRERIUTING, либо в FORWARD выше исключающих этот трафик правил.
$ sudo iptables -t mangle -A PREROUTING -s 192.168.8.55 -j MARK --set-mark 101
$ sudo iptables -t mangle -A PREROUTING -s 192.168.8.55 -j RETURNTIME- временные параметры
TIME=[<dow><dow>.../]<from>-<till>;<rate>[/<burst>][,<ceil>[/<cburst>]]
TIME=60123/18:00-06:00;256Kbit/10Kb,384Kbit
TIME=18:00-06:00;256KbitREALM=[srealm,][drealm]- именное обозначение направлений
REALM=russia,internetПример 1
- Скачаем htb.init, положить сюда
/usr/sbin/htb.initи дать права:
$ sudo chmod u+x /sbin/htb.init- Создадим директорию для конфигов:
$ sudo mkdir -p /etc/sysconfig/htbПри запуске, кэш будет храниться в этом файле:
/var/cache/htb.init
- Создадим конфиги для входящего трафика
$intif(enp6s0):
- Общий для $intif(enp6s0):
# cat << EOF > enp6s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
EOF- Корневой класс для исходящей ширины канала:
# cat << EOF > enp6s0-2.root
RATE=100Mbit # гарантированная пропускная способность
CEIL=1000Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
EOF- Дочерний класс для ограничения скорости пакетов, маркированных 87
# cat << EOF > enp6s0-2:30.MARK87
RATE=512Kbit # гарантированная пропускная способность
CEIL=512Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF- Класс для ограничения скорости по-умолчанию:
# cat << EOF > enp6s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOFПерезапускаем скрипт:
$ sudo htb.init restartМаркированные пакеты будут замедлены до 512Kbit, не маркированные до 10Mbit, убедимся (запуск с клиента):
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -R -P 1- Теперь займёмся исходящим трафиком $extif(enp7s0). Все классы создаются аналогично:
# cat << EOF > enp7s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
EOF# cat << EOF > enp7s0-2.root
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
EOF# cat << EOF > enp7s0-2:30.MARK88
RATE=4Mbit # гарантированная пропускная способность
CEIL=4Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=88 # применять правило для пакетов, маркированных меткой 87
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF# cat << EOF > enp7s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF- Перезапустим правила управления трафиком:
$ sudo /sbin/htb.init restartПроверяем с клиента:
$ iperf3 -c speedtest.studiofunk.de -p 5200Пример 2.
Выделить пропускную полосу 512Кбит/с для локального клиента 192.168.8.55. На сервере-шлюзе 2 интерфейса:
$intif(enp6s0)- внутренний интерфейс$extif(enp7s0)- внешний интерфейс
Создаём файлы с соответствующим содержимым:
# cat << EOF > enp6s0
DEFAULT=30
R2Q=100
EOF# cat << EOF > enp6s0-2.root
# Скорость корневого класса 100Мбит, так как других классов тут не будет
RATE=100Mbit
EOF# cat << EOF > enp6s0-2:10.local
# Правило для локального трафика
RATE=1Kbit
CEIL=100Mbit
LEAF=sfq
# Если из локальной сети обращаются по внутреннему адресу к шлюзу, не ограничивать
RULE=192.168.0.0/24,192.168.0.0/24
# Если из локальной сети обращаются по внешнему адресу к шлюзу, не ограничивать
RULE=82.24.110.14/32,192.168.0.0/24
PRIO=10
EOF# cat << EOF > enp6s0-2:20.voip
# Гарантированная скорость 512Кbit, для трафика проходящего к 192.168.0.200
RATE=512Kbit
CEIL=2Mbit
LEAF=sfq
RULE=*,192.168.0.200
PRIO=1
EOF# cat << EOF > enp6s0-2:30.all
# Правило по умолчанию. Оставшийся трафик будет интернет трафиком.
RATE=1Kbit
CEIL=1536Kbit
LEAF=sfq
PRIO=10
EOFПрименим:
sudo htb.init compile # тест. можно посмотреть какие правила будут сформированы и ошибки, если есть.
sudo htb.init start # запуск
sudo htb.init stop # остановка
sudo htb.init restart # перезапуск после внесения изменений в файлы конфигурацииИзмерим скорость на удалённом сервере. Если клиент в сети отдаёт:
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -P 5
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -P 1Если клиент в сети принимает:
$ sudo iperf3 -R -c speedtest.hostkey.ru -p 5200 -P 1Поднять свой сервер:
sudo iperf3 -s -p 5001Перед проверкой нужно убедиться что порт в цепочке INPUT открыт.
Текущие конфиги:
enp6s0- внутренний интерфейсenp7s0- внешний интерфейс
enp6s0:
# $ cat enp6s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений# $ cat enp6s0-2.root
RATE=100Mbit # гарантированная пропускная способность
CEIL=1000Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений# $ cat enp6s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми# $ cat enp6s0-2:30.MARK87
RATE=512Kbit # гарантированная пропускная способность
CEIL=512Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
# PRIO=20 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0$ cat enp6s0-2:40.MARK90
RATE=2Mbit # гарантированная пропускная способность
CEIL=2Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=90 # применять правило для пакетов, маркированных меткой 90
# PRIO=10 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0enp7s0:
# $ cat enp7s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений# $ cat enp7s0-2.root
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений# $ cat enp7s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
# $ cat enp7s0-2:30.MARK88
RATE=64Kbit # гарантированная пропускная способность
CEIL=64Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=88 # применять правило для пакетов, маркированных меткой 87
# PRIO=20 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0
# $ cat enp7s0-2:40.MARK91
RATE=2Mbit # гарантированная пропускная способность
CEIL=2Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=91 # применять правило для пакетов, маркированных меткой 91
# PRIO=10 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0
htb.initсоздаёт файл конфигурации и хранит его в/var/cache/htb.init
Чтобы не было ругани на maxdepth изменим скрипт:
$ diff /usr/sbin/htb.init htb.init-v0.8.5
471,472c471,472
< find $HTB_PATH -maxdepth 1 \( -type f -or -type l \) \
< -name "$dev-*" -not -name '*~' \
---
> find $HTB_PATH \( -type f -or -type l \) \
> -name "$dev-*" -not -name '*~' -maxdepth 1 \
486,487c486,487
< [ `find $HTB_PATH -maxdepth 1 \( -type f -or -type l \) \
< -name "$dev*" -newer $HTB_CACHE| \
---
> [ `find $HTB_PATH \( -type f -or -type l \) \
> -name "$dev*" -maxdepth 1 -newer $HTB_CACHE| \
496c496
< [ `find $HTB_PATH -maxdepth 1 -type f -name "$1*" \
---
> [ `find $HTB_PATH -type f -name "$1*" -maxdepth 1 \Файл systemd для запуска демона:
systemctl cat htb.init.service
# /etc/systemd/system/htb.init.service
[Unit]
Description=Service to start htb.init rules
After=network.target
[Service]
user=root
group=root
Type=oneshot
RemainAfterExit=yes
ExecStart=htb.init start
ExecStop=htb.init stop
[Install]
WantedBy=default.target
RequiredBy=netfilter-persistent.service
RequiredBy=ufw.serviceСам файл htb.init:
htb.init:
#!/bin/bash
#
# htb.init v0.8.5
# Copyright (C) 2002-2004 Lubomir Bulej <pallas@kadan.cz>
#
# chkconfig: 2345 11 89
# description: script to set up HTB traffic control
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# To get the latest version, check on Freshmeat for actual location:
#
# http://freshmeat.net/projects/htb.init
#
#
# VERSION HISTORY
# ---------------
# v0.8.5- Nathan Shafer <nicodemus at users.sourceforge.net>
# - allow symlins to class files
# - Seth J. Blank <antifreeze at users.sourceforge.net>
# - replace hardcoded ip/tc location with variables
# - Mark Davis <mark.davis at gmx.de>
# - allow setting of PRIO_{MARK,RULE,REALM} in class file
# v0.8.4- Lubomir Bulej <pallas at kadan.cz>
# - fixed small bug in RULE parser to correctly parse
# rules with identical source and destination fields
# - removed the experimental INJECT keyword
# - ignore *~ backup files when looking for classes
# - Mike Boyer <boyer at administrative.com>
# - fix to allow arguments to be passed to "restart" command
# - <face at pos.sk>
# - fix to preserve class priority after timecheck
# v0.8.3- Lubomir Bulej <pallas at kadan.cz>
# - use LC_COLLATE="C" when sorting class files
# - Paulo Sedrez
# - fix time2abs to allow hours with leading zero in TIME rules
# v0.8.2- Lubomir Bulej <pallas at kadan.cz>
# - thanks to Hasso Tepper for reporting the following problems
# - allow dots in interface names for use with VLAN interfaces
# - fixed a thinko resulting from "cosmetic overdosage" :)
# v0.8.1- Lubomir Bulej <pallas at kadan.cz>
# - added function alternatives for sed/find with less features. To
# enable them, you need to set HTB_BASIC to nonempty string.
# - added posibility to refer to RATE/CEIL of parent class when
# setting RATE/CEIL for child class. Look for "prate" or "pceil"
# in the documentation.
# - fixed broken "timecheck" invocation
# v0.8 - Lubomir Bulej <pallas at kadan.cz>
# - simplified and converted CBQ.init 0.7 into HTB.init
# - changed configuration file naming conventions
# - lots of HTB specific changes
#
#
# INTRODUCTION
# ------------
#
# This script is a clone of CBQ.init and is meant to simplify setup of HTB
# based traffic control. HTB setup itself is pretty simple compared to CBQ,
# so the purpose of this script is to allow the administrator of large HTB
# configurations to manage individual classes using simple, human readable
# files.
#
# The "H" in HTB stands for "hierarchical", so while many people did not use
# (or know about) the possibility to build hierarchical structures using
# CBQ.init, it should be obvious thing to expect from HTB.init :-)
#
# In HTB.init this is done differently, compared to CBQ.init: the usage of
# PARENT keyword was dropped and instead, class file naming convetion was
# introduced. This convention allows the child class to determine ID of its
# parent class from the filename and also (if not abused :) enforces file
# ordering so that the parent classes are created before their children.
#
# HTB.init uses simple caching mechanism to speed up "start" invocation if the
# configuration is unchanged. When invoked for the first time, it compiles the
# configuration files into simple shell script containing the sequence of "tc"
# commands required to setup the traffic control. This cache-script is stored
# in /var/cache/htb.init by default and is invalidated either by presence of
# younger class config file, or by invoking HTB.init with "start invalidate".
#
# If you want to HTB.init to setup the traffic control directly without the
# cache, invoke it with "start nocache" parameters. Caching is also disabled
# if you have logging enabled (ie. HTB_DEBUG is not empty).
#
# If you only want HTB.init to translate your configuration to "tc" commands,
# invoke it using the "compile" command. Bear in mind that "compile" does not
# check if the "tc" commands were successful - this is done (in certain places)
# only when invoked with "start nocache" command. When you are testing your
# configuration, you should use it to check whether it is completely valid.
#
# In case you are getting strange sed/find errors, try to uncomment line with
# HTB_BASIC setting, or set the variable to nonempty string. This will enable
# function alternatives which require less advanced sed/find functionality. As
# a result, the script will run slower but will probably run. Also the caching
# will not work as expected and you will have to invalidate the cache manually
# by invoking HTB.init with "start invalidate".
#
#
# CONFIGURATION
# -------------
#
# Every traffic class is described by a single file in placed in $HTB_PATH
# directory, /etc/sysconfig/htb by default. The naming convention is different
# compared to CBQ.init. First notable change is missing 'htb-' prefix. This
# was replaced by interface name to improve human readability and to separate
# qdisc-only configuration.
#
# Global qdisc options are placed in $HTB_PATH/<ifname>, where <ifname> is
# (surprisingly) name of the interface, made of characters and numbers. This
# file must be present if you want to setup HTB on that interface. If you
# don't have any options to put into it, leave it empty, but present.
#
# Class options belong to files with names matching this expression:
# $HTB_PATH/<ifname>-<clsid>(:<clsid>)*<description>
#
# <clsid> is class ID which is hexadecimal number in range 0x2-0xFFFF, without
# the "0x" prefix. If a colon-delimited list of class IDs is specified, the
# last <clsid> in the list represents ID of the class in the config file.
#
# <clsid> preceding the last <clsid> is class ID of the parent class. To keep
# ordering so that parent classes are always created before their children, it
# is recommended to include full <clsid> path from root class to the leaf one.
#
# <description> is (almost) arbitrary string where you can put symbolic
# class names for better readability.
#
# Examples of valid names:
#
# eth0-2 root class with ID 2, on device eth0
# eth0-2:3 child class with ID 3 and parent 2, on device eth0
# eth0-2:3:4 child class with ID 4 and parent 3, on device eth0
# eth1-2.root root class with ID 2, on device eth1
#
#
# The configuration files may contain the following parameters. For detailed
# description of HTB parameters see http://luxik.cdi.cz/~devik/qos/htb.
#
### HTB qdisc parameters
#
# The following parameters apply to HTB root queuening discipline only and
# are expected to be put into $HTB_PATH/<ifname> files. These files must
# exist (even empty) if you want to configure HTB on given interface.
#
# DEFAULT=<clsid> optional, default 0
# DEFAULT=30
#
# <dclsid> is ID of the default class where UNCLASSIFIED traffic goes.
# Unlike HTB qdisc, HTB.init uses 0 as default class ID, which is
# internal FIFO queue that will pass packets along at FULL speed!
#
# If you want to avoid surprises, always define default class and
# allocate minimal portion of bandwidth to it.
#
# R2Q=<number> optional, default 10
# R2Q=100
#
# This allows you to set coefficient for computing DRR (Deficit
# Round Robin) quanta. The default value of 10 is good for rates
# from 5-500kbps and should be increased for higher rates.
#
# DCACHE=yes|no optional, default "no"
#
# This parameters turns on "dequeue cache" which results in degraded
# fairness but allows HTB to be used on very fast network devices.
# This is turned off by default.
#
### HTB class parameters
#
# The following are parameters for HTB classes and are expected
# to be put into $HTB_PATH/<ifname>-<clsid>(:<clsid>)*.* files.
#
# RATE=<speed>|prate|pceil mandatory
# RATE=5Mbit
#
# Bandwidth allocated to the class. Traffic going through the class is
# shaped to conform to specified rate. You can use Kbit, Mbit or bps,
# Kbps and Mbps as suffices. If you don't specify any unit, bits/sec
# are used. Also note that "bps" means "bytes per second", not bits.
#
# The "prate" or "pceil" values will resolve to RATE or CEIL of parent
# class. This feature is meant to help humans to keep configuration
# files consistent.
#
# CEIL=<speed>|prate|pceil optional, default $RATE
# CEIL=6MBit
#
# The maximum bandwidth that can be used by the class. The difference
# between CEIL and RATE amounts to bandwidth the class can borrow, if
# there is unused bandwidth left.
#
# By default, CEIL is equal to RATE so the class cannot borrow bandwidth
# from its parent. If you want the class to borrow unused bandwidth, you
# must specify the maximal amount it can use, if available.
#
# When several classes compete for the unused bandwidth, each of the
# classes is given share proportional to their RATE.
#
# BURST=<bytes> optional, default computed
# BURST=10Kb
#
# CBURST=<bytes> optional, default computed
# CBURST=2Kb
#
# BURST and CBURST parameters control the amount of data that can
# be sent from one class at maximum (hardware) speed before trying
# to service other class.
#
# If CBURST is small (one packet size) it shapes bursts not to
# exceed CEIL rate the same way PEAK works for TBF.
#
# PRIO=<number> optional, default 0
# PRIO=5
#
# Priority of class traffic. The higher the number, the lesser the
# priority. Also, classes with higher priority are offered excess
# bandwidth first.
#
# LEAF=none|sfq|pfifo|bfifo optional, default "none"
#
# Tells the script to attach specified leaf queueing discipline to HTB
# class. By default, no leaf qdisc is used.
#
# If you want to ensure (approximately) fair sharing of bandwidth among
# several hosts in the same class, you should specify LEAF=sfq to attach
# SFQ as leaf queueing discipline to the class.
#
# MTU=<bytes> optional, default "1600"
#
# Maximum packet size HTB creates rate maps for. The default should
# be sufficient for most cases, it certainly is for Ethernet.
#
### SFQ qdisc parameters
#
# The SFQ queueing discipline is a cheap way to fairly share class bandwidth
# among several hosts. The fairness is approximate because it is stochastic,
# but is not CPU intensive and will do the job in most cases. If you desire
# real fairness, you should probably use WRR (weighted round robin) or WFQ
# queueing disciplines. Note that SFQ does not do any traffic shaping - the
# shaping is done by the HTB class the SFQ is attached to.
#
# QUANTUM=<bytes> optional, qdisc default
#
# Amount of data in bytes a stream is allowed to dequeue before next
# queue gets a turn. Defaults to one MTU-sized packet. Do not set
# this parameter below the MTU!
#
# PERTURB=<seconds> optional, default "10"
#
# Period of hash function perturbation. If unset, hash reconfiguration
# will never take place which is what you probably don't want. The
# default value of 10 seconds is probably a good value.
#
### PFIFO/BFIFO qdisc parameters
#
# Those are simple FIFO queueing disciplines. They only have one parameter
# which determines their length in bytes or packets.
#
# LIMIT=<packets>|<bytes> optional, qdisc default
# LIMIT=1000
#
# Number of packets/bytes the queue can hold. The unit depends on
# the type of queue used.
#
### Filtering parameters
#
# RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]
#
# These parameters make up "u32" filter rules that select traffic for
# each of the classes. You can use multiple RULE fields per config.
#
# The optional port mask should only be used by advanced users who
# understand how the u32 filter works.
#
# Some examples:
#
# RULE=10.1.1.0/24:80
# selects traffic going to port 80 in network 10.1.1.0
#
# RULE=10.2.2.5
# selects traffic going to any port on single host 10.2.2.5
#
# RULE=10.2.2.5:20/0xfffe
# selects traffic going to ports 20 and 21 on host 10.2.2.5
#
# RULE=:25,10.2.2.128/26:5000
# selects traffic going from anywhere on port 50 to
# port 5000 in network 10.2.2.128
#
# RULE=10.5.5.5:80,
# selects traffic going from port 80 of single host 10.5.5.5
#
#
#
# REALM=[srealm,][drealm]
#
# These parameters make up "route" filter rules that classify traffic
# according to packet source/destination realms. For information about
# realms, see Alexey Kuznetsov's IP Command Reference. This script
# does not define any realms, it justs builds "tc filter" commands
# for you if you need to classify traffic this way.
#
# Realm is either a decimal number or a string referencing entry in
# /etc/iproute2/rt_realms (usually).
#
# Some examples:
#
# REALM=russia,internet
# selects traffic going from realm "russia" to realm "internet"
#
# REALM=freenet,
# selects traffic going from realm "freenet"
#
# REALM=10
# selects traffic going to realm 10
#
#
#
# MARK=<mark>
#
# These parameters make up "fw" filter rules that select traffic for
# each of the classes accoring to firewall "mark". Mark is a decimal
# number packets are tagged with if firewall rules say so. You can
# use multiple MARK fields per config.
#
#
# Note: Rules for different filter types can be combined. Attention must be
# paid to the priority of filter rules, which can be set below through
# the PRIO_{RULE,MARK,REALM} variables.
#
### Time ranging parameters
#
# TIME=[<dow><dow>.../]<from>-<till>;<rate>[/<burst>][,<ceil>[/<cburst>]]
# TIME=60123/18:00-06:00;256Kbit/10Kb,384Kbit
# TIME=18:00-06:00;256Kbit
#
# This parameter allows you to change class bandwidth during the day or
# week. You can use multiple TIME rules. If there are several rules with
# overlapping time periods, the last match is taken. The <rate>, <burst>,
# <ceil> and <cburst> fields correspond to parameters RATE, BURST, CEIL
# and CBURST.
#
# <dow> is single digit in range 0-6 and represents day of week as
# returned by date(1). To specify several days, just concatenate the
# digits together.
#
#
#
# TRIVIAL EXAMPLE
# ---------------
#
# Consider the following example:
# (taken from Linux Advanced Routing & Traffic Control HOWTO)
#
# You have a Linux server with total of 5Mbit available bandwidth. On this
# machine, you want to limit webserver traffic to 5Mbit, SMTP traffic to 3Mbit
# and everything else (unclassified traffic) to 1Kbit. In case there is unused
# bandwidth, you want to share it between SMTP and unclassified traffic.
#
# The "total bandwidth" implies one top-level class with maximum bandwidth
# of 5Mbit. Under the top-level class, there are three child classes.
#
# First, the class for webserver traffic is allowed to use 5Mbit of bandwidth.
#
# Second, the class for SMTP traffic is allowed to use 3Mbit of bandwidth and
# if there is unused bandwidth left, it can use it but must not exceed 5Mbit
# in total.
#
# And finally third, the class for unclassified traffic is allowed to use
# 1Kbit of bandwidth and borrow unused bandwith, but must not exceed 5Mbit.
#
# If there is demand in all classes, each of them gets share of bandwidth
# proportional to its default rate. If there unused is bandwidth left, they
# (again) get share proportional to their default rate.
#
# Configuration files for this scenario:
# ---------------------------------------------------------------------------
# eth0 eth0-2.root eth0-2:10.www eth0-2:20.smtp eth0-2:30.dfl
# ---- ----------- ------------- -------------- -------------
# DEFAULT=30 RATE=5Mbit RATE=5Mbit RATE=3Mbit RATE=1Kbit
# BURST=15k BURST=15k CEIL=5Mbit CEIL=5Mbit
# LEAF=sfq BURST=15k BURST=15k
# RULE=*:80, LEAF=sfq LEAF=sfq
# RULE=*:25
# ---------------------------------------------------------------------------
#
# Remember that you can only control traffic going out of your linux machine.
# If you have a host connected to network and want to control its traffic on
# the gateway in both directions (with respect to the host), you need to setup
# traffic control for that host on both (or all) gateway interfaces.
#
# Enjoy.
#
#############################################################################
export LC_ALL=C
### Command locations
TC=/sbin/tc
IP=/sbin/ip
MP=/sbin/modprobe
### Default filter priorities (must be different)
PRIO_RULE_DEFAULT=${PRIO_RULE:-100}
PRIO_MARK_DEFAULT=${PRIO_MARK:-200}
PRIO_REALM_DEFAULT=${PRIO_REALM:-300}
### Default HTB_PATH & HTB_CACHE settings
HTB_PATH=${HTB_PATH:-/etc/sysconfig/htb}
HTB_CACHE=${HTB_CACHE:-/var/cache/htb.init}
### Uncomment for sed/find with less features (useful for busybox)
#HTB_BASIC="yes"
### Uncomment to enable logfile for debugging
#HTB_DEBUG="/var/run/htb-$1"
### Modules to probe for. Uncomment the last HTB_PROBE
### line if you have QoS support compiled into kernel
HTB_PROBE="sch_htb sch_sfq cls_fw cls_u32 cls_route"
#HTB_PROBE=""
### Config keywords
HTB_QDISC="DEFAULT\|DCACHE\|R2Q"
HTB_CLASS="RATE\|CEIL\|BURST\|CBURST\|PRIO\|LEAF\|MTU"
HTB_CLASS="$HTB_CLASS\|PRIO_RULE\|PRIO_MARK\|PRIO_REALM"
HTB_CLASS="$HTB_CLASS\|LIMIT\|QUANTUM\|PERTURB"
#############################################################################
############################# SUPPORT FUNCTIONS #############################
#############################################################################
if [ -z "$HTB_BASIC" ]; then
### List of network devices
all_device_list () {
ip link show \
| sed -n "/^[0-9]/ { s/[[:space:]]//g; \
s/^[0-9]\+:\([^@-]\+\)\(@.\+\)\?:<.*/\1/; p; }"
} # all_device_list
### Load & filter file $HTB_PATH/$1
htb_filter_file () {
sed -n "s/#.*//; s/[^a-zA-Z0-9.,;:=/*-_]\+//g; \
/^[a-zA-Z0-9]\+=[a-zA-Z0-9.,:;/*-_]\+$/ p" $HTB_PATH/$1
} # htb_filter_file
### Parse class ID chain from file name
htb_clsid_chain () {
echo "${1#*-}" \
| sed -n "/^[0-9a-fA-F]/ { s/^\([0-9a-fA-F:]\+\).*/\1/; \
s/::/:/g; s/:$//; p; }"
} # htb_clsid_chain
### List of classes in $HTB_PATH
htb_class_list () {
for dev in `htb_device_list`; do
find $HTB_PATH \( -type f -or -type l \) \
-name "$dev-*" -not -name '*~' -maxdepth 1 \
-printf "%f\n"| sort
done
} # htb_class_list
### Gather $1 rules from $CFILE
htb_cfile_rules () {
echo "$CFILE"| sed -n "/^$1=/ { s/.*=//; p; }"
} # htb_cfile_rules
### Validate cache against config files
htb_valid_cache () {
for dev in `htb_device_list`; do
[ `find $HTB_PATH \( -type f -or -type l \) \
-name "$dev*" -maxdepth 1 -newer $HTB_CACHE| \
wc -l` -gt 0 ] && VALID=0
[ $VALID -ne 1 ] && break
done
} # htb_valid_cache
### Find class config for device $1, which is newer than cache
htb_cache_older () {
[ `find $HTB_PATH -type f -name "$1*" -maxdepth 1 \
-newer $HTB_CACHE| wc -l` -gt 0 ] && return 0
return 1
} # htb_cache_older
### Get current RATE and CEIL
htb_class_state () {
tc class show dev $1 \
| sed -n "s/[[:space:]]\+/ /g; /^class htb 1:$2 / \
{ s/.*rate \(.\+\) burst.*/\1/; p; q; }"
} # htb_class_state
else ### Less feature-hungry versions of above functions
all_device_list () {
ip link show \
| grep "^[0-9]" \
| sed "s/[[:space:]]//g; \
s/^[0-9]\+:\([^@-]\+\)\(@.\+\)\?:<.*/\1/"
} # all_device_list
htb_filter_file () {
sed 's/#.*//; s/[^a-zA-Z0-9.,;:=/*-_]\+//g' $HTB_PATH/$1 \
| grep '^[a-zA-Z0-9]\+=[a-zA-Z0-9.,;:/*-_]\+$'
} # htb_filter_file
htb_clsid_chain () {
echo "${1#*-}" \
| grep '^[a-fA-F0-9]' \
| sed 's/^\([a-fA-F0-9:]\+\).*/\1/; s/::/:/g; s/:$//'
} # htb_clsid_chain
htb_class_list () {
PFX=`echo "$HTB_PATH"| sed 's/\//\\\\\//g'`
for dev in `htb_device_list`; do
find $HTB_PATH -type f -name "$dev-*" \
| grep "^$HTB_PATH/$dev-[^/]\+[^~]$" \
| sed "s/$PFX\///" \
| sort
done
} # htb_class_list
htb_cfile_rules () {
echo "$CFILE"| grep "^$1="| cut -d"=" -f2
} # htb_cfile_rules
htb_cache_older () {
### cache is always up-to-date
return 1
} # htb_cache_older
htb_class_state () {
tc class show dev $1 \
| sed 's/[[:space:]]\+/ /g' \
| grep "^class htb 1:$2 " \
| sed 's/.*rate \(.\+\) burst.*/\1/'
} # htb_class_state
fi # HTB_BASIC
### List of HTB devices
htb_device_list () {
for dev in `all_device_list`; do
[ -f $HTB_PATH/$dev ] && echo $dev
done
} # htb_device_list
### Remove root class from device $1
htb_device_off () {
tc qdisc del dev $1 root 2> /dev/null
} # htb_device_off
### Remove HTB from all devices
htb_off () {
for dev in `htb_device_list`; do
htb_device_off $dev
done
} # htb_off
### Prefixed message
htb_message () {
echo -e "**HTB: $@"
} # htb_message
### Failure message
htb_failure () {
htb_message "$@"
exit 1
} # htb_failure
### Failure w/htb_off
htb_fail_off () {
htb_message "$@"
htb_off
exit 1
} # htb_fail_off
### Convert time to absolute value
htb_time2abs () {
local min=${1##*:}; min=${min##0}
local hrs=${1%%:*}; hrs=${hrs##0}
echo $[hrs*60 + min]
} # htb_time2abs
### Display traffic control setup
htb_show () {
for dev in `all_device_list`; do
[ `tc qdisc show dev $dev| wc -l` -eq 0 ] && continue
echo -e "### $dev: queueing disciplines\n"
tc $1 qdisc show dev $dev; echo
[ `tc class show dev $dev| wc -l` -eq 0 ] && continue
echo -e "### $dev: traffic classes\n"
tc $1 class show dev $dev; echo
[ `tc filter show dev $dev| wc -l` -eq 0 ] && continue
echo -e "### $dev: filtering rules\n"
tc $1 filter show dev $dev; echo
done
} # htb_show
### Derive DEVICE, CLASS and PARENT from $1
### Check validity of CLASS and PARENT class IDs
### Load class configuration from $HTP_PATH/$1
### Configure class parameters from CFILE
htb_load_class () {
DEVICE=${1%%-*}
CLSIDS=`htb_clsid_chain $1`
CLASS=${CLSIDS##*:}; [ -z "$CLASS" ] &&
htb_fail_off "$1 has invalid class ID!"
[ $[0x$CLASS] -lt 2 -o $[0x$CLASS] -gt 65535 ] &&
htb_fail_off "class ID of $1 must be in range 0x2-0xFFFF!"
CLSIDS=${CLSIDS%$CLASS}; CLSIDS=${CLSIDS%:}
PARENT=${CLSIDS##*:}; [ -n "$PARENT" ] &&
[ $[0x$PARENT] -lt 2 -o $[0x$PARENT] -gt 65535 ] &&
htb_fail_off "parent ID of $1 must be in range 0x2-0xFFFF!"
CFILE=`htb_filter_file $1`
### Set defaults & load class
MTU=""; LEAF=none; PERTURB=10
RATE=""; BURST=""; CEIL=""; CBURST=""
PRIO=""; LIMIT=""; QUANTUM=""
PRIO_RULE=$PRIO_RULE_DEFAULT
PRIO_MARK=$PRIO_MARK_DEFAULT
PRIO_REALM=$PRIO_REALM_DEFAULT
eval `echo "$CFILE"| grep "^\($HTB_CLASS\)="`
RNAME=""; CNAME=""
### Resolve RATE if needed
[ "$RATE" = "prate" ] && RNAME=RATE_$PARENT
[ "$RATE" = "pceil" ] && RNAME=CEIL_$PARENT
[ -n "$RNAME" ] && RATE=${!RNAME}
### RATE is required
[ -z "$RATE" ] &&
htb_fail_off "missing or unresolvable RATE in $1!"
### Resolve CEIL if needed
[ "$CEIL" = "prate" ] && CNAME=RATE_$PARENT
[ "$CEIL" = "pceil" ] && CNAME=CEIL_$PARENT
[ -n "$CNAME" ] && CEIL=${!CNAME}
### Store CEIL & RATE for children
eval RATE_$CLASS=$RATE
eval CEIL_$CLASS=${CEIL:-$RATE}
} # htb_load_class
#############################################################################
#################################### INIT ###################################
#############################################################################
### Check iproute2 tools
[ -x $TC -a -x $IP ] ||
htb_failure "iproute2 utilities not installed or executable!"
### Check $HTB_PATH directory
[ -d $HTB_PATH -a -r $HTB_PATH -a -x $HTB_PATH ] ||
htb_failure "$HTB_PATH does not exist or is not readable!"
### ip/tc wrappers
if [ "$1" = "compile" ]; then
### no module probing
HTB_PROBE=""
ip () {
$IP "$@"
} # ip
### echo-only version of "tc" command
tc () {
echo "$TC $@"
} # tc
elif [ -n "$HTB_DEBUG" ]; then
echo -e "# `date`" > $HTB_DEBUG
### Logging version of "ip" command
ip () {
echo -e "\n# ip $@" >> $HTB_DEBUG
$IP "$@" 2>&1 | tee -a $HTB_DEBUG
} # ip
### Logging version of "tc" command
tc () {
echo -e "\n# tc $@" >> $HTB_DEBUG
$TC "$@" 2>&1 | tee -a $HTB_DEBUG
} # tc
else
# default wrappers
ip () {
$IP "$@"
} # ip
tc () {
$TC "$@"
} # tc
fi # ip/tc wrappers
case "$1" in
#############################################################################
############################### START/COMPILE ###############################
#############################################################################
start|compile)
### Probe QoS modules (start only)
for module in $HTB_PROBE; do
$MP $module || htb_failure "failed to load module $module"
done
### If we are in compile/nocache/logging mode, don't bother with cache
if [ "$1" != "compile" -a "$2" != "nocache" -a -z "$HTB_DEBUG" ]; then
VALID=1
### validate the cache
[ "$2" = "invalidate" -o ! -f $HTB_CACHE ] && VALID=0
[ $VALID -eq 1 ] && for dev in `htb_device_list`; do
htb_cache_older $dev && VALID=0
[ $VALID -ne 1 ] && break
done
### compile the config if the cache is invalid
if [ $VALID -ne 1 ]; then
$0 compile > $HTB_CACHE ||
htb_fail_off "failed to compile HTB configuration!"
fi
### run the cached commands
exec /bin/sh $HTB_CACHE 2> /dev/null
fi
### Setup root qdisc on all configured devices
DEVICES=`htb_device_list`
[ -z "$DEVICES" ] && htb_failure "no configured devices found!"
for dev in $DEVICES; do
### Retrieve root qdisc options
DEFAULT=""; DCACHE=""; R2Q=""
eval `htb_filter_file $dev| grep "^\($HTB_QDISC\)="`
[ "$DCACHE" = "yes" ] && DCACHE="dcache" || DCACHE=""
### Remove old root qdisc from device
htb_device_off $dev
### Setup root qdisc for the device
tc qdisc add dev $dev root handle 1 htb \
default ${DEFAULT:-0} ${R2Q:+r2q $R2Q} $DCACHE ||
htb_fail_off "failed to set root qdisc on $dev!"
[ "$1" = "compile" ] && echo
done # dev
### Setup traffic classes (if configured)
for classfile in `htb_class_list`; do
htb_load_class $classfile
### Create the class
tc class add dev $DEVICE parent 1:$PARENT classid 1:$CLASS \
htb rate $RATE ${CEIL:+ceil $CEIL} ${BURST:+burst $BURST} \
${PRIO:+prio $PRIO} ${CBURST:+cburst $CBURST} ${MTU:+mtu $MTU} ||
htb_fail_off "failed to add class $CLASS with parent $PARENT on $DEVICE!"
### Create leaf qdisc if set
if [ "$LEAF" != "none" ]; then
if [ "$LEAF" = "sfq" ]; then
LEAFPARM="${PERTURB:+perturb $PERTURB} ${QUANTUM:+quantum $QUANTUM}"
elif [ "$LEAF" = "pfifo" -o "$LEAF" = "bfifo" ]; then
LEAFPARM="${LIMIT:+limit $LIMIT}"
else
htb_fail_off "unknown leaf qdisc ($LEAF) in $classfile!"
fi
tc qdisc add dev $DEVICE \
parent 1:$CLASS handle $CLASS $LEAF $LEAFPARM ||
htb_fail_off "failed to add leaf qdisc to class $CLASS on $DEVICE!"
fi
### Create fw filter for MARK fields
for mark in `htb_cfile_rules MARK`; do
### Attach fw filter to root class
tc filter add dev $DEVICE parent 1:0 protocol ip \
prio $PRIO_MARK handle $mark fw classid 1:$CLASS
done ### mark
### Create route filter for REALM fields
for realm in `htb_cfile_rules REALM`; do
### Split realm into source & destination realms
SREALM=${realm%%,*}; DREALM=${realm##*,}
[ "$SREALM" = "$DREALM" ] && SREALM=""
### Convert asterisks to empty strings
SREALM=${SREALM#\*}; DREALM=${DREALM#\*}
### Attach route filter to the root class
tc filter add dev $DEVICE parent 1:0 protocol ip \
prio $PRIO_REALM route ${SREALM:+from $SREALM} \
${DREALM:+to $DREALM} classid 1:$CLASS
done ### realm
### Create u32 filter for RULE fields
for rule in `htb_cfile_rules RULE`; do
### Split rule into source & destination
SRC=${rule%%,*}; DST=${rule##*,}
[ "$SRC" = "$rule" ] && SRC=""
### Split destination into address, port & mask fields
DADDR=${DST%%:*}; DTEMP=${DST##*:}
[ "$DADDR" = "$DST" ] && DTEMP=""
DPORT=${DTEMP%%/*}; DMASK=${DTEMP##*/}
[ "$DPORT" = "$DTEMP" ] && DMASK="0xffff"
### Split up source (if specified)
SADDR=""; SPORT=""
if [ -n "$SRC" ]; then
SADDR=${SRC%%:*}; STEMP=${SRC##*:}
[ "$SADDR" = "$SRC" ] && STEMP=""
SPORT=${STEMP%%/*}; SMASK=${STEMP##*/}
[ "$SPORT" = "$STEMP" ] && SMASK="0xffff"
fi
### Convert asterisks to empty strings
SADDR=${SADDR#\*}; DADDR=${DADDR#\*}
### Compose u32 filter rules
u32_s="${SPORT:+match ip sport $SPORT $SMASK}"
u32_s="${SADDR:+match ip src $SADDR} $u32_s"
u32_d="${DPORT:+match ip dport $DPORT $DMASK}"
u32_d="${DADDR:+match ip dst $DADDR} $u32_d"
### Uncomment the following if you want to see parsed rules
#echo "$rule: $u32_s $u32_d"
### Attach u32 filter to the appropriate class
tc filter add dev $DEVICE parent 1:0 protocol ip \
prio $PRIO_RULE u32 $u32_s $u32_d classid 1:$CLASS
done ### rule
[ "$1" = "compile" ] && echo
done ### classfile
;;
#############################################################################
################################# TIME CHECK ################################
#############################################################################
timecheck)
### Get time + weekday
TIME_TMP=`date +%w/%k:%M`
TIME_DOW=${TIME_TMP%%/*}
TIME_NOW=${TIME_TMP##*/}
TIME_ABS=`htb_time2abs $TIME_NOW`
### Check all classes (if configured)
for classfile in `htb_class_list`; do
### Load class and gather all TIME rules
htb_load_class $classfile
TIMESET=`htb_cfile_rules TIME`
[ -z "$TIMESET" ] && continue
MATCH=0; CHANGE=0
for timerule in $TIMESET; do
### Split TIME rule to pieces
TIMESPEC=${timerule%%;*}; PARAMS=${timerule##*;}
WEEKDAYS=${TIMESPEC%%/*}; INTERVAL=${TIMESPEC##*/}
BEG_TIME=${INTERVAL%%-*}; END_TIME=${INTERVAL##*-}
### Check the day-of-week (if present)
[ "$WEEKDAYS" != "$INTERVAL" -a \
-n "${WEEKDAYS##*$TIME_DOW*}" ] && continue
### Compute interval boundaries
BEG_ABS=`htb_time2abs $BEG_TIME`
END_ABS=`htb_time2abs $END_TIME`
### Midnight wrap fixup
if [ $BEG_ABS -gt $END_ABS ]; then
[ $TIME_ABS -le $END_ABS ] &&
TIME_ABS=$[TIME_ABS + 24*60]
END_ABS=$[END_ABS + 24*60]
fi
### If time period matches, remember params and set MATCH flag
if [ $TIME_ABS -ge $BEG_ABS -a $TIME_ABS -lt $END_ABS ]; then
RATESPEC=${PARAMS%%,*}; CEILSPEC=${PARAMS##*,}
[ "$RATESPEC" = "$CEILSPEC" ] && CEILSPEC=""
NEW_RATE=${RATESPEC%%/*}; NEW_BURST=${RATESPEC##*/}
[ "$NEW_RATE" = "$NEW_BURST" ] && NEW_BURST=""
NEW_CEIL=${CEILSPEC%%/*}; NEW_CBURST=${CEILSPEC##*/}
[ "$NEW_CEIL" = "$NEW_CBURST" ] && NEW_CBURST=""
MATCH=1
fi
done ### timerule
### Get current RATE and CEIL of a class
read RATE_NOW JUNK CEIL_NOW <<-EOT
`htb_class_state $DEVICE $CLASS`
EOT
[ -z "$RATE_NOW" -o -z "$CEIL_NOW" ] && continue
### Fill empty values if matched
if [ $MATCH -ne 0 ]; then
NEW_RATE=${NEW_RATE:-$RATE_NOW}
NEW_CEIL=${NEW_CEIL:-$CEIL_NOW}
NEW_BURST=${NEW_BURST:-$BURST}
NEW_CBURST=${NEW_CBURST:-$CBURST}
### Force configured values if not matched
else
NEW_RATE=$RATE; NEW_CEIL=$CEIL
NEW_BURST=$BURST; NEW_CBURST=$CBURST
fi
### Check for RATE and CEIL changes
[ "$RATE_NOW" != "$NEW_RATE" ] && CHANGE=1
[ "$CEIL_NOW" != "$NEW_CEIL" ] && CHANGE=1
### If there are no changes, go for next class
[ $CHANGE -eq 0 ] && continue
### Replace HTB class
tc class change dev $DEVICE classid 1:$CLASS htb \
prio $PRIO rate $NEW_RATE ${NEW_CEIL:+ceil $NEW_CEIL} \
${NEW_BURST:+burst $NEW_BURST} ${NEW_CBURST:+cburst $NEW_CBURST}
htb_message "$TIME_NOW: change on $DEVICE:$CLASS ($RATE_NOW/$CEIL_NOW -> $NEW_RATE/$NEW_CEIL)"
done ### class file
;;
#############################################################################
################################## THE REST #################################
#############################################################################
stop)
htb_off
;;
list)
htb_show
;;
stats)
htb_show -s
;;
restart)
shift
$0 stop
$0 start "$@"
;;
*)
echo "Usage: `basename $0` {start|compile|stop|restart|timecheck|list|stats}"
esacБонус
Собрать и установить netatop для atop:
wget https://www.atoptool.nl/download/netatop-3.1.tar.gz
tar -tf netatop-3.1.tar.gz
tar -zxvf netatop-3.1.tar.gz
cd netatop-3.1
cat README
sudo apt install zlib1g-dev
sudo apt install checkinstall
sudo apt-get install linux-headers-`uname -r`
make
checkinstall --install=no
sudo dpkg -i netatop_3.1-1_amd64.deb
sudo systemctl enable netatop.service
sudo systemctl start netatop.serviceВключить передачу графики по ssh:
При установке на сервер приедет графическая оболочка. У меня приехала gnome.
sudo dpkg -l gnome*
Установим необходимое и перезагрузимся:
$ sudo apt list xorg openbox
$ sudo rebootВ конфиге sshd_config подправить значение X11Forwarding yes.
Подключаемся по ssh:
$ ssh -X pumaЗапускаем графическое приложение:
$ virt-managerУстановить виртуализацию libvrt:
Проверим, есть ли поддержка:
$ egrep -c '(vmx|svm)' /proc/cpuinfo
$ sudo apt install cpu-checker
$ kvm-okУстанавливаем:
$ sudo apt install -y qemu qemu-kvm libvirt-daemon libvirt-clients bridge-utils virt-managerПроверим, работает ли демон виртуализации:
$ sudo systemctl status libvirtdПроверим загружены ли модули kvm:
$ lsmod | grep -i kvmПосмотреть список доступных образов:
$ osinfo-query osТеперь можно установить виртуальную машину c помощью:
- virsh
- virt-install
- virt-manager (графический интерфес, можно подключиться к удалённому хосту с виртуалками)
$ sudo virt-install --name=deepin-vm --os-variant=Debian10 --vcpu=2 --ram=2048 --graphics spice --location=/home/Downloads/deepin-20Beta-desktop-amd64.iso --network bridge:vibr0
$ sudo virt-install --name=ubu-virt --os-variant=ubuntu20.04 --vcpu=2 --ram=2048 --graphics spice --cdrom=iso/ubuntu-20.04.2-live-server-amd64.iso --network bridge:br0Настройка моста.
Установим необходимое:
$ sudo apt install bridge-utilsВот такой конфиг получился:
$ cat <<- EOF | tee /etc/netplan/manual.yaml
network:
ethernets:
enp6s0:
dhcp4: false
# addresses:
# - 192.168.8.1/24
# - 172.16.8.1/24
enp7s0:
dhcp4: true
nameservers:
addresses:
- 127.0.0.1
search:
- zavod.lan
bridges:
br0:
interfaces:
- enp6s0
addresses:
- 192.168.8.1/24
- 172.16.8.1/24
parameters:
stp: true
version: 2
renderer: networkd
EOFПроверим, что всё без ошибок:
$ sudo netplan generateПрименить, с возможность откатить изменения не получится:
$ sudo netplan try
br0: reverting custom parameters for bridges and bonds is not supported
Please carefully review the configuration and use 'netplan apply' directly.После объединения интерфейсов в bridge, нужно поменять настройки сервисов (например, нужно указать новый интерфейс br0 для
isc-dhcp-server). Так же необходимо изменить настройки сетевого экрана, в частности тоже имя интерфейса.
Применяем настройки и поднимаем интерфейс:
$ sudo netplan --debug applyПосмотреть сетевые обекты можно так:
# bridge control
brctl show
# network control
networkctl
networkctl status br0
# ip list
ip a | grep " br0:" -A 3
# show host routes
ip route
# show arp table (IP to MAC)
arp -nСоздадим свою сеть для виртуалок:
# https://libvirt.org/formatnetwork.html#examplesBridge
cat <<- EOF | tee host-bridge.xml
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
EOF
# create libvirt network using existing host bridge
$ sudo virsh net-define host-bridge.xml
$ sudo virsh net-start host-bridge
$ sudo virsh net-autostart host-bridge
# state should be active, autostart, and persistent
$ sudo virsh net-list --allТеперь, при создании виртуалки нужно указать сеть host-bridge.
При перезапуске демона
libvirtd, он будет создавать свои правила файервола. Все настройкиlibvirtdнаходятся по стандартному пути:/etc/libvirt, если удалитьdefault.xmlиз/etc/libvirt/qemu/networks/autostart/, то настройки применяться будут, т.к. в данному случае мы удаляемsysmlink.
Посмотреть все сети:
$ virsh net-list --allУдалить сеть default:
$ virsh net-destroy defaultИзменить сеть default:
$ sudo virsh net-edit default