Прикладной уровень: возможности операционной системы
Поток / датаграмма / whatever получены. Что дальше?
Цели:
- Активация интерпретатора
- Сопоставление потока данных интерпретатору
- Обеспечение готовности сервиса-интерпретатора
- Интерпретация
- (…) а откуда нам знать? Сколько протоколов, столько и логик.
Задачи:
Связывание порта и интерпретатора
Запуск и обслуживание интерпретатора
- Анонс прикладных служб по сети и распознавание этого анонса
- Учёт потребления ресурсов прикладными службами: иногда изнутри самого приложения не видно, насколько всё плохо
Систем запуска и контроля сетевых сервисов в Linux несколько, остановимся на самом «универсальном» — SystemD.
Леннарт и юзабилити ;_;
Коротко об управлении systemd
Понятие службы systemd
Команды управления systemctl:
- start / restart / stop / status
- enable / disable
- cat
edit и его ;_;-грабельки
--full --force
$SYSTEMD_EDITOR
Назначение systemd.socket
- Есть ещё таймеры, точки монтирования, чёрт в ступе…
Связь с интерпретатором
Пространство имён: /etc/services — только well-known и нет прямой связи с приложением
В роли «служб» мы использовали
netcat -l
socat TCP-LISTEN…,fork (или UDP…)
Два варианта сетевой службы в Linux:
- Полноценный сервис.
- Делает подсистема запуска:
- Запуск и останов по расписанию / заспросу
- Делает сама служба:
Создание и обслуживание сокета (bind() + listen() + accept())
- (одно соединение) Закрытие сокета + respawn при закрытии соединения
(несколько соединений) Обработка соединения отдельным процессом accept() + fork()
- Количество одновременных соединений?
- Интерпретация потоков В/В
- Управление сервисом — сигналы или специальный сокет
- Делает подсистема запуска:
- «Сокет-активация»
- Делает подсистема запуска:
Создание и обслуживание сокета (bind() + listen() + accept())
- Обслуживание одного соединения
Обслуживание нескольких соединений accept() + fork() (в т. ч. общие для прикладного уровня ограничения по ресурсам, конкуренции между соединениями и т. п.)
Запуск соответствующего интерпретатора потока (stdin / stdout) и преобразование потока в пакеты
- Управление сервисом посредством сигналов
- Делает сама служба:
- Интерпретация потоков В/В
- Управление сервисом через специальный сокет / утилиту
- Делает подсистема запуска:
;_; Есть ещё сокет-активация для полноценных сервисов с передачей им открытого сокета, (с указанием Accept=No):
- В документации написано, что именно так и надо делать
- …но никто так не делает
…и единственный пример, который я нашёл — это systemd-socket-proxyd, странный вариант socat от тех же авторов)
Примеры
netstat (или ss — sockstat)
-ltp (и -lup)
-ntp (и -nup)
socat как служба запуска:
socat TCP-LISTEN:1234 EXEC:/usr/bin/cal
В Linux при повторном запуске можете получить TIME_WAIT ⇒ TCP-LISTEN:1234,reuseaddr
Несколько соединений: базовый сервис + fork() : TCP-LISTEN:1234,reuseaddr,fork
Запуск собственных служб с помощью systemd
Полноценный сервис
Сервис должен сам уметь в транспортный уровень (bind() → listen() → accept() etc.)
Запуск socat как службы:
Создание .service файла:
[root@srv ~]# systemctl edit --force --full cal.service` … не забываем про $SYSTEMD_EDITOR [root@srv ~]# systemctl cat cal.service # /etc/systemd/system/cal.service [Unit] Description=SOCAT Example [Service] ExecStart=/usr/bin/socat TCP-LISTEN:1234 EXEC:/usr/bin/cal
- Запуск:
[root@srv ~]# systemctl start cal.service … [root@srv ~]# systemctl status cal … [root@srv ~]# ps | grep cal … [root@srv ~]# ss -ltp State Recv-Q Send-Q Local Address:Port Peer Address:Port Process … LISTEN 0 5 0.0.0.0:1234 0.0.0.0:* users:(("socat",pid=1473,fd=5))
- Проверка с соседней машины
[root@router ~]# netcat 10.9.0.1 1234 April 2024 Su Mo Tu We Th Fr Sa 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
- Служба отработала:
[root@srv ~]# systemctl status cal … Apr 04 16:55:40 srv systemd[1]: cal.service: Deactivated successfully.
- Если хотим, чтобы служба перезапускалась, надо самостоятельно бороться с REUSEADDR:
- Изменить сервис файл — добавить
… [Service] Restart=always ExecStart=/usr/bin/socat TCP-LISTEN:1234,reuseaddr EXEC:/usr/bin/cal
Не забыть взывать systemctl daemon-reload (перечитать файлы сервисов)
- Изменить сервис файл — добавить
Такая служба обрабатывает только одно подключение, но у socat TCP-LISTEN есть параметр ,fork
Сокет-активация
- Сам сервис — только прикладной
- Масштабирование с помощью шаблонов
Пример:
- Надо создать два юнита:
- Сокет-активатор
[root@srv ~]# systemctl edit --full --force hexdump.socket … [root@srv ~]# systemctl cat hexdump.socket # /etc/systemd/system/hexdump.socket [Unit] Description = Hexdump Socket [Socket] ListenStream = 1234 Accept = yes
Accept = yes — это ещё и приём нескольких соединений в стиле accept() + fork()`
Сервис. Поскольку сервисов будет запускаться несколько одновременно, мы задаём шаблон (@ заменится на ID сервиса,
[root@srv ~]# systemctl edit --full --force hexdump@.service … [root@srv ~]# systemctl cat hexdump@.service # /etc/systemd/system/hexdump@.service [Unit] Description=Hexdump Service [Service] ExecStart=/usr/bin/hexdump -C StandardInput=socket # StandardOutput=socket is also set by previous line
- Сокет-активатор
- Запустим сокет-активацию:
[root@srv ~]# systemctl start hexdump.socket [root@srv ~]# ss -ltp State Recv-Q Send-Q Local Address:Port Peer Address:Port Process … LISTEN 0 4096 0.0.0.0:1234 0.0.0.0:* users:(("systemd",pid=1,fd=53))
На порту слушает сам systemd, сервис поднимется только после подключения:
[root@router ~]# netcat 10.9.0.1 1234
[root@srv ~]# systemctl | grep hexdump hexdump@1-10.9.0.1:1234-10.9.0.2:34200.service
- как видим, ID сервиса, активированного сокетом, — это знакомая нам четвёрка
- Проверим, как обрабатывается несколько подключений
При задании сервиса можно использовать разные динамические значения
Например, можно добавить ExecStartPre=echo "Hexdump on %H %i" или что-то подобное в hexdump@.service
Для того, чтобы сервисы стартовали автоматом после перезагрузки, необходимо поставить их в зависимость от какого-либо этапа загрузки системы, вписав в .service-файл примерно такое:
… [Install] WantedBy=multi-user.target
Перманентная настройка сети с помощью systemd-networkd
Различные дистрибутивы и сообщества Linux пользуются несколькими разными высокоуровневыми системами настройки сети; стандарта или общейдоговорённости нет. Раз уже мы начали с SystemD, рассмотрим, как настраивать сеть с его помощью.
Отступление 0: Просмотр, останов и запуск служб systemd
Отступление 1: .d-схема хранения конфигурационных файлов.
.d-каталог /etc/systemd/network/
Сам systemd-networkd:
systemd.link: переименование и настройка сетевых интерфейсов
systemd.netdev: создание виртуальных сетевых устройств (например, бриджей и VLAN-ов)
См. примеры
systemd.network: настройки параметров сети на интерфейсах и специальных подсистем
См. примеры
Настроим IP сервера с выходом в Интернет через стандартную «виртуальную» сеть VirtualBox (пример по ссылке выше)
[Match] Name=eth0 [Network] Address=10.0.2.15/24 Gateway=10.0.2.2
- Адрес/подсеть — 10.0.2.15/24
- Маршрутизатор по умолчанию — 10.0.2.2
DNS пока настраиваем вручную: строка nameserver 1.1.1.1 в файле /etc/resolv.conf
DNS 1.1.1.1 не заработает на АКАДО, там надо указывать такой же DNS, что и в хост-системе
Файл обязан называться что-то-там.network (других настроек не нужно)
Например, /etc/systemd/network/10-inet.network
10 — это для .d-схемы
Перечитаем настройки сети и обновим настройки интерфейса
[root@srv ~]# networkctl reload [root@srv ~]# networkctl reconfigure eth0 [root@srv ~]# networkctl IDX LINK TYPE OPERATIONAL SETUP 1 lo loopback carrier unmanaged 2 eth0 ether routable configured 3 eth1 ether off unmanaged 4 eth2 ether off unmanaged 5 eth3 ether off unmanaged 5 links listed. [root@srv ~]# networkctl delete forcerenew list reconfigure renew up down label lldp reload status [root@srv ~]# networkctl status eth0 * 2: eth0 Link File: /lib/systemd/network/99-default.link Network File: /etc/systemd/network/50-vbox.network Type: ether State: routable (configured) Online state: online Alternative Names: enp0s3 Path: pci-0000:00:03.0 Driver: pcnet32 Vendor: Advanced Micro Devices, Inc. [AMD] Model: 79c970 [PCnet32 LANCE] (PCnet - Fast 79C971) HW Address: 08:00:27:89:d2:0f (PCS Systemtechnik GmbH) MTU: 1500 (min: 68, max: 1500) QDisc: fq_codel Queue Length (Tx/Rx): 1/1 Auto negotiation: no Speed: 10Mbps Duplex: half Port: tp Address: 10.0.2.15 Gateway: 10.0.2.2 Activation Policy: up Required For Online: yes Apr 14 18:09:47 srv systemd-networkd[1096]: eth0: Re-configuring with /etc/systemd/network/50-vbox.network Apr 14 18:09:47 srv systemd-networkd[1096]: eth0: Link UP Apr 14 18:09:47 srv systemd-networkd[1096]: eth0: Gained carrier Apr 14 18:09:51 srv systemd-networkd[1096]: eth0: Re-configuring with /etc/systemd/network/50-vbox.network
Эта настройка перманентна — после перезагрузки должна восстановиться.
Настройка статического маршрута
Тот же файл ….network +
[Route] Gateway=маршрутизатор Destination=сеть
Настройка net.ipv4.ip_forward:
[Network] … IPForward=ipv4
В любом одном файле
Из известного нам: ProxyARP, Policy routing, …
(коротко, без демонстрации) Использование netdev
Доступ к VLAN + организация bridge с ним для загрузки виртуальной машины из этой сети.
- Основной интерфейс:
[Match] Name=eth0 [Network] DHCP=yes VLAN=prac
- Мост:
Файл allprac.netdev:
[NetDev] Name=allprac Kind=bridge
Файл allprac.network:
[Match] Name=allprac [Link] ActivationPolicy=always-up
Интерфейс prac@eth0:
Файл prac.netdev:
[NetDev] Name=prac Kind=vlan [VLAN] Id=61
Файл prac.network:
[Match] Name=prac [Network] Bridge=allprac
Настройка автоматической конфигурации по DHCP
Это самый простой вариант:
… [Network] DHCP=on
systemd-networkd умеет в DNS, но только посредством systemd-resolved — в следующей лекции
Д/З
Образ обновился:
В .bashrc и .bas_profile добавлены «башизмы» (read -t … -d … вместо dd). Это позволило поднять тайм-аут при определении типа терминала до 1 секунды, но сократить время, если ответ приходит быстрее
Задание 8
Суть: две виртуалки объединить в сеть (интерфейсами eth1), настроить сеть с помощью systemd-networkd и запустить три сетевых сервиса: два вырожденных и один простой
Первый сервис получает на вход произвольный файл, и выдаёт на выход hexdump этого файла в любом удобном для решения задачи формате
- Второй сервис выполняет обратную задачу
- Третий сервис запускается на другой виртуалке, и он посложнее.
- На вход подаётся три или более текстовых строк в формате ASCII
- Шаблон (первая строка)
- Замена (вторая строка)
- Текст из одной или более строк
- На выходе должен получиться «текст», в котором все вхождения «шаблона» заменены на «замену».
- На вход подаётся три или более текстовых строк в формате ASCII
Задача:
Настроить на обоих хостах сеть с помощью systemd-networkd (в отчёт не входит)
Оформить все три сервиса как чисто текстовые обработчики с сокет-активацией. С помощью этих сервисов организовать замену произвольного байта на любой другой произвольный байт (каждый байт — это две шестнадцатеричные цифры).
- Настройка сети и запуск служб производятся заранее и в отчёт не входят
Подсказка: почитайте systemd.exec: имеет смысл отделить stderr сервиса от stdout
Спойлер: первые два сервиса за нас сделает xxd с ключами -c1 -p и -r -p соответственно.
- Площадка:
srv — хост с двумя вырожденными сервисами (1) и (2)
client — хост с сервисом замены текста (3). Для программирования на client доступны (можно пользоваться чем угодно, что найдёте в образе; я выбрал python3):
bash (на bash+sed это три строки), awk, … прочие стандартные утилиты linux, python3, perl
- Отчёт:
report 8 client
Сделать networkctl status eth1 -n 1
Сделать systemctl cat сервису (3) и его сокету
Если для обработки написан какой-то скрипт на каком-то языке, сделать ему cat
Подать на вход сервису три строки: 33, 44 и 33, и убедиться, что он возвращает 44:
echo -e '33\n44\n33' | netcat localhost порт
Сделать systemctl status сокету: должно показать нулевое количество соединений в данный момент (Connected:) и ненулевое — обслуженных соединений (Accepted:)
report 8 srv
Сделать networkctl status eth1 -n 1
Сделать systemctl cat обоим сервисам и их сокетам
Сделать systemctl status обоим сокетам
- Проверить, что преобразование в сервисах обратимо:
date > d; netcat localhost порт1 < d | netcat localhost порт2 | cmp d -
Собрать следующий конвейер из netcat-ов:
{ echo 09; echo 2d; netcat localhost порт1 < /etc/crontab.template; } | netcat клиент порт | netcat localhost порт2
- (табуляции должны замениться минуcами)
Сделать systemctl status обоим сокетам: должно показать нулевое количество соединений в данный момент (Connected:) и ненулевое — обслуженных соединений (Accepted:)
Два отчёта(названия сохранить, должно быть: report.08.srv, report.08.client) переслать одним письмом в качестве приложений на uneexlectures@cs.msu.ru
В теме письма должно встречаться слово LinuxNetwork2024