Программирование, радиоэлектроника,
саморазвитие и частичка из моей жизни здесь...

Самодельный роутер и мини-сервер на Raspberry Pi - Часть 2 (программы)

В прошлой статье было рассказано об аппаратной части самодельного сервера (роутера) и его конструкции. В этой статье я расскажу как установить и настроить операционную систему Raspbian (GNU/Linux), подготовить программы для работы с сетью: ssh, iw, iptables, hostapd, isc-dhcp, wvdial, minicom.

Также, приведу простые скрипты на языке Python для вывода информации на дисплей SSD1306, воспроизведения звуковых сигналов, считывания информации с кнопок и другую полезную информацию.

Содержание:

  1. Структура сети и ее работа
  2. Подготовка Micro-SD карты с Raspbian
  3. Первое включение и базовая настройка Raspbian
  4. Подключение к сети и обновление ПО
  5. Установка необходимого программного обеспечения
  6. Оптимизация файловых систем
  7. Сетевые настройки и SSH
  8. Мощность передатчика Wi-Fi карты, регуляторный домен
  9. Настройка брандмауэра IPTables, роутинг и защита
  10. Беспроводная точка доступа (Access Point) на основе HOSTAPD
  11. Настройка демона ISC-DHCP-Server
  12. Решение проблемы старта isc-dhcpd и активации сетевых интерфейсов
  13. Настройка статического списка DNS-серверов
  14. Подготовка 3G-модема, узнаем его состояние используя minicom
  15. 3G-модем и консольная звонилка WVDIAL
  16. Режимы управления частотой CPU в Raspberry Pi и его температура
  17. Настройка часов реального времени (RTC)
  18. Считываем показания термодатчика DS18B20
  19. Генерация звуковых сигналов через пьезо-зуммер
  20. Управление RGB-светодиодом и реагирование на нажатия кнопок
  21. Набор скриптов для управления
  22. Другие полезности
  23. В завершение

Структура сети и ее работа

Поскольку наш самодельный мини-сервер будет выполнять роль сетевого маршрутизатора (роутер, router), то целесообразно предварительно спланировать структуру сети с использованием данного устройства.

Структура сети, управляемой самодельным маршрутизатором (роутером) построенном на основе Raspberry PI

Рис. 1. Структура сети, управляемой самодельным маршрутизатором (роутером) построенном на основе Raspberry PI.

Маршрутизатор может быть подключен к интернету используя один из каналов:

  1. Проводной, через USB-ethernet адаптер (интерфейс eth1);
  2. Беспроводный, через USB 3G адаптер (интерфейс ppp0).

Сетевые устройства могут быть подключены к маршрутизатору через следующие каналы:

  1. Проводной (eth0) - через сетевой свич (Ethernet switch): сервер, рабочая станция, ноутбук и т.п.
  2. Беспроводной (wlan0) - Wi-Fi: смартфон, планшет, ноутбук и другие беспроводные устройства.

USB-3G модем используется как резервный вариант в случае пропадания проводного канала, также возможно использовать его как основной канал.

Пропускная способность проводной сети составит 100Мбит/c. Она ограничена скоростью встроенного Ethernet-порта Raspberry Pi, USB-Ethernet адаптера, а также скоростью сетевого коммутатора.

Пропускная способность беспроводной сети может колебаться в значительных пределах и зависит от качества Wi-Fi сигнала между соединенными устройствами. Скорость интернета в варианте с 3G-модемом зависит от выбранного тарифа, уровня сигнала и возможностей самого модема.

В данном случае, внешние сетевые интерфейсы - это eth1 и ppp0, а внутренние - eth0 и wlan0.

Адреса для интерфейсов:

  • eth0 - 192.168.1.1 /24
  • wlan0 - 192.168.2.1 /24
  • eth1 - DHCP (получаем адрес от интернет-провайдера)
  • ppp0 - PPP (получаем адрес от интернет-провайдера)

Пулы адресов, зарезервированные для DHCP-сервера, который будет обслуживать внутренние LAN и WLAN сети:

  • eth0: 192.168.1.10 - 192.168.1.100
  • wlan0: 192.168.2.10 - 192.168.2.100

Остальные доступные адреса можно использовать для устройств со статическими сетевыми настройками или же чтобы обозначить какое-то конкретное устройство.

Например, можно выделить тестовому серверу легко запоминающийся адрес 192.168.1.111 (подключение по кабелю), а рабочему ноутбуку - 192.168.2.2 (подключение по Wi-Fi).

Все устройства из подсети 192.168.1.1/24 будут доступны для связи устройствам из подсети 192.168.2.1/24 и наоборот. Таким образом можно будет осуществлять коммуникацию между сетевыми устройствами, которые подключены к проводному и беспроводному (Wi-Fi) интерфейсам роутера.

Сетевые пакеты, проходящие через любой из интерфейсов ppp0 или eth1 (интернет-трафик), будут транслироваться с изменением их адресов (masquarade, NAT) для использования во внутренней сети.

Также, на этих интерфейсах выполним фильтрацию входящих пакетов и защиту от вторжений используя мощь iptables.

Как видите, структура сети совсем не сложная и достаточно универсальная. Можем приступать к реализации схемы.

Подготовка Micro-SD карты с Raspbian

Раньше, в одной из статей, я уже подробно описывал процесс установки Raspbian на Micro-SD карту в операционных системах (ОС) Microsoft Windows и GNU/Linux, также там описаны нюансы подбора флешь-карточки и другиая полезная информация. Поэтому, здесь я лишь кратко распишу как установить Raspbian.

Скачиваем архив с образом операционной системы с официального сайта Raspbian.

В данном случае, мною был скачан архив "2018-04-18-raspbian-stretch.zip" (1,6Гб), в котором запакован файл "2018-04-18-raspbian-stretch.img" (4,6Гб) - образ операционной системы Raspbian Stretch (Debian 9). Я сохранил его в папку "/home/master/Downloads" на своем рабочем Linux-ПК.

Установим архиватор 7-Zip (для распаковки архива) и программу "pv" (для мониторинга за потоком данных):

sudo apt-get install p7zip-full pv

Распакуем архив:

cd /home/master/Downloads
7z x 2018-04-18-raspbian-stretch.zip

Установим Micro-SD карту в карт-ридер и узнаем название ее блочного устройства:

lsblk
sdX             8:32   1  14.5G  0 disk 
├─sdX1          8:33   1    56M  0 part 
└─sdX2          8:34   1  14.4G  0 part

Вместо "X" подставьте букву для своего полученного устройства и можно приступать к процессу записи образа ОС на карту памяти:

sudo pv 2018-04-18-raspbian-stretch.img | sudo dd of=/dev/sdX bs=4M

Запустим команду для сброса буферов записи и дождемся завершения ее работы:

sync

Теперь можно смело извлечь Micro-SD карту из карт-ридера и установить ее в компьютер Raspberry Pi.

Первое включение и базовая настройка Raspbian

Подключаем к нашему самодельному мини-серверу USB-клавиатуру и мышь (удобно использовать беспроводный комплект), к HDMI-выходу подключаем монитор. Включаем питание.

Дожидаемся загрузки графического интерфейса и запускаем программу "Терминал" (Консоль). В терминале запускаем конфигуратор малинки:

sudo raspi-config

Настройки по пунктам:

Change User Password - устанавливаем пароль доступа, желательно длиной от 8 и более символов.

Network options -> Hostname - меняем название системы, например на "myserver".

Boot options:

  • Desktop / CLI -> Text console, requiring user to login - отключаем запуск графической оболочки при старте системы, будет загружена консоль с запросом авторизации. В будущем для запуска графической среды достаточно будет выполнить команду "startx" из консоли.
  • Wait for Network at Boot -> Yes - ожидать завершения инициализации сетевой подсистемы при старте.
  • Splash Screen -> Would you like to show the splash screen at boot? -> No - не отображать заставку при старте.

Localisation Options -> Change Locale:

  • en_US.UTF-8,  ru_RU.CP1251, ru_RU.KOI8-R, ru_RU.UTF-8,  uk_UA.UTF-8, uk_UA.KOI8-R;
  • Default locale for the system environment -> en_US.UTF-8 - выбор системной локали по умолчанию, если желаете то можете выбрать украинскую или русскую.

Localisation Options -> Change Timezone - установка временной зоны, например Europe -> Kiev.

Localisation Options -> Change Keyboard Layout:

  • Generic 105-key (Intl) PC
  • English UK
  • Key to function as AltGr -> The default for the keyboard
  • Compose key -> No compose key
  • Use Control+Alt+Backspace to terminate teh X server? -> No

Localisation Options -> Change Wi-fi Country - выбор страны для Wi-Fi, например "UA Ukraine". Очень важная настройка!

Interfacing options:

  • SSH -> Would you like the SSh server to be enabled? -> Yes - включаем SSH-службу для удаленного доступа к консоли по сети;
  • I2C -> Would you like the ARM I2C interface to be enabled? - Yes - включаем I2C-шину для доступа к дисплею SSD1306 и часам реального времени DS1307;
  • 1-Wire -> Would you like the one-wire interface to be enabled? - Yes - включаем 1-Wire шину для доступа к датчику температуры DS18B20.

Advanced options:

  • Expand filesystem - расширяем файловую систему ОС для использования всего доступного на Micro-SD карте пространства;
  • Memory Split -> 64 - выбираем количество оперативной памяти, выделяемое под графический адаптер. Значение 64МБ - оптимальное если планируется использовать графическую оболочку, в противном случае можно установить 32МБ или 16МБ.

Подключение к сети и обновление ПО

Для возможности удаленного доступа к малинке через SSH выполним первичную настройку проводной сети. Это позволит удобно выполнять настройки, копировать файлы и редактировать скрипты.

Подключим малинку к ноутбуку или рабочему ПК используя сетевой кабель и сетевой коммутатор. Можно также непосредственно подключить два устройства без сетевого коммутатора, в таком случае понадобится сетевой кабель RJ-45 c перевернутой разводкой проводов (кросс).

Вариант 1: [notebook |RJ-45>----кабель1----<RJ-45| Ethernet switch |RJ-45>----кабель2----<RJ-45| Raspberry Pi]
Вариант 2: [notebook |RJ-45>----кабель_кросс----<RJ-45| Raspberry Pi]

На ноутбуке (или ПК) установим статический IP-адрес - 192.168.1.2.

Начиная с Raspbian Stretch (Debian 9) статические настройки для сетевых интерфейсов прописываются в конфигурационном файле для DHCP клиента (DHCP Client Daemon) - "/etc/dhcpcd.conf". В более старых версиях ОС, например Raspbian Jessie (Debian 8) - это делалось с помощью файла "/etc/network/interfaces".

Теперь, присвоим на малинке интерфейсу eth0 сетевой адрес 192.168.1.1.  Для добавления настроек статической адресации откроем файл "dhcpcd.conf":

sudo nano /etc/dhcpcd.conf

Добавляем в самый низ файла следующие строчки:

interface eth0
static ip_address=192.168.1.1/24

Выходим из редактора (CTRL+X), подтверждаем сохранение содержимого файла (Y + ENTER).

Выполним перезагрузку Raspbian:

sudo reboot

Проверяем есть ли связь на ноутбуке (ПК) с сетевым адресом 192.168.1.1, пробуем подключиться к Raspberry PI используя этот же адрес:

ping 192.168.1.1
ssh pi@192.168.1.1

Будет запрошен пароль для авторизации по SSH - мы установили его на этапе начальной конфигурации.

Теперь, подключившись к Raspberry Pi удаленно по SSH, можно отключить клавиатуру и мышь от мини-компьютера. Но прятать далеко их не стоит, они еще могут понадобиться в случае если не удастся выполнить подключение к малинке по SSH и для решения других возможных проблем в процессе настройки.

Подключаем USB-Ethernet адаптер к одному из свободных USB-портов самодельного роутера, также подключаем к этому же адаптеру сетевой кабель с интернетом от провайдера или модема/роутера.

USB-Ethernet адаптер должен автоматически определиться малинкой, а его интерфейс получить IP-адрес, сетевой шлюз (Gateway) и список DNS-серверов от провайдера интернета или домашнего роутера.

Смотрим список доступных сетевых интерфейсов и их конфигурацию, список активных сетевых маршрутов, а также список DNS-серверов, полученных по DHCP:

ip -c a
ip route
cat /etc/resolv.conf

 На малинке должен появиться интернет. Проверим доступен ли DNS-сервер Google:

ping 8.8.8.8

Теперь можно выполнить обновление списков пакетов и обновить уже установленное программного обеспечение:

sudo apt-get update
sudo apt-get upgrade

Настроим автоматическую установку критических обновлений безопасности:

sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

На запрос последней команды отвечаем утвердительно - Yes.

Выполним принудительный запуск unattended-upgrades для проверки работоспособности:

sudo unattended-upgrades -d

На этом этапе желательно перезагрузить Raspberry Pi и повторно проверить работоспособность сети и интернета.

Установка необходимого программного обеспечения

Выполним установку необходимого для работы и функционирования программного обеспечения. Базовый набор инструментов:

sudo apt-get install mc htop p7zip-full lynx tmux
  • mc - Midnight Commander, консольный двухпанельный файловый менеджер;
  • htop - мониторинг производительности и ресурсов системы;
  • p7zip-full - мощный архиватор 7Zip;
  • tmux - Terminal Multiplexor, удобный мультифункциональный эмулятор терминалов.

Полезности для работы с USB-модемом:

sudo apt-get install usb-modeswitch usb-modeswitch-data wvdial ppp minicom
  • usb-modeswitch - набор скриптов для автоматического переключения режима работы модемов;
  • wvdial - программа дозвона для модема;
  • ppp - служба для поддержки протокола Point-to-Point;
  • minicom - терминал с возможностью подключения к последовательным портам.

Сетевые программы:

sudo apt-get install tcpdump nmap netdiag hostapd isc-dhcp-server
  • tcpdump - сниффер сетевых пакетов;
  • nmap - мощный сетевой сканер, легендарная программа;
  • netdiag - пакет, содержащий несколько полезных утилит, в особенности "trafshow" для мониторинга подключений;
  • hostapd - служба для создания беспроводной точки доступа IEEE 802.11 AP  и IEEE 802.1X/WPA/WPA2/EAP авторизатор ;
  • isc-dhcp-server - популярный DHCP сервер.

Мониторинг дисковых операций:

sudo apt-get install iotop sysstat
  • iotop - мониторинг операций ввода-вывода (I/O);
  • sysstat - набор утилит для мониторинга производительности в GNU/Linux.

Оптимизация файловых систем

Для работы малинки в качестве роутера можно провести ряд оптимизаций, которые снизят количество операций записи на карту. Можно отключить логирование для некоторых программ и демонов, отключить отслеживание времени последнего доступа к файлам, а также перенести некоторые разделы на TMPFS (файловая система в оперативной памяти).

Для того чтобы узнать какие программы выполняют интенсивный обмен данными с накопителем данных (картой памяти), можно использовать утилиту iotop:

sudo iotop -bktoqqq

Пояснение ключей запуска:

  • b - batch, включить не интерактивный режим;
  • k - отображать значения в Килобайтах;
  • t - показать временную метку для каждой строчки;
  • o - отобразить только активные процессы ввода-вывода;
  • qqq - не выводить суммарную информацию.

Увидим примерно следующую картину (фрагмент):

08:06:44    94 be/3 root        0.00 K/s   46.61 K/s  0.00 % 20.63 % [jbd2/mmcblk0p2-]
08:06:46   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.05 % [kworker/3:2]
08:06:48   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.05 % [kworker/3:2]
08:06:50   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.05 % [kworker/3:2]
08:06:52   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.05 % [kworker/3:2]
08:06:54   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.06 % [kworker/3:2]
08:06:55   537 be/4 root        0.00 K/s   11.13 K/s  0.00 %  0.00 % rsyslogd -n [rs:main Q:Reg]
08:06:56   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.06 % [kworker/3:2]
08:06:59   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.05 % [kworker/3:2]
08:07:01    94 be/3 root        0.00 K/s    7.41 K/s  0.00 %  1.88 % [jbd2/mmcblk0p2-]
08:07:01   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.06 % [kworker/3:2]
08:07:03   139 be/4 root        0.00 K/s    0.00 K/s  0.00 %  0.06 % [kworker/3:2]
08:07:03   537 be/4 root        0.00 K/s   14.83 K/s  0.00 %  0.00 % rsyslogd -n [rs:main Q:Reg]
08:07:03  1412 be/4 root        0.00 K/s    7.42 K/s  0.00 %  0.00 % sshd: pi [priv]

Также можно понаблюдать за суммарной статистикой ввода-вывода для накопителей данных, используя утилиту iostat:

iostat -dzp 5

Ключи запуска:

  • d - отобразить отчет об использовании устройств;
  • z - не выводить данные для неактивных устройств;
  • p - отображать все блочные устройства и их разделы;
  • 5 - интервал обновления.

Вывод программы будет иметь следующий вид:

Linux 4.9.35-v7+ (myserver)    24.08.17        _armv7l_        (4 CPU)

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
mmcblk0           4,11       116,12        43,40     208752      78024
mmcblk0p1         0,05         1,12         0,00       2015          0
mmcblk0p2         4,04       114,78        43,40     206337      78024

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
mmcblk0           0,40         0,00         3,20          0         16
mmcblk0p2         0,40         0,00         3,20          0         16

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn

Таким образом, можно узнать какие системные и запущенные вручную программы наиболее активно обращаются к диску.

Перейдем непосредственно к оптимизациям, вот в чем они заключаются:

  • Отключаем операции записи временных меток доступа к папкам и файлам (noatime, nodiratime);
  • Переносим директории "/tmp", "/var/log", "/var/spool/mqueue" и "/var/tmp" в оперативную память (tmpfs);
  • Отключаем файл подкачки (swap).

Все эти меры помогут минимизировать количество операций записи на карту памяти.

Редактируем файл "fstab" с описанием всех монтируемых файловых систем:

sudo nano /etc/fstab

Для раздела с точкой монтирования "/" добавляем флаги "noatime,nodiratime", также добавляем строчки для монтирования директорий в файловую систему "tmpfs". Примерный вид файла "fstab":

proc            /proc           proc    defaults          0       0
PARTUUID=afb93022-01  /boot           vfat    defaults  0       2
PARTUUID=afb93022-02  /               ext4    defaults,noatime,nodiratime  0       1
tmpfs    /tmp               tmpfs   nodev,nosuid,nodiratime,size=256M              0    0
tmpfs    /var/log           tmpfs   defaults,noatime,nosuid,mode=0755,size=50M     0    0
tmpfs    /var/spool/mqueue  tmpfs   defaults,noatime,nosuid,mode=0700,size=20M     0    0
tmpfs    /var/tmp           tmpfs   defaults,noatime,nosuid,size=256M              0    0
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that

С такой конфигурацией все системные логи, письма в очереди на отправку и временные файлы будут записываться в файловой системе, выделяемой из оперативной памяти, после выключения питания малинки вся эта информация будет безвозвратно утеряна.

Если нужно сохранять логи, или же временно включить их сохранение, то достаточно закомментировать строчку "tmpfs    /var/log...". Подобным образом можно поступить и с другими точками монтирования, а также если нужно добавить свои.

Еще один из вариантов хранения логов и другой статической информации - подключить и подмонтировать миниатюрный USB-флешь накопитель с размером памяти 2-8G.

Максимальные значения оперативной памяти, которые могут быть выделены для точек монтирования в приведенном случае:

  • /tmp  - 256M;
  • /var/log  - 50M;
  • /var/spool/mqueue  - 20M;
  • /var/tmp  - 256M.

В суме: 256 + 50 + 20 + 256 = 582(М).

Оперативная память в файловой системе tmpfs используется по мере необходимости, это значит что если в /tmp записать файл размером 10М, то при максимально допустимом размере файловой системы 256M реальной памяти будет использовано примерно 10М.

В Raspberry Pi 3 B установлено 1G оперативной памяти, поэтому если будут заполнены все файловые системы "tmpfs" (что маловероятно) то на все остальное останется примерно 400М.

В некоторых случаях (просмотр содержания больших архивов через mc, установка определенного ПО которое использует много места во временной файловой системе и т.п.) выделенной памяти в 256М для раздела /tmp может быть маловато.

Чтобы выйти из этой ситуации можно временно закомментировать строчку отвечающую за монтирвоание "tmpfs" для "/tmp", перезагрузить малинку и выполнить все нужные операции, а потом вернуть все как прежде. Также можно попробовать увеличить размер файловой системы с 256М до 512М.

Идем дальше. Осталось отключить и удалить файл подкачки:

sudo dphys-swapfile swapoff
sudo systemctl disable dphys-swapfile
sudo rm /var/swap

В случае неполадок или ошибок после редактирования файла "fstab" операционная система может быть загружена в однопользовательском режиме, нормальный режим загрузки станет недоступным.

Чтобы исправить записи в файле "fstab" нужно перемонтировать корневую файловую систему в режиме записи и отредактировать файл fstab:

mount -o,remount /
nano /etc/fstab

После внесения изменений перезагружаем малинку.

Сетевые настройки и SSH

Разрешим пересылку IPv4 пакетов между сетевыми интерфейсами, а также отключим сетевой протокол IPv6. Для домашней сети IPv6 избыточен, поэтому мы его использовать не будем.

Открываем для редактирования файл "/etc/sysctl.conf":

sudo nano /etc/sysctl.conf

 Добавляем в самый низ его содержимого следующие строки:

net.ipv4.ip_forward=1

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Добавим в файл "/etc/network/interfaces" настройки для поддержки "горячего" извлечения сетевых устройств, относящихся к интерфейсам wlan0(может быть USB-адаптер, например в малинке 2-й версии) и eth1(USB-адаптер). Также укажем что эти интерфейсы настраиваются вручную (их настройками будет управлять сконфигурированный нами сетевой демон DHCPCD).

sudo nano /etc/network/interfaces

Добавляем описания для интерфейсов:

allow-hotplug eth1
iface eth1 inet manual

allow-hotplug wlan0
iface wlan0 inet manual

Раньше нами уже был прописан статический IPv4-адрес для интерфейса eth0, осталось задать статический адрес для интерфейса беспроводной сети wlan0. Также нам нужно запретить использование механизма WPA-авторизации, что позже позволит использовать этот сетевой интерфейс для создания на его основе беспроводной точки доступа (Wireless Access Point).

sudo nano /etc/dhcpcd.conf

Заменяем ранее добавленные строчки для интерфейса eth0 следующим содержимым:

nohook wpa_supplicant

interface eth0
static ip_address=192.168.1.1/24

interface wlan0
static ip_address=192.168.2.1/24

Вы можете ознакомиться с назначением директив в файле "dhcpcd.conf" используя встроенную справочную систему:

man dhcpcd.conf

Перезагружаем малинку и смотрим статус службы dhcpcd:

sudo reboot
sudo systemctl status dhcpcd.service

Смотрим присвоены ли нужные нам статические IP-адреса для интерфейсов eth0 и wlan0:

ip -c a | grep  eth0 && ip -c a | grep  wlan0

Вы можете заметить что интерфейсу wlan0 не присвоен установленный нами IP-адрес, в действительности здесь все нормально - он появится позже, когда интерфейс будет инициализирован после настройки беспроводной точки доступа.

Фикс уязвимостей CVE-2016-0777 и CVE-2016-0778 для безопасности SSH-клиента:

sudo nano /etc/ssh/ssh_config

Добавить вниз файла строку:

UseRoaming no

В SSH-демоне по умолчанию включено выполнение DNS-запросов для получения имени удаленного хоста (который питается подключиться), эта возможность используется для того чтобы убедиться что обратное преобразование имени вернет идентичный IP-адрес, служит в целях безопасности. Следующий фикс ускорит SSH-подключения к нашему самодельному серверу из машин в локальной сети.

sudo nano /etc/ssh/sshd_config

Нужно найти (CTRL+W) и раскомментировать строку:

UseDNS no

Мощность передатчика Wi-Fi карты, регуляторный домен

В Raspberry Pi 3 (model B) встроен достаточно мощный модуль Wi-Fi. Мне нигде не удалось найти точных данных о выходной мощности беспроводного модуля для малинки, поэтому определил ее примерное значение экспериментально.

Значения мощности часто указывают по логарифмической децибельной шкале - в Децибелах (дБ, Decibel, dB). Если измерение выполняется относительно единицы мощности милливатт (мВт), то в децибеллах (дБ) это значение обозначается как "дБм" или "dBm" (0 dBm = 1mW).

Выходная мощность излучения беспроводного адаптера часто указывается и задается именно в dBm. Для простого перевода значений dBm в милиВатты можно воспользоваться следующей табличкой:

Значение, дБм Значение, мВт      Значение, дБм Значение, мВт
-1 0,8   21 125
0 1   22 160
1 1,259   23 200
2 1,6   24 250
3 1,995   25 320
4 2,5   26 400
5 3,2   27 500
6 3,981   28 640
7 5   29 800
8 6,4   30 1000
9 8   31 1250
10 10   32 1600
11 12,5   33 2000
12 16   34 2500
13 20   35 3200
14 25   36 4000
15 32   37 5000
16 40   38 6400
17 50   39 8000
18 64   40 10 000
19 80   50 100 000
20 100   60 1000 000

Увеличение мощности передатчика на 1dBm равносильно ее увеличению в 100,1 раза или примерно в 1,259 раза. Каждое прибавление 3 дБ к мощности увеличивает ее в два раза, например: 10дБ (10мВт) + 3дБ = 13дБ (20мВт) или 30дБ (1Вт) + 3дБ = 33дБ (2Вт) и т.д.

Текущую мощность передатчика (txpower, Transmit Power) для беспроводного модуля с сетевым интерфейсом wlan0 можно узнать используя команду:

iw wlan0 info

 Получим примерно следующую информацию:

Interface wlan0
        ifindex 3
        wdev 0x1
        addr b8:27:eb:6a:XX:XX
        ssid Raspberry-Pi
        type AP
        wiphy 0
        channel 6 (2437 MHz), width: 20 MHz, center1: 2437 MHz
        txpower 15.00 dBm

Здесь мы видим, что текущая выходная мощность передатчика (txpower) - 15 дБм, что равно 32мВт или 0,032Вт.

Чтобы узнать больше подробностей о текущих настройках и возможностях доступных беспроводных сетевых устройств, можно воспользоваться следующей командой:

iw list

На экран будет выведено много разной информации: поддерживаемые алгоритмы шифрования и режимы интерфейса, список возможных скоростей для передачи данных, каналов с указанием частот, поддерживаемые команды и многое другое.

Сейчас нас наиболее интересует раздел "Frequencies":

iw list | grep -A 15 Frequencies:

 В моем случае его вывод команды имеет следующий вид:

Frequencies:
  * 2412 MHz [1] (20.0 dBm)
  * 2417 MHz [2] (20.0 dBm)
  * 2422 MHz [3] (20.0 dBm)
  * 2427 MHz [4] (20.0 dBm)
  * 2432 MHz [5] (20.0 dBm)
  * 2437 MHz [6] (20.0 dBm)
  * 2442 MHz [7] (20.0 dBm)
  * 2447 MHz [8] (20.0 dBm)
  * 2452 MHz [9] (20.0 dBm)
  * 2457 MHz [10] (20.0 dBm)
  * 2462 MHz [11] (20.0 dBm)
  * 2467 MHz [12] (20.0 dBm)
  * 2472 MHz [13] (20.0 dBm)
  * 2484 MHz [14] (disabled)
Supported commands:

Здесь указаны 14 частот для 14-ти каналов, доступны из которых только 13 (14-й канал заблокирован, disabled). Выходная мощность для передатчика ограничена значением в 20 dBm (100 mW).

Выполняя базовую настройку Raspbian в разделе "Localisation Options -> Change Wi-fi Country" мы раньше установили страну для Wi-Fi - UA (Украина).

В каждой стане действуют свои правила и ограничения по использованию частот и беспроводного сетевого оборудования. Для большинства стран мира доступны каналы 1-13, а 14-й канал недоступен к использованию, исключением здесь является Япония, где в некоторых режимах работа на 13-м канале все же возможна. Для соединенных штатов доступны каналы 1-11.

Для реализации правил использования частот при работе с сетевым оборудованием в разных странах используются регуляторные домены.

Регуляторный домен (Regulatory Domain, regdomain) - это специальный набор правил, специфичный для каждой страны, который регулирует использование частот, может ограничивать мощность радиопередатчика, не допускать использование некоторых технологий и возможностей при передаче данных в беспроводных сетях.

При работе с регуляторными доменами в GNU/Linux используется CRDA (Central Regulatory Domain Agent). Чтобы узнать правила и ограничения регуляторного домена для вашей страны можно воспользоваться публичной базой данных - 

https://www.kernel.org/pub/software/network/wireless-regdb/

Скачиваем самый свежий архив, открываем файл "db.txt" и ищем там индекс своей страны. Пример для Украины:

country UA: DFS-ETSI
	(2400 - 2483.5 @ 40), (20), NO-OUTDOOR
	(5150 - 5250 @ 80), (20), NO-OUTDOOR, AUTO-BW
	(5250 - 5350 @ 80), (20), DFS, NO-OUTDOOR, AUTO-BW
	(5490 - 5670 @ 160), (20), DFS
	(5735 - 5835 @ 80), (20)
	# 60 GHz band channels 1-4, ref: Etsi En 302 567
	(57000 - 66000 @ 2160), (40)

Там же найдете ссылки на регуляторные документы своей страны и другую полезную информацию.

Чтобы узнать какой регуляторный домен используется в текущий момент на малинке, достаточно выполнить следующую команду:

iw reg get

В моем случаем вывод команды будет почти идентичным (за исключением комментария), как и в примере из файла "db.txt" для Украины. Здесь видно что для диапазона частот 2400 - 2483(МГц) выходная мощность передатчика ограничивается значением 20dBm (100 мВт).

В данном случае, попытка установить мощность передатчика выше 20dBm, скорее всего, не даст практического результата - мощность будет ограничиваться текущим регуляторным доменом (ядром ОС, использующим этот набор правил).

Для установки или смены регуляторного домена в GNU/Linux применяется следующая команда:

sudo iw reg set UA

Здесь вместо "UA" может быть "US", "VE" или другой код страны. Сменив регуляторный домен, мы сменим правила, по которым ядро ОС применяет ограничения при использовании беспроводных сетевых устройств.

Есть регуляторные домены, в которых для некоторых частот запрещено использовать режим точки доступа (AP, Access Point), поэтому нужно с ответственностью и пониманием отнестись к установке этой опции.

Чтобы обойти ограничение на 20dBm, в моем случае можно выбрать регуляторный домен "VE" и изменить мощность передатчика в большую сторону - 30dBm, но это уже будет нарушением правил по использованию частот для моей страны. К тому же, мне не нужна такая большая мощность, даже наоборот - мы будем ее снижать, зачем нам лишнее излучение вокруг нас.

Установить мощность Wi-Fi передатчика для интерфейса wlan0 можно следующей командой:

sudo iwconfig wlan0 txpower 10

В данном случае "10" - это значение мощности в дБм (dBm), которое равно 10мВт. Такой мощности может вполне хватить чтобы покрыть беспроводной сетью небольшую комнату, в которой расположен роутер.

Данное изменение будет действовать только до перезагрузки ОС. Чтобы установка требуемого значения мощности выполнялась каждый раз при загрузке ОС, нужно добавить вышеуказанную команду в какой-то из скриптов, запускаемых при старте системы.

Мы же заставим эту команду выполняться при готовности сетевого интерфейса, в файле "/etc/network/interfaces". Там же можно и добавить команду установки регуляторного домена, если нужно. Откроем этот файл в редакторе:

sudo nano /etc/network/interfaces

Добавим секцию из двух строчек для интерфейса wlan0, настройки получат следующий вид:

allow-hotplug wlan0
iface wlan0 inet manual
    up iw reg set UA
    up iwconfig wlan0 txpower 10

Статический IP-адрес для этого интерфейса мы уже раньше указали в файле "/etc/dhcpcd.conf", поэтому здесь ничего больше добавлять не нужно.

Перезагружаем малинку и смотрим установилась ли нужная мощность передатчика и нужный регуляторный домен:

sudo reboot
iw wlan0 info
iw reg get

Настройка брандмауэра IPTables, роутинг и защита

С помощью IPTables мы будем выполнять следующие задачи:

  • Разрешим пересылку сетевых пакетов между внутренними подсетями (интерфейсы eth0, wlan0);
  • Выполним трансляцию сетевых пакетов (NAT, masquarade) через интерфейсы, которые выходят в интернет (ppp0, eth1);
  • Разрешим подключение к роутеру через внутренние интерфейсы eth0, wlan0 используя порт 22 (SSH);
  • Разрешим все входящие пакеты, относящиеся к уже установленным подключениям (для цепочек INPUT и FORWARD);
  • Запретим все остальные входящие соединения на любом из сетевых интерфейсов;
  • Ограничим возможность сканирования роутера с использованием TCP-пакетов со специальными флагами.

Это достаточно жесткая политика, тем не менее, она позволит неплохо защитить ваш роутер. Вы сможете устанавливать исходящие соединения и принимать входящие, которые относятся к уже установленным исходящим, использовать интернет, свободно работать с сетевыми устройствами во внутренней сети.

На роутере будет открыт для подключения только порт 22 (SSH, для администрирования), все остальные попытки "достукаться" до роутера со стороны провайдера или другого промежуточного маршрутизатора (через интерфейсы eth1, ppp0) будут бесполезны. Ваш роутер не смогут даже "пропинговать" (командой ping) снаружи, поскольку будут отсекаться все ICMP-пакеты.

Если же вам не нужна такая жесткая политика, то вы можете настроить брандмауэр на свое усмотрение, исправив, добавив или удалив какие-то из правил.

Для построения набора правил IPTables в Raspbian можно использовать пакет "iptables-persistent", который при каждом старте ОС будет выполнять загрузку правил брандмауэра с ранее сохраненной конфигурацией.

Я же предлагаю использовать отдельный скрипт, который будет загружаться системой через systemd. В одной из статей я приводил скрипт IPTables для ipv4 и ipv6 с автозагрузкой в Linux, здесь будет использована немного упрощенная (без IPv6) и модифицированная версия этого скрипта.

Создаем файл скрипта с будущими правилами, откроем его для редактирования:

sudo nano /usr/local/sbin/systemd-iptables.sh

Вставляем в окно редактора следующий код:

#!/bin/sh
# IPTables init script for systemd
# Project: Raspberry Pi Router
# by ph0en1x - https://ph0en1x.net

IPT=/sbin/iptables

ETH=eth0
WLAN=wlan0
PPP=ppp0
ETH_EXT=eth1

# Flush active rules, flush custom tables, and set default policy
Flush_Rules () {
	$IPT --flush
	$IPT -t nat --flush
	$IPT -t mangle --flush
	$IPT --delete-chain
	$IPT -t nat --delete-chain
	$IPT -t mangle --delete-chain
	# Set default policies to ACCEPT
	$IPT -P INPUT ACCEPT
	$IPT -P FORWARD ACCEPT
	$IPT -P OUTPUT ACCEPT
}

# Loading rules
Load_Rules () {
        # Flush
        Flush_Rules
        # DEFAULT POLICIES
        $IPT -P INPUT DROP
        $IPT -P FORWARD DROP
        $IPT -P OUTPUT ACCEPT

        # PASS localhost traffic
        $IPT -A INPUT  -i lo -j ACCEPT
        $IPT -A OUTPUT -o lo -j ACCEPT

        # ALLOW traffic from already established connections
        $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
        # ALLOW local connections to router via SSH
        $IPT -A INPUT -p tcp --dport 22 -i $ETH -j ACCEPT
        $IPT -A INPUT -p tcp --dport 22 -i $WLAN -j ACCEPT
        # DROP all other incoming connections
        $IPT -A INPUT -j DROP

        # ALLOW packets forwarding between internal networks
        $IPT -A FORWARD -i $ETH -o $WLAN -j ACCEPT
        $IPT -A FORWARD -i $WLAN -o $ETH -j ACCEPT
        # ALLOW packets forwarding between local net and internet
        $IPT -A FORWARD -i $PPP -o $ETH -m state --state RELATED,ESTABLISHED -j ACCEPT
        $IPT -A FORWARD -i $ETH -o $PPP -j ACCEPT
        $IPT -A FORWARD -i $PPP -o $WLAN -m state --state RELATED,ESTABLISHED -j ACCEPT
        $IPT -A FORWARD -i $WLAN -o $PPP -j ACCEPT
        
        $IPT -A FORWARD -i $ETH_EXT -o $ETH -m state --state RELATED,ESTABLISHED -j ACCEPT
        $IPT -A FORWARD -i $ETH -o $ETH_EXT -j ACCEPT
        $IPT -A FORWARD -i $ETH_EXT -o $WLAN -m state --state RELATED,ESTABLISHED -j ACCEPT
        $IPT -A FORWARD -i $WLAN -o $ETH_EXT -j ACCEPT

        # DROP all other forwarding traffic
        $IPT -A FORWARD -j DROP 

        # DROP ports scanning traffic
        $IPT -N PORT-SCAN
        $IPT -A PORT-SCAN -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j RETURN
        $IPT -A PORT-SCAN -j DROP

        # NAT for external interface
        $IPT -t nat -A POSTROUTING -o $PPP -j MASQUERADE
        $IPT -t nat -A POSTROUTING -o $ETH_EXT -j MASQUERADE
}


case $1 in
	start)
		Load_Rules
		echo "IPTables rules loaded."
		;;
	stop)
		Flush_Rules
		echo "IPTables rules flushed."
		;;
	restart)
		Flush_Rules
		Load_Rules
		echo "IPTables rules reloaded."
		;;
	*)
		echo "Usage: systemctl {start|stop|restart} iptables.service"
		exit 1
esac

exit 0

В начале скрипта указаны названия задействованных интерфейсов:

  • ETH - проводной сетевой интерфейс (внутренняя сеть)
  • WLAN - беспроводной (Wi-Fi) сетевой интерфейс (внутренняя сеть)
  • PPP - беспроводной (USB-3G) сетевой интерфейс (Internet)
  • ETH_EXT - проводной сетевой интерфейс (Internet)

В самом начале статьи была приведена схема сети с использованием будущего роутера на основе малинки, не ленитесь еще раз на нее взглянуть чтобы более четко понять структуру сети и работу скрипта с правилами IPTables.

В процедуре "Flush_Rules" выполняется очистка правил для всех цепочек брандмауэра, установка разрешающей (ACCEPT) сетевой политики для всех цепочек. Процедура "Load_Rules" выполняет загрузку прописанных нами правил с указанием различных опций и цепочек фильтрации.

В конце, с помощью конструкции "case $1 in", выполняется анализ и применение переданной скрипту команды (start, stop, restart), запускаются выше указанные процедуры "Flush_Rules" и "Load_Rules в нужном порядке.

Чтобы скрипт можно было запускать на исполнение, его файлу нужно дать соответствующие права:

sudo chmod +x /usr/local/sbin/systemd-iptables.sh

Теперь вы можете вручную запустить, остановить, перезапустить скрипт и оттестировать функционал его правил:

sudo /usr/local/sbin/systemd-iptables.sh start
sudo /usr/local/sbin/systemd-iptables.sh stop
sudo /usr/local/sbin/systemd-iptables.sh restart

Когда скрипт готов, можно приступать к созданию специального юнита для systemd, который будет выполнять автозапуск скрипта при старте ОС.

sudo nano /etc/systemd/system/iptables.service

Содержимое файла будет таким:

[Unit]
Description=IPTables rules
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/systemd-iptables.sh start
ExecStop=/usr/local/sbin/systemd-iptables.sh stop
ExecReload=/usr/local/sbin/systemd-iptables.sh restart
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Разрешим использование новосозданного юнита демоном systemd:

sudo systemctl enable iptables.service

Дадим юниту команду на старт, проверим состояние таблиц IPTables:

sudo systemctl start iptables.service
sudo systemctl status iptables.service
sudo iptables -nvL

Также можно вывести список уже загруженных в IPTables правил в более удобном виде, с нумерацией строк:

sudo iptables -t filter --list --line-numbers
sudo iptables -t nat --list --line-numbers

Беспроводная точка доступа (Access Point) на основе HOSTAPD

Поскольку наш роутер будет предоставлять возможность подключения к нему по Wi-Fi, давайте выполним настройку отвечающей за это службы  hostapd.

Hostapd (Host Access Point Daemon) - это демон, работающий в фоновом режиме и отвечающий за организацию беспроводной сетевой точки доступа стандарта IEEE 802.11 на основе имеющегося Wi-Fi адаптера с поддержкой этого режима. Также это демон берет на себя функции авторизации клиентов и выполняет другую связанную работу.

Чтобы убедиться что сетевой Wi-Fi адаптер малинки поддерживает режим точки доступа (Access Point, AP), выведем еще раз, как в разделе о настройке мощности передатчика, информацию о беспроводных интерфейсах:

iw list

Смотрим секцию "Supported interface modes", в моем случае ее содержимое выглядит вот так:

Supported interface modes:
  * IBSS
  * managed
  * AP
  * P2P-client
  * P2P-GO
  * P2P-device

Как видим, режим "AP" присутствует, значит можно продолжать.

Пакет "hostapd" уже был ранее нами установлен, на этапе установки необходимого программного обеспечения. Приступаем к настройке. Открываем для редактирования конфигурационный файл демона hostapd: 

sudo nano /etc/hostapd/hostapd.conf

Приводим его содержимое к такому виду:

interface=wlan0

driver=nl80211

ssid=JohnX-Pi

# Use the 2.4GHz band
hw_mode=g

channel=6

# Enable 802.11n
ieee80211n=1

wmm_enabled=1

# Enable 40MHz channels with 20ns guard interval
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]

# Accept all MAC addresses
macaddr_acl=0

# Use WPA authentication
auth_algs=1

# Require clients to know the network name
ignore_broadcast_ssid=0

wpa=2

wpa_key_mgmt=WPA-PSK

wpa_passphrase=SUP3R_PASSW00RD*#12

# Use AES, instead of TKIP
rsn_pairwise=CCMP

# 0 - disabled
wps_state=0

Это минимальный набор опций для организации беспроводной точки доступа. Опции которые вам следует изменить на свое усмотрение:

  • "ssid=JohnX-Pi" - здесь указано название будущей точки доступа, вместо "JohnX-Pi" укажите свое название, используйте по возможности символы A-Z0-9 и дефис. В названии допустимо использование всего арсенала символов из кодировки UTF-8 если добавить в конфигурационный файл опцию "utf8_ssid=1", правда отображаться на некоторых устройствах такие имена могут не корректно;
  • "channel=6" - номер канала, на котором будет осуществляться обслуживание беспроводной сети, выберите наименее загруженный в своей местности или здании;
  • "wpa_passphrase=SUP3R_PASSW00RD*#12" - пароль для доступа к беспроводной сети. Установите сложный и надежный пароль, с использованием 10-20 символов, включая буквы, цифры и специальные знаки.

 Укажем путь к используемому конфигурационному файлу для демона hostapd:

sudo nano /etc/default/hostapd

Нужно расскомментировать строчку "DAEMON_CONF=" и указать в ней путь к файлу hostapd.conf:

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Перезапускаем службу hostapd и смотрим ее статус после запуска:

sudo systemctl restart hostapd
sudo systemctl status hostapd

Теперь можно попробовать подключиться к точке доступа, используя ноутбук или смартфон, правда ни одно из устройств не получит сетевых настроек, потому что нужно еще настроить сервер DHCP.

Настройка демона ISC-DHCP-Server

Раньше мы уже выполнили установку пакета "isc-dhcp-server".

ISC DHCP Server (Internet Systems Consortium Dynamic Host Configuration Server) - это программа, работающая в фоновом режиме (служба, демон), которая отвечает за автоматическую выдачу сетевых настроек для разных устройств.

Документация по ISC DHCP Server доступна во встроенной справочной системе GNU/Linux, используем команды "man":

man dhcpd
man dhcpd.conf

Планируя структуру сети в начале статьи мы уже определились с пулами адресов для сетевых интерфейсов, которыми будет орудовать DHCPD:

  • eth0: 192.168.1.10 - 192.168.1.100
  • wlan0: 192.168.2.10 - 192.168.2.100

Открываем для редактирования конфигурационный файл DHCP сервера - dhcpd.conf (не путать с dhcpcd.conf для DHCP клиента):

sudo nano /etc/dhcp/dhcpd.conf

Укажем что этот DHCP-сервер будет официальным в сети, для этого ищем строчку "#authoritative;" и раскомментируем ее, убрав значек решотки:

authoritative;

Добавляем в самый низ файла две секции с описанием параметров выдачи адресов и настроек для подсетей:

subnet 192.168.1.0 netmask 255.255.255.0 {
 range 192.168.1.10 192.168.1.100;
 option broadcast-address 192.168.1.255;
 option routers 192.168.1.1;
 default-lease-time 600;
 max-lease-time 7200;
 option domain-name "local-network";
 option domain-name-servers 8.8.8.8, 8.8.4.4;
}
 
subnet 192.168.2.0 netmask 255.255.255.0 {
 range 192.168.2.10 192.168.2.100;
 option broadcast-address 192.168.2.255;
 option routers 192.168.2.1;
 default-lease-time 600; 
 max-lease-time 7200;
 option domain-name "local-network";
 option domain-name-servers 8.8.8.8, 8.8.4.4;
}

Также, по желанию, можно привязать какой-либо фиксированный IP-адрес к какому-то устройству по его MAC-адресу. Например, сделаем так, чтобы тестовый лептоп с мак-адресом сетевой карты "00:0c:12:b6:f2:c8" всегда получал IP-адрес "192.168.1.55", для этого добавим в конец файла "dhcpd.conf" еще одну секцию:

host TEST-LAPTOP {
  hardware ethernet 00:0c:12:b6:f2:c8;
  fixed-address 192.168.1.55;
}

По завершению редактирования конфигурационного файла DHCPD выполним проверку его синтаксиса:

sudo dhcpd -t

Если нет никаких предупреждений и указаний о наличии ошибок - значит все отлично!

По умолчанию DHCPD будет пробовать работать на всех доступных сетевых интерфейсах - нам это не нужно, поскольку eth1 у нас подключен к интернету и с ним уже работает служба DHCP клиента - dhcpcd.

Поэтому укажем DHCP серверу работать только с интерфейсами eth0 и wlan0:

sudo nano /etc/default/isc-dhcp-server

Прописываем названия интерфейсов для IPv4 через пробел:

INTERFACESv4="eth0 wlan0"
INTERFACESv6=""

Запускаем службу и смотрим ее состояние:

sudo systemctl start isc-dhcp-server
sudo systemctl status isc-dhcp-server

Наблюдать за всеми событиями служб DHCP сервера и клиента можно с помощью следующей команды:

cat /var/log/daemon.log | grep dhcp

DHCP сервер от ISC сохраняет внутреннюю базу данных о выданных когда-либо адресах и параметрах подключаемых устройств, эту информацию удобно использовать как для отладки, так и в других целях. Посмотреть файл базы данных можно командой:

less /var/lib/dhcp/dhcpd.leases

Содержимое и структура этого файла хорошо описаны во встроенной справочной системе:

man dhcpd.leases

Теперь можно попробовать подключить к роутеру другие сетевые устройства и убедиться что они получают корректные сетевые настройки.  Подключенному устройству будут назначены следующие адреса:

  • IP-адрес с подсетью 192.168.1.ххх для проводного подключения и с подсетью 192.168.2.ххх для беспроводного;
  • Шлюз (Gateway) 192.168.1.1 для проводного подключения и 192.168.2.1 для беспроводного;
  • Публичные DNS-сервера от Google (8.8.8.8, 8.8.4.4).

Подключив к USB-разъему малинки USB-Ethernet адаптер, который в свою очередь подключен сетевым кабелем к другому маршрутизатору с DHCP-сервером на борту или же интернет-провайдеру, мы получим работающий интернет как на малинке, так и на подключенных к ней сетевых устройствах.

Маршрутизатор на основе Raspberry Pi должен уже работать.

Решение проблемы старта isc-dhcpd и активации сетевых интерфейсов

После нескольких перезапусков роутера на основе малинки вы можете столкнуться с проблемой, когда подключаемые к нему сетевые устройства не могут получить сетевых настроек (IP, Gateway, DNS) по протоколу DHCP.

Причина этому - запуск демона DHCPD, прежде чем сетевые интерфейсы станут активными и получат указанные нами в настройках DHCPCD статические IP-адреса.

Смотрим логи системы с момента ее запуска:

journalctl -b

Там можно встретить следующие предупреждения для сетевых интерфейсов (пример для eth0):

No subnet declaration for eth0 (no IPv4 addresses).
** Ignoring requests on eth0.  If this is not what
    you want, please write a subnet declaration
    in your dhcpd.conf file for the network segment
    to which interface eth0 is attached. **
 
Not configured to listen on any interfaces!

If you think you have received this message due to a bug rather
than a configuration issue please read the section on submitting
bugs on either our web page at www.isc.org or in the README file
before submitting a bug.  These pages explain the proper
process and the information we find helpful for debugging..

exiting.

Это означает, что в конфигурационном файле "dhcpd.conf" нет описания подходящей зоны для сетевого интерфейса eth0 с IP-адресом и подсетью которые ему назначены на данный момент. Поэтому обслуживание этого интерфейса будет игнорироваться.

По сути, интерфейс eth0 еще не успел получить статический IP-адрес и подсеть, указанный в настройках DHCPCD. Такое же предупреждение появится и для второго интерфейса - wlan0.

Для решения проблемы можно попробовать переназначить приоритеты для запуска служб, то есть запускать DHCPD на более позднем этапе загрузки, после инициализации DHCPCD и сетевой подсистемы в целом.

На форуме raspberrypi.org нашел описание решения подобной проблемы, заключается оно в создании копии юнит-файла "isc-dhcp-server.service" для systemd, с указанием дополнительных опций "Restart=on-failure" и "RestartSec=5", что позволило бы при неудачном старте или сбое (failure) демона "isc-dhcp-server" выполнить его автоматический перезапуск через 5 секунд.

Подобное решение мне показалось интересным, но оно не заработало, и вот почему... Предупреждение в логах системы гласит что в файле "dhcpd.conf" отсутствует описание зоны для закрепленной за интерфейсом подсети. Интерфейс еще не успел получить настройки от DHCPCD, поэтому он просто игнорируется службой DHCPD.

Сама же служба DHCPD при этом не "падает" (failure) и продолжает работать, выводя в системный лог предупреждение (warning). Таким образом, опция "Restart=on-failure" в юнит-файле проблему не решит.

К тому же, подобное копирование и изменение системного юнит-файла "isc-dhcp-server.service" может привести в будущем к проблемам при получении обновлений для пакета isc-dhcp-server.

Решил разобраться с этой проблемой по своему - создать сторожевого песика (Watchdog), являющего из себя скрипт, который будет запущен при старте системы и проследит за получением сетевых адресов на указанных интерфейсах, после этого выполнит перезапуск службы "isc-dhcp-server".

Открываем для редактирования новый файл:

sudo nano /usr/local/sbin/systemd-isc-watchdog.sh

Вставляем в него следующий код:

#!/bin/bash
# Waiting for interfaces assigning IP, than restarting isc-dhcp-server.
# https://ph0en1x.net

declare -A INTERFACES
INTERFACES=(
  [eth0]="192.168.1.1"
  [wlan0]="192.168.2.1"
)

for i in "${!INTERFACES[@]}"
do
  # wait until interface accepts IP
  for ((n=0; n < 60; n++))
  do
    has_ip=`ip a show "$i" | grep "inet ${INTERFACES[$i]}"`
    if [ ! -z "$has_ip" ]; then
      echo "ISC_Watchdog: interface $i ready."
      break
    fi
    sleep 1
  done
done
sleep 15
echo "ISC_Watchdog: restarting isc-dhcp-server..."
systemctl restart isc-dhcp-server
exit 0

Скрипт работает следующим образом:

  • запускается при старте ОС отдельно созданным для systemd юнит-файлом;
  • проходит в цикле через каждую пару [название_интерфейса]=IP из массива INTERFACES;
  • для каждого интерфейса делается 60 проверок наличия нужного IP-адреса с таймаутом 1 секунда;
  • после завершения проверок ждет 15 секунд и перезапускает isc-dhcp-server;

Таким образом, проверка с ожиданием может длиться максимум 60+60 секунд, после этого в любом случае через 15 секунд DHCPD будет перезапущен.

Здесь важно указать верные IP-адреса для сетевых интерфейсов eth0 и wlan0. Если планируется использовать еще какой-то сетевой интерфейс для внутренней сети (например eth2), обслуживаемый DHCPD и получивший IP-адрес (например 192.168.10.1) через DHCPCD, то его также можно добавить в массив строчкой "[eth2]="192.168.10.1".

Дадим файлу скрипта право на запуск и откроем для редактирования новый файл с юнитом для systemd:

sudo chmod +x /usr/local/sbin/systemd-isc-watchdog.sh
sudo nano /etc/systemd/system/isc-watchdog.service

Поместим в него следующее содержимое:

[Unit]
Description=Watchdog for isc-dhcp-server.
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/systemd-isc-watchdog.sh
RemainAfterExit=no

[Install]
WantedBy=multi-user.target

Разрешим обработку юнита при старте ОС:

sudo systemctl enable isc-watchdog.service

На всякий случай, можно еще добавить периодический перезапуск демона через crontab, откроем файл системного планировщика заданий для редактирования:

sudo nano /etc/crontab

Добавим строчку с новым заданием:

1  *    * * *   root    /bin/systemctl restart isc-dhcp-server

Таким образом мы настроили перезапуск демона isc-dhcp-server в начале каждого часа (период 60 минут).

Настройка статического списка DNS-серверов

Список DNS-серверов, используемых системой, как правило содержится в файле "/etc/resolv.conf". По умолчанию, содержимое этого файла в Raspbian автоматически генерируется при запуске системы и может быть изменено различными службами (например DHCPCD, PPP и другими).

При подключении сетевого кабеля от провайдера интернета к USB-Ethernet адаптеру с интерфейсом eth1, этому интерфейсу будет присвоен IP-адрес от провайдера, в системе будет установлен маршрут по умолчанию (Default Route) с указанием шлюза провайдера, а также в файл "/etc/resolv.conf" будет помещен список DNS-серверов. Все эти действия выполняет сетевой демон DHCPCD (DHCP-клиент).

Мы можем сами указать список предпочитаемых DNS-серверов, поместив их в файл "/etc/resolv.conf", но после презагрузки системы или же после переподключения USB-Ethernet адаптера, все внесенные в файл изменения будут перезаписаны демоном DHCPCD.

Если вы действительно хотите использовать свой список DNS-серверов (например от Гугла), то нужно указать службе DHCPCD не выполнять "хук" (не "подцеплять") список NS-серверов, полученный от другого маршрутизатора по DHCP.

Добавим IP-адреса публичных серверов от Google:

sudo nano /etc/resolv.conf

Заменим содержимое файла строчками:

nameserver 8.8.8.8
nameserver 8.8.4.4

Теперь нужно отредактировать файл "/etc/dhcpcd.conf":

sudo nano /etc/dhcpcd.conf

Добавляем в нем строчку "nohook resolv.conf", вот пример из текущей конфигурации:

nohook wpa_supplicant
nohook resolv.conf

interface wlan0
static ip_address=192.168.2.1/24

Данное ограничение на действия с файлом "/etc/resolv.conf" будет справедливо только для службы DHCPCD, другие программы и далее смогут вносить изменения в этот файл.

Чтобы полностью запретить изменение прописанных вручную DNS-серверов в файле "/etc/resolv.conf", его нужно защитить от перезаписи, важно заметить что манипуляции с командой "chmod -w" здесь не помогут. Для этой цели воспользуемся командой "chattr", которая служит для изменения атрибутов файлов.

Установим файлу "/etc/resolv.conf" атрибут "immutable" (не модифицируемый), который запретит переименование файла, создание символьных ссылок для него, не позволит записывать в него данные и запускать. Снять этот атрибут из файла может только суперпользователь - root.

sudo chattr +i /etc/resolv.conf

Если нужно будет отредактировать файл, то с помощью следующей команды можно снять атрибут "immutable":

sudo chattr -i /etc/resolv.conf

Важно понимать, что получаемый от интернет-провайдера список DNS-серверов может использоваться для сопоставления доменных имен и IP-адресов ресурсов, которые работают внутри сети провайдера (не в интернете).

В случае замены DNS-серверов полученных от провайдера по DHCP на любые другие, внутренние сайты и ресурсы у провайдера могут оказаться недоступными.

Таблица с публичными DNS-серверами от различных компаний по всему миру:

Компания IPv4 nameservers IPv6 nameservers Примечание
Google INC 8.8.8.8
8.8.4.4
2001:4860:4860::8888
2001:4860:4860::8844
 
OpenNIC 185.121.177.177
185.121.177.53
2a05:dfc7:5::53
2a05:dfc7:5::5353
 
UncensoredDNS 91.239.100.100
89.233.43.71
2001:67c:28a4::
2a01:3a0:53:53::
anycast
unicast
Comodo 8.26.56.26
8.20.247.20
   
DNS.WATCH 84.200.69.80
84.200.70.40
2001:1608:10:25::1c04:b12f
2001:1608:10:25::9249:d69b
 
OpenDNS 208.67.222.222
208.67.220.220
2620:0:ccc::2
2620:0:ccd::2
 
Quad9 9.9.9.9
9.9.9.10
2620:fe::fe
2620:fe::10
С blocklist и DNSSEC
Без blocklist и DNSSEC

Подготовка 3G-модема, узнаем его состояние используя minicom

Многие 3G-модемы являются составными устройствами, которые могут эмулировать несколько различных устройств:

  • виртуальный накопитель CD-ROM (как правило на нем содержатся драйвера и программы);
  • картридер для Flash-карты (если в устройстве есть разьем под карточку);
  • модем.

В начале статьи нами был установлен пакет "usb-modeswitch", который представляет собой набор udev-правил (скриптов), позволяющих в автоматическом режиме переключить беспроводный 3G-адаптер из режима накопителя (как правило виртуальный CD-привод) в режим модема.

Подключаем 3G-модем к свободному USB-разъему малинки и смотрим какие устройства в /dev нам доступны для использования:

ls /dev | grep ttyUSB

Получим примерно следующий список файлов-устройств (последовательных портов):

ttyUSB0
ttyUSB1
ttyUSB2
ttyUSB3

Теперь не плохо бы узнать код производителя (Vendor ID, vid) и код устройства (Product ID, pid) для используемого модема, просмотрим список подключенных по USB к малинке устройств:

lsusb

Примерный вывод:

...
Bus 001 Device 008: ID 05c6:6000 Qualcomm, Inc. Siemens SG75
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

В данном случае модем определился как 'Siemens SG75' со следующими идентификаторами:

  • Vendor ID = 05c6 (Qualcomm, Inc.);
  • Product ID = 6000 (Siemens SG75).

Идентификаторы USB-устройств и их названия можно узнать на сайте проекта 'Linux USB Project', вот свежий список в формате TXT: http://www.linux-usb.org/usb.ids

Идентификаторы 'Vendor ID' и 'Product ID' зависят от типа используемого вами 3G-модема и будут отличаться от приведенного выше примера.

Теперь мы можем подключиться к любому из ttyUSB* используя эмулятор последовательного терминала 'minicom'. О параметрах запуска и работе с программным эмулятором последовательного терминала 'minicom' можно узнать из его man-странички:

man minicom

В моем случае на прием команд согласились только два из портов: 'ttyUSB0' и 'ttyUSB1'. Первый порт используется для управления модемом, а второй - для приема и передачи потока данных.

Подключимся к 'ttyUSB0':

minicom --device=/dev/ttyUSB0

При успешном подключении к порту увидим приветствие и информацию по вызову справки:

Welcome to minicom 2.7

OPTIONS: I18n
Compiled on Apr 22 2017, 09:14:19.
Port /dev/ttyUSB0, 11:47:54

Press CTRL-A Z for help on special keys

Для отображения списка команд (справки) нужно нажать комбинацию клавиш CTRL+A и отпустив их потом нажать Z, для выхода из справки нажимаем ENTER.

Теперь для тестирования и управления модема можно использовать AT-команды. Проверим отвечает ли нам модем - наберем команду "AT" и нажмем ENTER:

Press CTRL-A Z for help on special keys

AT
OK

Если все работает то получим ответ 'OK'.

Используя AT-команды можно узнать разную полезную информацию о модеме и его состоянии, установить режим его работы, и даже отправить SMS (если поддерживается).

Список некоторых информационных AT-команд:

  • ATI  - вывести информацию о модеме;
  • AT+CGMI  - отобразить только производителя модема;
  • AT+CGMR  - вывести версию программного обеспечения;
  • AT^HWVER  - вывести версию аппаратного обеспечения;
  • AT+CGSN  - вывести IMEI;
  • AT+CIMI  - вывести IMSI;
  • AT^PREFMODE=? - вывести поддерживаемые режимы передачи данных;
  • AT+CSQ  - вывести уровень сигнала 3G;
  • AT+CBC  - уровень заряда батареи (если используется автономный модем или телефон);
  • AT^CVOICE=?  - поддерживает ли модем голосовые вызовы;
  • AT^SYSINFO  - вывести системную информацию (состояние, роуминг, режим).

Если какая-то из команд вывела ошибку и терминал отказывается отвечать - выполним выход из программы со сбросом состояния модема: нажимаем CTRL+A, Z и потом X. Теперь можно снова подключиться к порту модема используя minicom.

Запрос 'AT^SYSINFO' выведет информацию одной закодированной строчкой:

AT^SYSINFO
^SYSINFO:2,255,0,8,240

Формат выведенной информации: [status], [domain], [roaming status], [mode], [SIM state]. Сегменты разделены запятыми и имеют соответствующие текущим параметрам цифровые значения.

[status]:

  • 0 - No service (нет сигнала);
  • 1 - Restricted service (ограниченный доступ);
  • 2 - Valid service (сигнал ок);
  • 3 - Restricted regional service (ограниченный региональный доступ);
  • 4 - Power-saving and deep sleep state (спящий режим).

[domain]:

  • 0 - No service;
  • 1 - Only CS service;
  • 2 - Only PS service;
  • 3 - PS+CS service;
  • 4 - CS and PS not registered, searching.

[roaming status]:

  • 0 - Non roaming (роуминг не активен);
  • 1 - Roaming (в роуминге).

[mode]:

  • 0 - No service;
  • 1 - AMPS mode;
  • 2 - CDMA mode;
  • 3 - GSM/GPRS mode;
  • 4 - HDR mode;
  • 5 - WCDMA mode;
  • 6 - GPS mode;
  • 7 GSM/WCDMA;
  • 8 CDMA/HDR HYBRID;
  • 15 TD-SCDMA mode.

[SIM state]:

  • 0 - Invalid USIM card state or pin code locked;
  • 1 - Valid USIM card state;
  • 2 - USIM is invalid in case of CS;
  • 3 - USIM is invalid in case of PS;
  • 4 - USIM is invalid in case of either CS or PS;
  • 255 - USIM card is not existent.

Запрос 'AT+CSQ' выведет уровень сигнала:

AT+CSQ
+CSQ: 26, 99

В данном случае получено значение в формате '26, 99', где:

  • 26 - Received signal strength indicator (уровень сигнала в CSQ)
  • 99 - Bit Error Rate (счетчик ошибок)

Для перевода значения из CSQ в dBm можно использовать формулу:

dBm = -113 + N * 2

где N - это полученное после AT-команды значение CSQ.

dBm = -113 + 26 * 3 = -61 (отличное качество сигнала).

Чтобы вам было легче сориентироваться в значениях, приведу небольшую табличку:

Значение CSQ RSSI, dBm Описание
2 ... 9 -109 ... -95 Плохой сигнал
10 ... 14 -93 ... -85 Так себе, ОК
15 ... 19 -83 ... -75 Хороший сигнал
20 ... 30 -73 ... -53 Отличный сигнал

Запрос 'AT^PREFMODE=?' выведет список поддерживаемых режимов передачи данных для 3G-модема:

AT^PREFMODE=?
^PREFMODE:(2,4,8)

Возможные режимы работы модема:

  • 2 - CDMA2000 (1x), скорость обмена данными до 153 КБит/сек;
  • 4 - EVDO (Evolution Data Only), высокая скорость обмена данными;
  • 8 - гибридный, с автоматическим выбором типа подключения по состоянию сигнала.

Скорость передачи данных в разных ревизиях EVDO:

  • rev.0 - 2,4 Mbit/s на прием 0,153 Mbit/s на передачу;
  • rev.A - 3,1 Mbit/s на прием 1,8 Mbit/s на передачу;
  • rev.B - 73,5 Mbit/s на прием 27 Mbit/s на передачу.

Как видите, с помощью AT-команд можно узнать очень много полезной информации о модеме, она вам может пригодиться для отладки, мониторинга и сбора информации о модеме.

3G-модем и консольная звонилка WVDIAL

Для работы с 3G-USB модемом нам понадобится программа "wvdial", которая умеет выполнять дозвон к провайдеру с установленными параметрами, а также следить за состоянием сетевого подключения.

WVDial (WeaVe Dial) - это умная программа для организации подключений с использованием модемов через протокол PPP (Point-to-Point Protocol). Мы уже установили ее на этапе установки программ.

Документация по wvdial и параметрам его конфигурационного файла:

man wvdial
man wvdial.conf

Для обнаружения модема и создания базового файла с настройками, желательно запустить программу-конфигуратор:

sudo wvdialconf

Программа выполнит определение и тест модема, на основе полученных данных сгенерирует базовый конфигурационный файл:

Editing `/etc/wvdial.conf'.

Scanning your serial ports for a modem.

ttyUSB0<*1>: ATQ0 V1 E1 -- OK
ttyUSB0<*1>: ATQ0 V1 E1 Z -- OK
ttyUSB0<*1>: ATQ0 V1 E1 S0=0 -- OK
ttyUSB0<*1>: ATQ0 V1 E1 S0=0 &C1 -- OK
ttyUSB0<*1>: ATQ0 V1 E1 S0=0 &C1 &D2 -- OK
ttyUSB0<*1>: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0 -- OK
ttyUSB0<*1>: Modem Identifier: ATI -- Manufacturer: +GMI: Qualcomm
ttyUSB0<*1>: Speed 9600: AT -- OK
ttyUSB0<*1>: Max speed is 9600; that should be safe.
ttyUSB0<*1>: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0 -- OK
...
Found a modem on /dev/ttyUSB0.
Modem configuration written to /etc/wvdial.conf.
ttyUSB0<Info>: Speed 9600; init "ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0"
ttyUSB1<Info>: Speed 9600; init "ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0"

Теперь файл "/etc/wvdial.conf" должен быть уже создан, в нем прописаны настройки и путь к файлу последовательного порта (/dev/ttyUSB0), через который будет работать модем. Откроем "wvdial.conf" для редактирования:

sudo nano /etc/wvdial.conf

Примерно так выглядит мой уже измененный конфигурационный файл:

[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CSQ
Init4 = AT^PREFMODE=8
Modem Type = Analog Modem
Phone = #777
ISDN = 0
Username = USER
Password = PASSWORD
New PPPD = yes
Modem = /dev/ttyUSB0
Baud = 9600

В параметрах Init1-init4 содержатся наборы AT-команд для управления модемом, здесь я вручную добавил строку "Init4 = AT^PREFMODE=8", которая принудительно пытается переключить модем в гибридный режим работы EVDO+CDMA2000 (8).

Если у вас в местности слабый и не стабильный сигнал, то возможно что стоит переключить модем на использование именно гибридного режима (8).

Строчка 'Init3 = AT+CSQ' заставляет модем вывести текущий уровень принимаемого сигнала, об этом я рассказывал в предыдущем разделе.

Следующие параметры в конфигурационном файле отвечают за дозвон и авторизацию, установите их в соответствии с инструкциями от своего провайдера:

  • Phone = #777 - номер телефона для дозвона;
  • Username = USER - имя пользователя;
  • Password = PASSWORD - пароль.

В случае если в файле "/etc/resolv.conf" прописаны статичные DNS-сервера целесообразно отключить получение их списка от провайдера 3G-интернета. Для этого в файл /etc/wvdial.conf нужно добавить следующую строчку:

Auto DNS = Off

Также в данном случае нужно открыть для редактирования файл "/etc/ppp/peers/wvdial":

sudo nano /etc/ppp/peers/wvdial

Комментируем (ставим спереди значек решотки) в нем строчку:

#usepeerdns

Теперь мы можем запустить дозвон до провайдера и получить интернет подключение с помощью wvdial. Если у вас к малинке уже подключен интернет через внешний USB Ethernet адаптер, то интерфейс этого адаптера нужно предварительно деактивировать:

sudo ip link set dev eth1 down

Для запуска дозвона используем следующую команду:

sudo wvdial

Начнется процедура выполнения AT-команд и получения параметров соединения, IP-адресов.

--> WvDial: Internet dialer version 1.61
--> Initializing modem.
--> Sending: ATZ
ATZ
OK
--> Sending: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
...
--> PPP negotiation detected.
--> Starting pppd at Mon Jun 25 15:05:21 2018
--> Pid of pppd: 2967
--> Using interface ppp0
--> local  IP address 10.10.10.82
--> remote IP address 10.10.11.3
--> primary   DNS address 192.168.10.121
--> secondary DNS address 192.168.10.122

На малинке должен появиться интернет через 3G-соединение. Будет создан и активирован интерфейс ppp0, это можно проверить выполнив команду 'ip a':

$ ip a
...
5: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 3
    link/ppp 
    inet 10.10.10.122 peer 10.1.1.3/32 scope global ppp0
       valid_lft forever preferred_lft forever

Проверяем пингом соединение с каким-то внешним сайтом:

ping reddit.com

Результат:

PING reddit.com (151.101.65.140) 56(84) bytes of data.
64 bytes from 151.101.65.140 (151.101.65.140): icmp_seq=1 ttl=57 time=131 ms
64 bytes from 151.101.65.140 (151.101.65.140): icmp_seq=2 ttl=57 time=123 ms
64 bytes from 151.101.65.140 (151.101.65.140): icmp_seq=3 ttl=57 time=120 ms
^C
--- reddit.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 120.250/125.185/131.506/4.698 ms

Интернет есть, все работает!

Прервать соединение через wvdial можно в окне терминала, где была запущена команда на старт, достаточно нажать комбинацию клавиш 'CTRL+C'. Также можно принудительно завершить все процессы под именем wvdial следующей командой:

sudo killall wvdial

После деактивации 3G-подключения можем вернуть обратно интернет подключение через USB Ethernet адаптер (интерфейс eth1), активируем проводной интерфейс:

sudo ip link set dev eth1 up

Программу wvdial очень удобно запускать в мультиплексоре терминалов - TMUX (Terminal MUltipleXor). Это позволит выполнять программу в фоновом режиме и при необходимости наблюдать за состоянием соединения и процессом дозвона wvdial. Для этого запустим сначала сам TMUX:

tmux

В открывшемся терминале запускаем 'wvdial':

sudo wvdial

Теперь программа дозвона выполняется в программном терминале TMUX, чтобы отключиться от него и перейти в основной терминал достаточно нажать комбинацию клавиш 'CTRL+b', а потом отпустив их 'd'. Чтобы обратно подключиться к терминалу TMUX с запущенным и работающем в нем wvdial достаточно выполнить команду:

tmux attach

TMUX - очень мощная программа, которая позволяет разделить экран (сессию) на несколько подтерминалов, запускать и управлять множеством сессий и содержит много других полезных и удобных возможностей.

Больше информации о этой программе можно узнать из ее man-страници:

man tmux

Режимы управления частотой CPU в Raspberry Pi и его температура

Ядро Linux управляет частотой микропроцессора (CPU) в одном из установленных режимов:

  • ondemand - по требованию, частота каждого ядра CPU возрастает при увеличении нагрузки;
  • performance - частота ядер CPU постоянно имеет максимальное значение;
  • powersave - энергосберегающий режим.

Узнать текущий режим управления частотой первого ядра CPU Raspberry Pi (отсчет начинается с 0) можно командой:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Узнаем режимы для каждого из ядер:

for i in /sys/devices/system/cpu/*/cpufreq/scaling_governor; do cat $i; done

Примерный вывод для 4х-ядерного микропроцессора малинки:

ondemand
ondemand
ondemand
ondemand

По умолчанию в малинке используется 'ondemand'.

Текущий режим всех ядер CPU можно попробовать изменить например на 'performance' (максимальная частота), для этого нужно выполнить команду:

sudo sh -c 'for i in /sys/devices/system/cpu/*/cpufreq/scaling_governor; do echo performance > $i; done'

Таким же способом можно перевести все ядра в режим энергосбережения (минимальная частота):

sudo sh -c 'for i in /sys/devices/system/cpu/*/cpufreq/scaling_governor; do echo powersave > $i; done'

Cписок доступных рабочих частот всех ядер микропроцессора можно узнать командой:

for i in /sys/devices/system/cpu/*/cpufreq/scaling_available_frequencies; do cat $i; done

В моем случае доступны только по две частоты для каждого ядра:

600000 1200000

Минимальную и минимальную частоты первого ядра можно узнать следующими двумя командами:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq

Частоты ядер микропроцессора в Raspberry Pi 3 Model B:

  • 600МГц - минимальная (постоянно включена в режиме powersave);
  • 1200МГц - максимальная (постоянно включена в режиме performance).

Узнаем текущие частоты всех ядер микропроцессора:

for i in /sys/devices/system/cpu/*/cpufreq/scaling_cur_freq; do cat $i; done

Вывод:

600000
600000
600000
600000

Я бы не рекомендовал изменять scaling_governor из значения по умолчанию 'ondemand' на 'powersave' или 'performance' если малинка будет работать в режиме роутера, режим 'ondemand' - оптимальный в большинстве случаев применения малинки.

Если все же требуется перманентно перевести микропроцессор малинки например в энергосберегающий режим, то это можно сделать добавив соответствующую конструкцию из команд в файл 'rc.local':

sudo nano /etc/rc.local

Добавляем в самый низ строку с командами:

/bin/sh -c 'for i in /sys/devices/system/cpu/*/cpufreq/scaling_governor; do echo powersave > $i; done'

или так (для 4х ядер CPU):

/bin/echo powersave > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
/bin/echo powersave > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
/bin/echo powersave > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
/bin/echo powersave > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor

Теперь после перезагрузки Raspbian микропроцессор будет находиться в режиме энергосбережения.

В зависимости от нагрузки на CPU его температура будет возрастать. Узнать температуру микропроцессора Raspberry Pi можно следующей командой:

cat /sys/class/thermal/thermal_zone0/temp

Результатом будет число (пример):

45622

Делим его на 1000 и получим: 45,622 градусов по Цельсию.

Также температуру чипа можно получить используя одну из утилит для работы с графическим процессором (GPU):

/opt/vc/bin/vcgencmd measure_temp

Примерный вывод:

temp=45.6'C

Настройка часов реального времени (RTC)

В прошлой статье я описывал как исправить, подключить и установить в корпус модуль часов реального времени DS1307. Данный модуль работает используя шину данных I2C.

В одной из прошлых статей я описывал как работать с шиной I2C. На этапе настройки малинки мы уже включили эту шину, теперь можно просканировать ее на предмет подключенных к ней устройств:

sudo i2cdetect -y 1

Пример результата выполнения команды:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Видим что обнаружены три устройства:

  • 0x3c - OLED-дисплей SSD1306;
  • 0x68 - модуль RTC DS1307;
  • 0x50 - I2C EEPROM 24C32, установленная на плате с DS1307.

Модуль часов определен и готов к использованию. Зарегистрируем модуль часов реального времени в операционной системе:

sudo sh -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device'

Теперь, если снова вывести список адресов I2C-устройств в консоль, то вместо адреса модуля "68" появятся "UU":

Смена вывода адреса DS1307 после активации

Рис. 2. Смена вывода адреса DS1307 после активации.

Считаем текущее значение времени, установленное в RTC:

sudo hwclock -r

При первом подключении и использовании модуля получим дату 2000-01-01:

2000-01-01 02:00:03.093197+0200

Проверяем текущую дату и время в Raspbian, выполним любую из команд:

date
timedatectl

Если дата или время в системе отличается от реальных значений - исправляем их, сделать это можно следующей командой:

sudo timedatectl set-time '2050-11-23 08:10:40'

где:

  • 2050-11-23 - год в формате: год-мес-день;
  • 08:10:40 - время в формате: час:мин:сек.

По умолчанию в Raspbian включена служба NTP (Network Time Protocol), которая служит для синхронизации времени через интернет, поэтому делать правку даты или времени скорее всего не понадобится.

Теперь можем выполнить запись текущих значений даты и времени в модуль RTC:

sudo hwclock -w

Считываем значения из модуля RTC, убедимся что значения записались:

sudo hwclock -r

После выполнения команды должны увидеть текущие дату и время.

Теперь мы можем выполнять синхронизацию системного времени ОС Raspbian с временем в RTC используя следующую команду:

hwclock -s

При каждой загрузке малинки нужно выполнять синхронизацию времени ОС с данными даты и времени из RTC, поэтому мы автоматизируем этот процесс.

Отредактируем файл '/etc/rc.local', в котором можно добавить вызовы своих команды для запуска при старте системы:

sudo nano /etc/rc.local

В конце файла, перед строчкой 'exit 0' добавляем следующие команды:

# date+time from RTC DS1307 -> System
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
hwclock -s

Также, в данном случае, желательно отключить службу синхронизации времени через интернет. Узнаем установлена ли служба NTP:

sudo systemctl status ntp

Если же демон NTP установлен и запущен - остановим его и отключим:

sudo systemctl stop ntp
sudo systemctl disable ntp

Теперь можно перезагрузить малинку и проверить системное время - все должно быть в порядке!

Считываем показания термодатчика DS18B20

Датчик температуры DS18B20 установлен на плате модуля часов реального времени DS1307, его вывод данных подключен к пину интерфейса 1-Wire в Raspberry Pi, который соответствует IO4 (7-й вывод гребенки).

Интерфейс передачи данных 1-Wire (через один проводник) мы уже активировали на этапе базовой настройки операционной системы Raspbian.

Каждый датчик температуры DS18B20, подключаемый к малинке, получает свой уникальный идентификатор. В дереве устройств автоматически создается файловая структура, взаимодействуя с которой можно очень просто считать текущие данные из нужного нам датчика.

Выведем список директорий в дереве устройств, что имеют отношение к интерфейсу 1-Wire:

ls /sys/bus/w1/devices/

Примерный результат вывода:

28-021501b2baсf  w1_bus_master1

Для датчиков температуры DS18B20 создаются директории вида "28-XXXXXXXXXXXX", таким образом можно идентифицировать каждый из подключенных датчиков. В нашем случае, подключен всего один датчик температуры, он получил идентификатор "28-021501b2baсf".

В директории этого устройства содержатся некая структура файлов и директорий, смотрим их список:

ls /sys/bus/w1/devices/28-021501b2baсf

Вывод команды:

driver  hwmon  id  name  power  subsystem  uevent  w1_slave

В данном случае нас интересует файл под названием "w1_slave", выведем его содержимое в консоль:

cat /sys/bus/w1/devices/28-021501b2baсf/w1_slave

Примерный результат:

0e 02 4b 46 7f ff 0c 10 0b : crc=0b YES
0e 02 4b 46 7f ff 0c 10 0b t=32875

Здесь:

  • crc=0b YES  - говорит о том что контрольная сумма результата в порядке;
  • t=32875  - число, поделив которое на 1000 получим текущее значение температуры, в данном примере это 32,875 градуса по Цельсию.

Для получения только числового значения температуры можно воспользоваться чтением данных из другого файла:

cat /sys/bus/w1/devices/28-021501b2baсf/hwmon/hwmon0/temp1_input

Результат:

32875

Минус последнего метода в том, что здесь не указано верна ли контрольная сумма операции и можно ли доверять этому значению.

Полученные с помощью этих команд данные можно использовать в программах написанных на Bash, Python и других языках программирования.

Генерация звуковых сигналов через пьезо-зуммер

Пьезо-зуммер ("пищалка") подключен к каналу IO18 (вивод 12 на гребенке малинки). Генерация звуковых сигналов осуществляется подачей импульсов разной частоты и длины на канал IO18.

В данном случае можно написать программу с несколькими вложенными циклами, которая будет генерировать очереди импульсов, а можно использовать функцию PWM (широтно-импульсная модуляция) в модуле Rpi.GPIO.

Подавая на пин 12 сигналы с определенными частотами и длительностью можно генерировать различные звуковые оповещения и мелодии.

В качестве примера приведу очень простую программу, которая генерирует "сигналы от инопланетян" Alien, звучит достаточно забавно.

nano ~/speaker-alien-signal-test.py

Скопируйте в открывшийся редактор следующий код:

#!/usr/bin/env python3     
# -*- coding: utf-8 -*-
# 
# Raspberry Pi Router speaker test.
# https://ph0en1x.net

import RPi.GPIO as GPIO
from random import randrange
from time import sleep

GPIO.setmode(GPIO.BCM)
# Speaker connected to IO18 (pin N12).
GPIO.setup(18, GPIO.OUT) 
# Start frequency=1Hz.
pwm = GPIO.PWM(18, 1) 
# Generate meandr signal (duty_cycle=50%) |_|^|_|^|... 
pwm.start(50)

try:
    while True:
        # Change frequency in random range 20Hz-10kHz.
        pwm.ChangeFrequency(randrange(20,10001))
        # Change timeout in random range 0.01-0.04 sec.
        sleep(randrange(1,5)/100)

except KeyboardInterrupt:
    pass

# Stop PWM, clean GPIO PIN state.
pwm.stop()
GPIO.cleanup()

Запускаем...

python3 ~/speaker-alien-signal-test.py

Прервать выполнение программы можно нажав комбинацию клавиш "CTRL+C" (break).

Чередуя комбинации "частота+длительность" сигнала можно создать свою звуковую мелодию. Согласитесь, что составлять такую мелодию из значений частот и временных задержек не очень удобно - потребуется не мало времени и без хорошего служа тут не обойтись.

Компания Nokia в свое время создала специальный формат для описания, передачи и хранения мелодий в своих мобильных телефонах - RTTTL (Ring Tone Text Transfer Language).

Пример мелодии 'Aqua - Barbie girl' в формате RTTTL:

Barbie girl:d=4,o=5,b=125:8g#,8e,8g#,8c#6,a,p,8f#,8d#,8f#,8b,g#,8f#,8e,p,8e,8c#,f#,c#,p,8f#,8e,g#,f#

Ниже я покажу как можно проигрывать мелодии в формате RTTTL используя платформу Raspberry Pi и подключенный к ней динамик.

Прежде чем перейдем к программе нам понадобится установить модуль 'rtttl' для языка Python, который позволит перевести строчку мелодии формата RTTTL в массив с частотами и интервалами. Исходный код модуля и примеры по его использованию приведены на GITHUB'е разработчика.

Установим модуль для Python3 следующей командой:

sudo pip3 install rtttl

Создадим новый скрипт:

nano ~/speaker-rttl-test.py

Исходный код программы:

#!/usr/bin/env python3     
# -*- coding: utf-8 -*-
# 
# Raspberry Pi Router speaker RTTTL melody test.
# https://ph0en1x.net

import RPi.GPIO as GPIO
from rtttl import parse_rtttl
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT) 
pwm = GPIO.PWM(18, 1) 
pwm.start(50)

song = ("Barbie girl:d=4,o=5,b=125:8g#,8e,8g#,8c#6,a,p,8f#," 
        "8d#,8f#,8b,g#,8f#,8e,p,8e,8c#,f#,c#,p,8f#,8e,g#,f#")
notes = parse_rtttl(song)

try:
    print("Playing: {} ...".format(notes['title']))
    for note in notes['notes']:
        if note['frequency'] == 0:
            note['frequency'] = 1
        pwm.ChangeFrequency(note['frequency'])
        sleep(note['duration']/1000)

except KeyboardInterrupt:
    pass

pwm.stop()
GPIO.cleanup()

Запуск:

python3 ~/speaker-rttl-test.py

Данная программа является немного измененным и дополненным вариантом предыдущего примера. Здесь добавлен парсинг кода песни в формате RTTTL и проигрывание полученных нот в цикле по-порядку.

Добавил еще небольшую поправку: если частота в списке нот равна нулю (для реализации паузы), то проигрываем сигнал с частотой 1Гц. Метод 'pwm.ChangeFrequency' в качестве аргумента не принимает значения равного 0 (будет выведена ошибка). К тому же в этом решении есть еще один плюс: если пауза длинная, то мы будем слышать как бы звук фоновых ударных с частотой 1Гц.

Для поиска текстов мелодий в формате RTTTL можно воспользоваться поисковыми системами, используйте следующую конструкцию поискового запроса: "RTTTL + имя_песни". Также есть сайты, которые содержат целые базы рингтонов, например - www.cellringtones.com.

Вот архив с кодами 10 000+ мелодий - 10000_melodies_rttl.7z (513КБ).

У большинства мелодий в приведенном архиве есть названия песен и исполнителей, присутствуют разные варианты одних и тех же песен, некоторые мелодии могут не работать или работать не корректно, в общем нужно тестировать.

Таким образом, вы можете создать программу для проигрывания нужной мелодии и использовать ее вызов в различных скриптах на Bash или Python, озвучивая различные события.

Управление RGB-светодиодом и реагирование на нажатия кнопок

О том как работать с кнопками и светодиодами, подключенными к GPIO Raspberry Pi, я уже описывал в прошлых статьях:

Здесь приведу небольшой пример: будем в случайном порядке включать и выключать три цвета подключенного RGB-светодиода, при нажатии на одну из кнопок - перебор цветов остановится на текущем, при нажатии на другую кнопку - продолжится.

Если посмотреть на принципиальную схему, то светодиод и две из кнопок у нас подключены к следующим каналам GPIO:

  • LED Red - IO23 (вывод 16);
  • LED Green - IO24 (вывод 18);
  • LED Blue - IO25 (вывод 22);
  • Switch 1 - IO20 (вывод 38);
  • Switch 2 - IO21 (вывод 40).

Создадим новый файл скрипта:

nano ~/leds-switches-test.py

Код программы:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 
# Raspberry Pi Router LEDs+SWITCHes test.
# https://ph0en1x.net

import RPi.GPIO as GPIO

from random import choice, randrange
from time import sleep

GPIO.cleanup()
GPIO.setmode(GPIO.BCM)

# Prepare LEDs pins for OUTPUT.
leds_io = [23, 24, 25]
for led_io in leds_io:
    GPIO.setup(led_io, GPIO.OUT)

# Prepare SWITCHes pins for INPUT
switch_on = 20
switch_off = 21
GPIO.setup(switch_on, GPIO.IN)
GPIO.setup(switch_off, GPIO.IN)

change_color_on = True

def callback_start(channel):
    """ Start color changing. """
    global change_color_on
    change_color_on = True
    print('START')

def callback_stop(channel):
   """ Stop color changing. """
    global change_color_on
    change_color_on = False
    print('STOP')

GPIO.add_event_detect(
    switch_on, 
    GPIO.FALLING, 
    callback=callback_start, 
    bouncetime=300)
GPIO.add_event_detect(
    switch_off, 
    GPIO.FALLING, 
    callback=callback_stop, 
    bouncetime=300)

print("Press CTRL+C to exit...")
try:
    while True:
        io_num = choice(leds_io)
        io_level = GPIO.HIGH if randrange(0,2) else GPIO.LOW
        if not GPIO.input(io_num) == io_level and change_color_on:
            GPIO.output(io_num, io_level)
            sleep(0.1)
        sleep(0.01)

except KeyboardInterrupt:
    GPIO.cleanup()

Для запуска скрипта без указания в командной строке интерпретатора python3 сделаем файл исполняемым:

chmod +x ~/leds-switches-test.py

Запуск:

~/leds-switches-test.py

С помощью кнопок можно управлять различными режимами работы роутера, запускать и останавливать выполнение программ и служб, завершать работу операционной системы. RGB-светодиодом можно индицировать различные события и режимы работы, оповещать о пропадании интернет-канала и так далее.

Набор скриптов для управления

 

Статья еще в процессе написания...

 

Полезные ссылки:

  1. Decibel - dB (wikipedia)
  2. List of WLAN channels (wikipedia)
  3. wiki.archlinux.org - Resolv.conf
  4. Список AT-команд для модемов (M2M SUpport Forum)
  5. RTTTL (wikipedia)
Комментарии к публикации (3):
Владимир #1Владимир
28 Июнь 2018 18:34

Было бы интересно увидеть и последнюю часть)

+1
ph0en1x #2ph0en1x
01 Июль 2018 18:11

Владимир, у вас будет такая возможность Smile
Решил разделить последний раздел "Кнопочное управление, дисплей, пищалка, термодатчик" на несколько отдельных разделов и описать все более подробно.

0
Дмитрий #3Дмитрий
09 Июль 2018 14:54

Супер статья! Просто нет слов насколько она понятна, полезна, не вызывает не единого вопроса!Lol

+1