Быстрый переход:
| Ubuntu 20.04 | chrony | netplan | dns | isc-dhcpd | ipset | iptables | htb.init | build | libvirt | bridge
Обозначения:
$ timedatactl
- запуск от пользователя
root> timedatactl
- запуск от суперпользователя
some text
- вывод программы
#
- комментарий
...
- пропуск не нужной информации
Сервер времени chrony
Установка часового пояса
1
2
3
4
5
|
$ 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
Установим:
1
|
$ sudo apt install chrony
|
Проверим, что запущен и работает:
1
2
3
|
$ sudo systemctl status chrony
$ sudo systemctl is-enabled chrony
$ sudo systemctl enable --now chrony
|
Разбор параметров:
Reference ID
- идентификатор и имя, с которым компьютер в настоящее время синхронизирован.
Stratum
- количество переходов к компьютеру с установленными основными часами.
Ref time
- это время по Гринвичу, в которое было выполнено последнее измерение из эталонного источника.
System time
- задержка системных часов от синхронизированного сервера.
Last offset
- расчетное смещение последнего обновления часов.
RMS offset
- долгосрочное среднее арифметическое значения смещения.
Frequency
- это частота, на которой часы системы будут работать неправильно, если хронограф не проведет - коррекцию. Она выражена в ppm - ч/м (частей на миллион).
Residual freq
- остаточная частота указывает на разницу между измерениями от опорного источника и используемой в настоящее время частотой.
Skew
- расчетная погрешность, связанная с погрешностью частоты.
Root delay
- суммарная задержка сетевого пути к опорному серверу, с которым синхронизируется компьютер.
Leap status
- это статус, который может иметь одно из следующих значений - нормальное, добавить второй, удалить второй или не синхронизироваться.
Получим информацию об источниках:
1
2
3
|
$ chronyc sources
# с комментариями :)
$ chronyc sources -v
|
Выберем ближайшие сервера времени к нашему серверу и добавим их в конфиг:
1
|
$ sudo vi /etc/chrony/chrony.conf
|
По-умолчанию chrony
работает как клиент, чтобы работал как сервер времени добавим в конфигурационный файл разрешение с какими сетями можно работать:
1
2
|
allow 192.168.8.0/24
allow 172.16.8.0/24
|
Если добавить просто allow
, то chrony
будет отвечать всем. Подробнее об опциях здесь
Перезапустим демона:
1
|
$ sudo systemctl restart chronyd
|
Посмотрим логи chrony
:
1
|
$ journalctl --unit=chrony
|
Настройка сетевых интерфейсов
Есть 2 интерфейса, enp6s0
и enp7s0
.
В enp7s0
будет подключен интернет, а в enp6s0
локальные сети.
1
2
3
4
5
6
7
8
9
|
$ 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. Если файлов конфигурации несколько, то они обрабатываются в алфавитном порядке.
У меня получился такой конфиг:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$ 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. Куча примеров на офиц. сайте
Перед применением конфигурации, проверим её:
1
|
$ sudo netplan generate
|
Если команда generate
не выдала ничего, значит конфиг написан без ошибок.
Я удалил все автоматически сгенерированные файлы, оставил только свой.
Применить изменения можно либо командой netplan apply
, либо netplan try
, которая вернёт прежние настройки, если новые вы не подтвердите за 120 сек.
Теперь, подключив сетевой кабель, проверим адреса на сетевой карте:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$ 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)
Устанавливаем необходимое:
1
|
$ sudo apt install bind9 bind9utils bind9-doc bind9-host
|
Версия с доп. информацией:
В Ubuntu 20.04 пакет bind использует корневые сервера из /usr/share/dns/root.hints, вместо db.root
Добавим в автозагрузку и запустим:
1
2
|
$ sudo systemctl enable bind9
$ sudo systemctl start bind9
|
Bind
работает от пользователя bind:bind
, который создался автоматически во время установки.
В основном используется udp/53
, но так же и tcp/53
используется для больших ответов сервера и для передачи зоны.
Посмотрим, запустился ли:
1
|
$ sudo lsof -i -P -n | grep bind
|
-P
параметр указывает показывать номера портов
-n
параметр указывает показывать ip-адреса
Для управления используется rndc, подключается к TCP-порту 953:
1
2
3
|
$ sudo rndc status
...
server is up and running
|
Для описания своих зон нужно использовать файл /etc/bind/named.conf.local
,
а для настройки bind - /etc/bind/named.conf.options.
DNS-resolver
Посмотрим какой используется resolver в системе:
1
2
3
|
$ sudo systemd-resolve --status
# or
$ sudo resolvectl status
|
Чтобы установить наш DNS-сервер как resolver по-умолчанию, необходимо добавить следующую строку в файл /etc/systemd/resolved.conf
в секцию [Resolve]
:
1
2
3
4
|
$ cat /etc/systemd/resolved.conf
...
DNS=127.0.0.1
...
|
Ну и нужно перезапустить:
1
|
$ sudo systemctl restart systemd-resolved
|
Наблюдаем в секции Global DNS Servers: 127.0.0.1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ 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
|
Ещё посмотрим на файл:
1
2
3
4
|
$ cat /etc/resolv.conf
nameserver 127.0.0.53
search lan
options edns0 trust-ad
|
Исправим, чтобы указывало на наш dns-server:
1
2
3
|
$ sudo apt install resolvconf
$ sudo systemctl enable named-resolvconf.service
$ sudo systemctl start named-resolvconf.service
|
Проверим, что теперь указывает на наш dns-server:
1
2
3
4
|
$ cat /etc/resolv.conf
nameserver 127.0.0.1
search lan
options edns0 trust-ad
|
Посмотреть логи можно 2мя способами:
1
2
|
$ sudo journalctl -e --unit=named
$ sudo journalctl -xe | grep named
|
Настройка dns-зон
Вот так выглядят конфиг-файлы.
Конфиг-файл настроек bind
:
/etc/bind/named.conf.options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ 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
писать в неё:
1
2
|
$ sudo mkdir /var/log/named
$ sudo chown bind:bind /var/log/named
|
severity — указывает уровень логирования. Варианты: critical, error, warning, notice, info, debug, dynamic.
Теперь остаётся добавить в конфиг named
следующие директивы:
/etc/bind/named.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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
|
Проверим настройки и перезапустим:
1
2
|
$ 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
:
1
2
|
rndc-confgen -a
wrote key file "/etc/bind/rndc.key
|
Добавим rndc.key
в /etc/bind/named.conf
и проверим конфиг:
1
2
3
|
$ echo "include \"/etc/bind/rndc.key\";" | sudo tee --append /etc/bind/named.conf
include "/etc/bind/rndc.key";
$ sudo named-checkconf
|
Добавим возможность управления только с localhost
:
1
2
3
4
5
6
7
8
|
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
.
1
2
3
4
5
6
7
8
9
10
|
$ 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; };
|
Проверим, нет ли ошибок в конфигах и зонах:
1
2
3
4
5
6
7
8
9
10
|
$ 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
:
1
|
$ sudo systemctl restart named
|
Теперь настроим связь между named
и isc-dhcp-server
, чтобы при выдаче адреса, этот адрес записывался в зоны dns.
Стандартный путь для хранения зон это /var/lib/bind
. Если хранить их в другом месте, то нужно добавить эту папку в apparmor
и дать права на запись.
Так как у меня зоны лежат в /etc/bind/dynamic
, придётся в apparmor
разрешить named
право на запись.
Убедимся, что named
присутствует:
1
2
3
|
$ sudo apparmor_status | grep named
/usr/sbin/named
/usr/sbin/named (4764)
|
Добавим после /etc/bind/** r
в файле /etc/apparmor.d/usr.sbin.named
строку:
1
|
/etc/bind/dynamic/** rw,
|
Сохраним файл и рестартнём apparmor
:
1
|
$ sudo systemctl restart apparmor
|
Установим bind:bind
на директорию /etc/bind/dynamic
:
1
|
$ sudo chown -R bind:bind /etc/bind/dynamic
|
Теперь нужно подправить конфиг isc-dhcp-server
, как его готовить описано ниже.
После настройки isc-dhcp-server
следует вернуться сюда и применить эти настройки. Нужно добавить в файл /etc/dhcp/dhcpd.conf
следующее:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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;
}
|
Проверим что всё верно и перезапустим демон:
1
2
|
$ sudo dhcpd -t
$ sudo systemctl restart isc-dhcp-server
|
Теперь, когда в локально сети появится новый компьютер, isc-dhcp-server
выдаст ему свободный ip-адрес и обновит dns
-зоны. При этом в каталоге рядом с зонами будут добавлены соответствующие файлы с расширением .jnl
.
Работа с rndc
Для того, чтобы вручную изменить файлы зоны нужно приостановить динамическое обновление зон:
1
2
3
4
5
6
7
8
|
# убедимся, что всё синхонизировано, т.е. перенесём все временные данные из файла .jnl в файл зоны:
$ sudo rndc sync
# приостановим динамическое обновление
$ sudo rndc freeze zavod.lan
# либо приостановим обновление всех зон
$ sudo rndc freeze
|
После ручной правки зоны нужно сначала перечитать файлы зон:
А затем восстановить работу динамического обновления:
1
2
3
4
|
$ sudo rndc thaw zavod.lan
# или для всех зон:
$ sudo rndc thaw
|
Может сложиться такая ситуация: На компьютере в локальной сети поменяли сетевую карту (изменился MAC-адрес), а запись с этим именем компьютера осталась в файле зон. Тогда нужно описанным выше способом удалить старую запись, а новая будет добавлена автоматически. Сообщения такого вида в логах подскажут о такой ситуации:
1
|
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
у компьютера в сети:
1
2
3
4
5
6
7
8
9
10
11
|
$ $ 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
не удалось получить.
Получим вручную:
1
2
|
user@Q3:~$ sudo dhclient -r
user@Q3:~$ sudo dhclient enp2s0
|
Настройка isc-dhcp-server
Как и всегда, примеры конфигурации можно посмотреть здесь:
1
2
|
$ ls /usr/share/doc/
$ cat /usr/share/doc/isc-dhcp-server/examples/dhcpd.conf.example
|
Установим dhcp-server и укажем интерфейс для работы:
1
2
|
$ sudo apt install isc-dhcp-server
$ echo "INTERFACESv4=\"enp6s0\"" | sudo tee --append /etc/default/isc-dhcp-server
|
У меня получился вот такой конфиг:
/etc/dhcp/dhcpd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
$ 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
:
1
2
|
local7.* /var/log/dhcpd.log
& stop
|
И перезапустить:
1
|
$ sudo systemctl restart rsyslog
|
Теперь логи будут добавляться в /var/log/dhcpd.log
, но они так же будут и туда, куда раньше: /var/log/syslog
. Для отключения этого нужно изменить строку в файле /etc/rsyslog.d/50-default.conf
c (1) на (2):
1
2
|
(1) *.*;auth,authpriv.none -/var/log/syslog
(2) *.*;auth,authpriv.none;local7.none -/var/log/syslog
|
Ну и перезапустить демон:
1
|
$ sudo systemctl restart rsyslog
|
Тестируем конфиг и смотрим где лежит lease-файл:
Запускаем службу:
1
|
$ sudo systemctl start isc-dhcp-server
|
Смотрим status службы, если не она запустилась, ответы здесь:
/var/log/syslog
/var/log/dhcpd.log
Итак, dhcpd работает, можно посмотреть какие адреса выданы:
Чтобы пересоздать lease-file, нужно удалить старый и перезапустить демон isc-dhcpd.
Проверим lease-файл
на ошибки:
Нужно не забыть отключить 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
.
Для начала установим:
1
|
$ sudo apt install ipset
|
Возможные типы списков:
net
- сети, например 192.168.8.0/24
ip
- только ip, например 192.168.8.55
mac
- MAC адреса, например 11:22:33:44:55:66
port
- порты, удобно при создании списков ip,port
iface
- сетевые интерфейсы, удобно при создании списков ip,iface
Примеры создания списков, где mylist - имя списка:
1
2
3
4
5
6
7
|
$ 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
|
Удалить список:
1
|
$ sudo ipset destroy mylist
|
Добавить данные в спискок, учтите, данные должены соответствовать тому, какой список был создан.
1
2
3
4
5
6
|
$ 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
|
Удалить элемент из списка:
1
|
$ sudo ipset del mylist 192.168.5.5
|
Переименовать список:
1
|
$ sudo ipset rename OLDNAME NEWNAME
|
Посмотреть содержимое все или конкретного списка:
1
2
3
|
$ sudo ipset -L
$ sudo ipset --list
$ sudo ipset -L mylist
|
Использование списков в iptables:
1
2
3
|
$ 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
не превратились в тыкву:
1
2
|
$ sudo ipset save -file /etc/ipset.conf
$ sudo ipset restore -file /etc/ipset.conf
|
Опишем systemd
сервис, который будет подгружать настроки ipset
после загрузки системы и инициализации сети:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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
|
1
2
3
4
|
$ 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):
Для конкретной таблицы:
1
2
3
4
5
|
$ 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:
1
2
3
|
$ sudo iptables --flush
$ sudo iptables --table nat --flush
$ sudo iptables --delete-chain
|
Включим ip forwarding:
1
2
3
4
5
|
$ 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 в начало
1
2
3
|
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
|
Сохраним правила:
1
2
3
4
|
$ sudo apt-get install iptables-persistent
$ sudo netfilter-persistent save
# или сохранить по пути:
$ sudo netfilter-persistent save > /etc/iptables/rules.v4
|
Здесь всякие бинарники для управления iptables: ls /usr/sbin/iptables-*
Восстановим правила:
1
|
$ sudo iptables-restore /etc/iptables/rules.v4
|
Чтобы вывести список всех активных правил iptables по спецификации, выполните команду iptables с параметром -S:
На этом базовая настрока iptables окончена.
Скрипт iptables.sh
с комментариями.
iptables.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
#!/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 родительского класса.
Идентификаторы классов в пределах интерфейса должны быть уникальны.
Каждый конфигурационный файл описывает очередь, это заложено в самом названии файла, которое имеет формат:
1
|
$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=
- правила, определяющий трафик, который должен проходить через данную очередь. В одном файле могут присутствовать сразу несколько правил.
1
|
RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]
|
Если трафик попадает по условиям в очередь -2:10 (например, где правило задано по маске), то дальше он уже не будет проверять условия в -2:20 (где допустим будет описано правило с конкретно этим ip), -2:30 и т.д.
MARK=101
: трафик имеющий метку. Метим в таблице mangle, либо в PRERIUTING, либо в FORWARD выше исключающих этот трафик правил.
1
2
|
$ 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 RETURN
|
TIME
- временные параметры
1
2
3
|
TIME=[<dow><dow>.../]<from>-<till>;<rate>[/<burst>][,<ceil>[/<cburst>]]
TIME=60123/18:00-06:00;256Kbit/10Kb,384Kbit
TIME=18:00-06:00;256Kbit
|
REALM=[srealm,][drealm]
- именное обозначение направлений
Пример 1
- Скачаем htb.init, положить сюда
/usr/sbin/htb.init
и дать права:
1
|
$ sudo chmod u+x /sbin/htb.init
|
- Создадим директорию для конфигов:
1
|
$ sudo mkdir -p /etc/sysconfig/htb
|
При запуске, кэш будет храниться в этом файле: /var/cache/htb.init
- Создадим конфиги для входящего трафика
$intif(enp6s0)
:
- Общий для $intif(enp6s0):
1
2
3
4
|
# cat << EOF > enp6s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
EOF
|
- Корневой класс для исходящей ширины канала:
1
2
3
4
5
|
# cat << EOF > enp6s0-2.root
RATE=100Mbit # гарантированная пропускная способность
CEIL=1000Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
EOF
|
- Дочерний класс для ограничения скорости пакетов, маркированных 87
1
2
3
4
5
6
7
|
# cat << EOF > enp6s0-2:30.MARK87
RATE=512Kbit # гарантированная пропускная способность
CEIL=512Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF
|
- Класс для ограничения скорости по-умолчанию:
1
2
3
4
5
6
|
# cat << EOF > enp6s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF
|
Перезапускаем скрипт:
1
|
$ sudo htb.init restart
|
Маркированные пакеты будут замедлены до 512Kbit, не маркированные до 10Mbit, убедимся (запуск с клиента):
1
|
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -R -P 1
|
- Теперь займёмся исходящим трафиком $extif(enp7s0). Все классы создаются аналогично:
1
2
3
4
|
# cat << EOF > enp7s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
EOF
|
1
2
3
4
5
|
# cat << EOF > enp7s0-2.root
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
EOF
|
1
2
3
4
5
6
7
|
# cat << EOF > enp7s0-2:30.MARK88
RATE=4Mbit # гарантированная пропускная способность
CEIL=4Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=88 # применять правило для пакетов, маркированных меткой 87
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF
|
1
2
3
4
5
6
|
# cat << EOF > enp7s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
EOF
|
- Перезапустим правила управления трафиком:
1
|
$ sudo /sbin/htb.init restart
|
Проверяем с клиента:
1
|
$ iperf3 -c speedtest.studiofunk.de -p 5200
|
Пример 2.
Выделить пропускную полосу 512Кбит/с для локального клиента 192.168.8.55.
На сервере-шлюзе 2 интерфейса:
$intif(enp6s0)
- внутренний интерфейс
$extif(enp7s0)
- внешний интерфейс
Создаём файлы с соответствующим содержимым:
1
2
3
4
|
# cat << EOF > enp6s0
DEFAULT=30
R2Q=100
EOF
|
1
2
3
4
|
# cat << EOF > enp6s0-2.root
# Скорость корневого класса 100Мбит, так как других классов тут не будет
RATE=100Mbit
EOF
|
1
2
3
4
5
6
7
8
9
10
11
|
# 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
|
1
2
3
4
5
6
7
8
|
# 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
|
1
2
3
4
5
6
7
|
# cat << EOF > enp6s0-2:30.all
# Правило по умолчанию. Оставшийся трафик будет интернет трафиком.
RATE=1Kbit
CEIL=1536Kbit
LEAF=sfq
PRIO=10
EOF
|
Применим:
1
2
3
4
|
sudo htb.init compile # тест. можно посмотреть какие правила будут сформированы и ошибки, если есть.
sudo htb.init start # запуск
sudo htb.init stop # остановка
sudo htb.init restart # перезапуск после внесения изменений в файлы конфигурации
|
Измерим скорость на удалённом сервере.
Если клиент в сети отдаёт:
1
2
|
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -P 5
$ sudo iperf3 -c speedtest.hostkey.ru -p 5200 -P 1
|
Если клиент в сети принимает:
1
|
$ sudo iperf3 -R -c speedtest.hostkey.ru -p 5200 -P 1
|
Поднять свой сервер:
Перед проверкой нужно убедиться что порт в цепочке INPUT открыт.
Текущие конфиги:
enp6s0
- внутренний интерфейс
enp7s0
- внешний интерфейс
enp6s0:
1
2
3
|
# $ cat enp6s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
|
1
2
3
4
|
# $ cat enp6s0-2.root
RATE=100Mbit # гарантированная пропускная способность
CEIL=1000Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
|
1
2
3
4
5
|
# $ cat enp6s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
|
1
2
3
4
5
6
|
# $ cat enp6s0-2:30.MARK87
RATE=512Kbit # гарантированная пропускная способность
CEIL=512Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=87 # применять правило для пакетов, маркированных меткой 87
# PRIO=20 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0
|
1
2
3
4
5
6
|
$ cat enp6s0-2:40.MARK90
RATE=2Mbit # гарантированная пропускная способность
CEIL=2Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=90 # применять правило для пакетов, маркированных меткой 90
# PRIO=10 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0
|
enp7s0:
1
2
3
|
# $ cat enp7s0
DEFAULT=10 # указывает номер класса, куда попадает трафик не попавший ни под одно правило, в моём случае в enp6s0-2:10.default
R2Q=100 # точность ограничений
|
1
2
3
4
5
6
7
8
9
10
|
# $ cat enp7s0-2.root
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
# BURST=15k # первые 15k без ограничений
```bash
# $ cat enp7s0-2:10.default
RATE=10Mbit # гарантированная пропускная способность
CEIL=10Mbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
# PRIO=30 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0, при отправке пакетов, классы с низким значением поля приоритета оправляют первыми
|
1
2
3
4
5
6
|
# $ cat enp7s0-2:30.MARK88
RATE=64Kbit # гарантированная пропускная способность
CEIL=64Kbit # максимальная пропускная способность
LEAF=sfq # равномерное распределение между участниками очереди.
MARK=88 # применять правило для пакетов, маркированных меткой 87
# PRIO=20 # приоритет трафика очереди к другим очередям в классе. Чем меньше число, тем выше приоритет.default 0
|
1
2
3
4
5
6
|
# $ 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
изменим скрипт:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$ 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
для запуска демона:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
|
#!/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
:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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*
Установим необходимое и перезагрузимся:
1
2
|
$ sudo apt list xorg openbox
$ sudo reboot
|
В конфиге sshd_config
подправить значение X11Forwarding yes
.
Подключаемся по ssh:
Запускаем графическое приложение:
Установить виртуализацию libvrt:
Проверим, есть ли поддержка:
1
2
3
|
$ egrep -c '(vmx|svm)' /proc/cpuinfo
$ sudo apt install cpu-checker
$ kvm-ok
|
Устанавливаем:
1
|
$ sudo apt install -y qemu qemu-kvm libvirt-daemon libvirt-clients bridge-utils virt-manager
|
Проверим, работает ли демон виртуализации:
1
|
$ sudo systemctl status libvirtd
|
Проверим загружены ли модули kvm:
Посмотреть список доступных образов:
Теперь можно установить виртуальную машину c помощью:
- virsh
- virt-install
- virt-manager (графический интерфес, можно подключиться к удалённому хосту с виртуалками)
1
2
|
$ 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
|
Настройка моста.
Установим необходимое:
1
|
$ sudo apt install bridge-utils
|
Вот такой конфиг получился:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
$ 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
|
Проверим, что всё без ошибок:
1
|
$ sudo netplan generate
|
Применить, с возможность откатить изменения не получится:
1
2
3
4
|
$ 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
). Так же необходимо изменить настройки сетевого экрана, в частности тоже имя интерфейса.
Применяем настройки и поднимаем интерфейс:
1
|
$ sudo netplan --debug apply
|
Посмотреть сетевые обекты можно так:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 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
|
Создадим свою сеть для виртуалок:
1
2
3
4
5
6
7
8
|
# 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
|
1
2
3
4
5
6
7
|
# 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
.
Посмотреть все сети:
Удалить сеть default
:
1
|
$ virsh net-destroy default
|
Изменить сеть default
:
1
|
$ sudo virsh net-edit default
|