Сетевой шлюз на Orange Pi R1 и Yocto Project

Yocto Project - это совместный Open Source проект для упрощения разработки дистрибутивов для встраиваемых систем. Yocto содержит большое количество шаблонов, метаданных и инструментальных средств сборки, и  поддерживает очень большое количество аппаратных платформ.

Poky – это эталонная система сборки в рамках проекта Yocto Project. Название Poky также относится к эталонному дистрибутиву Linux, который создается этой системой сборки и может быть чрезвычайно минималистичным (core-image-minimal). В данной статье мы будем руководствоваться шаблоном core-image-minimal и на его основе создадим рецепт сборки дистрибутива для шлюза.

Содержание статьи:

Установка Yocto Project в Ubuntu

Для установки Yocto Project совместно со слоем поддержки платы "Orange Pi R1"
вы можете использовать "bash" скрипт следующего содержимого:

#!/bin/bash
#
# скрипт для установки Yocto Project 
# и слоя meta-sunxi для платы Orange Pi R1 
# и платы Orange Pi Zero
#
# license - The MIT License (MIT)
#
SYSTEM_BUILD="poky-router"
META_ROUTER="meta-router-bs"
#
BBLAYERS_CONFIG="build/conf/bblayers.conf"
LOCAL_CONFIG="build/conf/local.conf"
CONFIG_MACHINE="orange-pi-zero"
TYPE_PACKAGE="deb"
#
# версия "yocto-project" выбраная в качестве базовой,
# ветка sumo от 5 сентября 2018
GIT_YOCTO="git://git.yoctoproject.org/poky.git"
REV_YOCTO="51872d3f99e38f9d883ab0a8782ceecb41822fd0"
#
DIR_ORANGEPI="meta-sunxi"
GIT_ORANGEPI="https://github.com/linux-sunxi/$DIR_ORANGEPI"
# перешел на ветку sumo от 10 июня 2018
REV_ORANGEPI="85cc70a3fab2a750773576fa2b6631fcabbf3fdd"
#
get_git_project() {
    local git_path="$1"
    local git_rev="$2"
    local project_dir="$3"
    local cur_dir=`pwd`
#
    git clone --no-checkout $git_path $project_dir
#
    cd $project_dir
    git checkout $git_rev
    cd $cur_dir
}
#
sudo apt-get install -y --no-install-suggests --no-install-recommends \
     sed wget subversion git-core coreutils \
     unzip texi2html texinfo libsdl1.2-dev docbook-utils fop gawk \
     python-pysqlite2 diffstat make gcc build-essential xsltproc \
     g++ desktop-file-utils chrpath libgl1-mesa-dev libglu1-mesa-dev \
     autoconf automake groff libtool xterm libxml-parser-perl
#
old_dir=`pwd`
cd ..
#
get_git_project "$GIT_YOCTO" "$REV_YOCTO" "$SYSTEM_BUILD"
#
cd $SYSTEM_BUILD
poky_dir=`pwd`
get_git_project "$GIT_ORANGEPI" "$REV_ORANGEPI" "$DIR_ORANGEPI"
#
#####################################################################
# инициализация переменных Yocto Project
#####################################################################
source oe-init-build-env ""
cd $poky_dir
# создаем символическую ссылку на слой сборки шлюза
ln -v -s $old_dir/$META_ROUTER $META_ROUTER
#
# изменение настроек по умолчанию в конфигурационном файле системы сборки "Poky"
# добавление собственного слоя в список слоев BBLAYERS
# и добавление слоя сборки для "Orange Pi Zero"
sed -i "s|meta-yocto-bsp.*|&\n $poky_dir/$META_ROUTER \\\|g" $BBLAYERS_CONFIG
sed -i "s|meta-yocto-bsp.*|&\n $poky_dir/$DIR_ORANGEPI \\\|g" $BBLAYERS_CONFIG
sed -i "s|MACHINE ??=.*|MACHINE ??= \"$CONFIG_MACHINE\"|" $LOCAL_CONFIG
#
# тип бинарных пакетов для установки ПО 
F="PACKAGE_CLASSES ?= \"package_rpm\""
R="PACKAGE_CLASSES ?= \"package_$TYPE_PACKAGE\""
sed -i "s|$F|$R|" $LOCAL_CONFIG

После запуска установочного скрипта система сборки Poky будет располагаться каталогом выше, например если вы запустили установочный скрипт install.sh из каталога /home/user/router-bs, то система сборки Poky, будет установлена в каталог /home/user/poky-router

Скрипт прописывает две переменных в конфигурационном файле "build/conf/local.conf"

  • "MACHINE" - указывает архитектуру под которую собирается дистрибутив;
  • "PACKAGE_CLASSES" - указывает формат пакетов для установки ПО.

И добавляет два слоя в Poky, в файле  "build/conf/bblayers.conf"

Примечание: 
название корневого каталога системы сборки 
задается в скрипте установки
SYSTEM_BUILD="poky-router"

Назначение проекта сетевого шлюза

Проект предназначен для самостоятельной сборки с "нуля" Linux дистрибутива для одноплатного компьютера "Orange Pi R1" c минимальным набором программ, достаточным для использование Orange Pi R1 в качестве простого шлюза.

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

Основная функция нашего "Шлюза" - фильтрация внешнего (интернет) сетевого трафика приходящего на один сетевой интерфейс и передача его после фильтрации на другой сетевой интерфейс связанный с локальной сетью т.е. шлюз выполняет функцию "Брандмауэра" для защиты внутренней сети. Также шлюз будет обеспечивать подключение пользователей внутренней сети к ресурсам Интернет от имени своего ip адреса, т.е обеспечивать так называемую трансляцию сетевых адресов NAT (Network Address Translation).

Еще одной функцией "Шлюза" будет возможность получения от него динамических ip адресов, т.е. любая новая машина в локальной сети с помощью широковещательного запроса сможет получить ip адрес из выделенного диапазона адресов.

Таким образом "Шлюз" будет выполнять роль DHCP сервера (предполагается что шлюз одним сетевым интерфейсом подключен к сетевому коммутатору локальной сети).

Требования к оборудованию

Для создания сетевого шлюза, нам понадобиться одноплатный компьютер «Orange Pi R1» - на базе SoC Allwinner H2+ с характеристиками:

  • 4 ядра ARM Cortex-A7 с тактовой частотой 1.2 ГГц;
  • Объём оперативной памяти — 256 Мбайт DDR3 SDRAM;
  • На плате размещены два сетевых интерфейса;
  • Корпус;
  • Карта памяти - microSDHC, любого размера начиная от 8Гб (просто меньшего размера сейчас трудно найти);

Механизм сборки дистрибутива в Yocto Project

В Yocto Project каждая программная единица описывается с помощью рецепта сборки. Язык описания рецепта напоминает "bash" c возможностью вставок частей кода на языке "python".

Основную информацию по синтаксису вы можете почерпнуть из руководства Yocto Project

Набор рецептов сборки в зависимости от назначения можно объединять в отдельные слои сборки. В нашем случае все дополнительные рецепты которые расширяют функциональность базового дистрибутива Yocto, c минимальным количеством пакетов - "core-image-minimal" и привносят в него нужную нам функциональность "сетевого шлюза" будут храниться в слое "meta-router-bs".

Слой "meta-router-bs" прописывается в конфигурационном файле poky-router/build/conf/bblayers.conf в момент установки Poky (система сборки в рамках Yocto Project), см. главу Установка Yocto Project в Ubuntu этого документа (bash скрипт установки).

Структура слоя "meta-router-bs"

├── conf
│   └── layer.conf
├── recipes-connectivity
│   ├── bind
│   ├── dhcp
│   ├── ntp
│   ├── pps-tools
│   └── shorewall
├── recipes-core
│   ├── init-ifupdown
│   └── psplash
├── recipes-kernel
│   └── linux
└── recipes-router-bs
    └── images

Для внесения нужной нам функциональности мы по возможности будем использовать так называемые дополнения для рецептов, которые располагаются в файлах с расширением .bbappend. В файле .bbappend вы можете добавить собственные вызовы команд для штатного метода рецепта сборки, например в метод do_install, do_configure, do_compile  и т.д. В слое нашего шлюза находятся:

  • conf  - конфигурация слоя;
  • recipes-connectivity - рецепты сборки сетевых сервисов;
  • recipes-core - базовые репепты, настройка сетевых интерфейсов и стартовая заставка;
  • recipes-kernel - рецепт относящийся к сборки linux ядра;
  • recipes-router-bs - рецепт сборки прошивки с функциональностью шлюза.

Пакет поддержки платформы "Orange Pi"

Для того, чтобы собрать дистрибутив для Orange Pi Zero в Yocto Project существует отдельный слой - meta-sunxi. На github он располагается по адресу: https://github.com/linux-sunxi/meta-sunxi.

Плата которую мы выбрали - "Orange Pi R1" идентична плате "Orange Pi Zero" (за исключением дополнительной встроенной сетевой платы), и поэтому для сборки прошивки под нее мы будем указывать платформу MACHINE="orange-pi-zero"

Слой "meta-sunxi" хорошо работает прямо из коробки, это значит что нам пока без надобности знать особенности аппаратной работы и тонкости конфигурации Orange Pi Zero (все настройки можно оставить по умолчанию), т.е. нам достаточно подключить этот "BSP" слой в "Poky", и после сборки образа аппаратная поддержка платы Orange Pi R1 (Orange Pi Zero) будет включена в наш дистрибутив "router-bs".

Поддержка USB сетевых плат в "Orange Pi Zero"

Конечно в идеале нам необходимо взять плату с двумя встроенными сетевыми интерфейсами Orange Pi R1 , и далее это главу вы можете пропустить

Если же по какой то причине у вас есть под рукой только плата Orange Pi Zero, то рассмотрим гипотетический вариант использования второй, внешней USB => Ethernet сетевой платы. Таким же образом в дальнейшем вы можете подключить любое дополнительное оборудование (ну если конечно в Linux ядре это оборудование уже поддерживается).

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

  • Поддержка Linux ядром определенной сетевой платы;
  • Наличие в системе модуля ядра для определенной сетевой платы.

Возьмем к примеру сетевую плату Readyon RD-KY88772A, скорости подключения до 100 Мб/сек нам достаточно. Найдем чипсет на котором плата работает - это AX88772A разработка фирмы "ASIX".

Теперь найдем название параметра в конфигурации ядра отвечающую за драйвер чипсета AX88772A, лучше всего поискать сочетание слов "AX88772A cateee.net" (на google.com)
где "cateee.net" - сайт с полным описанием конфигураций модулей ядра Linux

Сразу находим название конфигурации ядра - CONFIG_USB_NET_AX8817X
и название нужного нам модуля ядра asix - https://cateee.net/lkddb/web-lkddb/USB_NET_AX8817X.html

Далее нам необходимо удостовериться, что в той версии ядра linux которое мы будет собирать в рамках Yocto Project, нужная нам конфигурация поддерживается, для этого мы можем в начале собрать ядро командой "bitbake linux-mainline" см. Краткую инструкция по созданию прошивки в конце статьи

A затем посмотреть сохраненный файл с текущей конфигурацией ядра:

poky-router/build/tmp/work/orange_pi_zero-poky-linux-gnueabi/linux-mainline/4.15-r0/defconfig

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

Для включения в образ поддерживаемых модулей ядра описанных в defconfig, в файле рецепта router-bs-image.bb  мы можем указать пакет "kernel-modules". Это добавит все собранные модули в наш образ, увеличив его ~ на 28 Mбайт, но позволит избавиться от части проблем с оборудованием.

Альтернативным вариантом является явное указание названия модуля, у нас это "kernel-module-asix"

Примечание:
Также следует отметить, что окончательная конфигурация ядра 
после сборки будет находиться здесь: 

poky-router/build/tmp/work/orange_pi_zero-poky-linux-gnueabi/
linux-mainline/4.15-r0/build/.config 

и если какое то подключенное устройство у вас не работает, 
то проверьте файл более внимательно (в defconfig содержаться 
рекомендуемые параметры и в окончательную конфигурацию, 
параметр может не попасть, если он не прошел проверку на 
совместимость с текущей версией ядра, проверка осуществляется 
автоматически, во время сборки ядра)

Механизм поддержки фрагментов конфигураций ядра

В Yocto Project вы можете создать небольшой конфигурационный файл, в котором указать только те параметры ядра, которые вам необходимы, и эти параметры будут добавлены к параметрам по умолчанию, которые уже входят в ядро, которое вы собираете (правда это не всегда работает для некоторых BSP слоев, но в нашем примере, мы покажем как эту функциональность добавить вручную)

например так: файл router-extra.cfg

# This option adds support for ASIX AX88xxx based USB 2.0 10/100 Ethernet adapters.
CONFIG_USB_NET_AX8817X=m
# Ethernet adapters, driver for TP Link UE300
CONFIG_USB_RTL8152=m
	
##### Orange Pi Zero ####
# This driver is used for H3/A83T/A64 EMAC ethernet controller, name module dwmac-sun8i
CONFIG_DWMAC_SUN8I=m

Файл будет располагаться по следующему пути:

router-bs/meta-router-bs/recipes-kernel/linux/files/router-extra.cfg

Чтобы подключить фрагмент конфигураций для нашей сборки ядра (у нас версия 4.15 )
нам необходимо добавить дополнение для рецепта сборки:

router-bs/meta-router-bs/recipes-kernel/linux/linux-mainline_4.15.bbappend

Следующего содержания:

# дополнительный параметры конфигурации описываются в router-extra.cfg
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
	
SRC_URI += "file://router-extra.cfg"

# в методе do_kernel_configme конфигурация ядра копируется из базы архитектур arch/ в рабочий каталог
do_kernel_configme_append() {
    cat ${WORKDIR}/router-extra.cfg >> ${WORKDIR}/defconfig
}

Настройка сетевого интерфейса шлюза

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

poky-router/meta/recipes-core/init-ifupdown/init-ifupdown_1.0.bb

у нас файл с дополнением будет располагаться:

poky-router/meta-router-bs/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend

Cледующего содержания:

FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI += "file://interfaces-router"

do_configure_append() {
  # заменяю скрипт /etc/network/interfaces
  install -d ${D}/etc/network
  install -m 0644 ${WORKDIR}/interfaces-router ${WORKDIR}/interfaces
}

В нашем расширении рецепта init-ifupdown_1.0.bb мы указываем, что в секцию "do_configure", а именно в конец секции (на это указывает строка "_append") мы добавляем команду копирования нашего файла с конфигурацией шлюза "interfaces-router" поверх существующего штатного файла "interfaces".

Указание SRC_URI += "file://interfaces-router" говорит рецепту о том что файл с указанным именем располагается по пути FILESEXTRAPATHS_prepend := "${THISDIR}/files:" (в начало списка FILESEXTRAPATHS добавляется путь с каталогом "files" текущего каталога)

Содержимое файла с конфигураций "files/interfaces-router":

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.0.1
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
# gateway xxx.xxx.xxx.xxx
# ip address DNS servers - OpenDNS Family Shield
dns-nameservers 208.67.222.123 208.67.220.123

#auto eth1
#iface eth1 inet static
# address 10.0.8.1
# netmask 255.255.255.0
# network 10.0.8.0
# broadcast 10.0.8.255
# dns-nameservers xxx.xxx.xxx.xxx

Здесь представлена настройка IP-адреса шлюза по умолчанию. Отредактируйте файл конфигурации files/interfaces-router, например так:

auto eth1
iface eth1 inet static
address 10.0.8.1
netmask 255.255.255.0
dns-nameservers 208.67.222.123 208.67.220.123

Где:

  • iface eth1 inet static - указывает, что интерфейс находится в диапазоне адресов IPv4;
  • address 10.0.8.1 - указывает что IP адрес нашей сетевой карты 10.0.8.1;
  • netmask 255.255.255.0 - указывает что наша маска подсети имеет значение 255.255.255.0;
  • dns-nameservers 208.67.222.123 208.67.220.123 - адреса DNS серверов

Еще в конфигурации сетевого интерфейса вы можете прописать адрес шлюза более верхнего уровня gateway xxx.xxx.xxx.xxx  (обычно данную информацию предоставляет провайдер). Запись auto eth1 - указывает что интерфейс eth1 необходимо включать автоматически при загрузке системы

В приведенном выше примере используются немаршрутизируемые адреса для локальной сети, и данный сетевой интерфейс eth1 будет считаться внутренним (закрытым из вне), для него адрес шлюза указывать не нужно

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

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

Все параметры конфигурации в этом случае вы должны взять у своего "Интернет Провайдера" т.е. компании поставщика услуг на доступ в Интернет

Настройка DHCP сервера на шлюзе

Наш "Шлюз" будет выполнять роль DHCP сервера (протокол динамической конфигурации узла). Настройки DHCP сервера на конечном устройстве будут храниться в файле "/etc/dhcp/dhcpd.conf" поэтому для замены исходного файла с настройками, нам необходимо включить в наш слой meta-router-bs рецепт сборки версии dhcp_4.4.1.bb

Примечание:
в той ветке Yocto Project, которую мы используем -"Sumo", уже 
включен рецепт сборки dhcp 4.3.6, но он у нас корректно 
не заработал, сервис не реагировал на сигнал завершения sigterm 
и не отвечал на широковещательные запросы 
т.е на клиенте висели сообщения:
    DHCPDISCOVER on enp3s0 to 255.255.255.255 port 67 interval 3 ...
    ...
поэтому его заменили более свежей версией

в Pokу рецепт храниться по пути:

poky-router/meta/recipes-connectivity/dhcp/dhcp_4.3.6.bb

У нас файл с новым рецептом dhcp_4.4.1 будет располагаться:

poky-router/meta-router-bs/recipes-connectivity/dhcp/dhcp_4.4.1.bb

Конфигурационные файлы которые мы подправим "dhcpd.conf" и "default-server"
будут находиться в каталоге poky-router/meta-router-bs/recipes-connectivity/dhcp/files

Содержимое файла с конфигураций "dhcpd.conf"

ddns-update-style none;
default-lease-time 36000;
max-lease-time 72000;

subnet 10.0.8.0 netmask 255.255.255.0 {
    range 10.0.8.14 10.0.8.100;
    # ip address OpenDNS Family Shield
    option domain-name-servers 208.67.222.123, 208.67.220.123;
    option subnet-mask 255.255.255.0;
    option routers 10.0.8.1;
}

"default-server" - файл конфигурации, который содержит имена сетевых интерфейсов
на которых DHCP сервер будет работать,в нашем случае это будет имя внутреннего сетевого интерфейса шлюза
INTERFACES="eth1"

Описание параметров настройки:

  • ddns-update-style - схема обновления DNS, в настоящий момент не используется, параметр none
  • default-lease-time - время по умолчанию в секундах на которое сервер выделяет ip адрес клиенту, пока действует lease-time сервер не может отдать данный ip-адрес другой машине. Пока ip-адресов больше чем компьютеров в сети, допустим офисная сеть, где все машины стационарны то lease-time можно ставить побольше, тот же месяц. Тогда и вероятность, что машина получит при включении другой адрес будет минимальна. А если адресов не так много, а компьютеры меняются часто, допустим кафе и wi-fi доступ, то lease-time нужно поменьше, например 1 час. У нас в примере время lease-time равно 36000 сек. (10 часов)
  • max-lease-time - максимальное время на которое выделяется ip адрес клиенту у нас в примере время max-lease-time равно 72000 сек. (20 часов)

Далее в блоке subnet указываем адрес нашей сети, сетевую маску, диапазон ip адресов которые будут использоваться, адрес(а) DNS серверов, которые по буквенному имени домена возвращают ip адрес (обычно назначается вашим провайдером), маска подсети и адрес шлюза.

Итак мы указали основной минимальный набор параметров, которые необходимы для работы DNS сервера на нашем "Шлюзе".

Фильтрация сетевых пакетов - функции "Брандмауэра"

В linux фильтрация пакетов происходит на уровне ядра операционной системы в модуле "netfilter" и управляется утилитой iptables.

Так как правила настройки iptables крайне сложные и запутанные мы будем использовать, удобную утилиту, которая позволяет в простой пользовательской форме задать эти правила, без необходимости изучения "iptables". Для настройки будет использована программа скрипт, программа Shorewall.

Shorewall использует правила описания каждого из аспектов фильтрации в отдельном файле, и при запуске использует Perl для разбора файлов и генерации правил уже в формате "iptables".

Конфигурация "Зоны" шлюза

Правила хождения пакетов в Shorewall используют абстракцию зон — все сети, которые вы хотите обрабатывать, надо как-то обозвать. Для начала следует определиться с названиями зон. В нашем случае их будет 3:

  • fw - необходимая зона, содержащая сам файрволл;
  • net - провайдерская сеть;
  • loc - локальная (или домашняя) сеть с DHCP.

Конфигурация получается примерно такой: файл zones, путь на целевом устройстве - /etc/shorewall/zones, путь в Poky - poky-router/meta-router-bs/recipes-connectivity/shorewall/files/zones

...
fw    firewall
net   ipv4
loc   ipv4

Интерфейсы и хосты

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

  • Путь на целевом устройстве /etc/shorewall/interfaces
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/interfaces
...
#ZONE INTERFACE BROADCAST OPTIONS
net     eth0    detect    tcpflags,nosmurfs,routefilter,logmartians
loc     eth1    detect    dhcp,tcpflags,nosmurfs,routefilter,logmartians
  • Параметр "detect" говорит shorewall автоматически определить широковещательный адрес, его можно прописать и вручную, например так: 10.0.8.255 для внутреннего сетевого интерфейса с ip адресом 10.0.8.1, см. выше.
  • Опция tcpflags - пакеты, поступающие на этот интерфейс проверяются на наличие определенных незаконных комбинаций TCP флагов.
  • Опция routeback - заставляет весь трафик, пришедший через интерфейс X, возвращаться к отправителю через него же (без этого практически не обойтись в ситуации, когда провайдеров несколько).
  • Опции nosmurfs,logmartians - разные по своему действию, но близкие по духу параметры, заставляющие Shorewall обращать внимание на пакеты, которых "точно не должно быть на этом интерфейсе". Так, пакеты с широковещательным адресом отправителя отклоняются (nosmurfs), "марсиане" (пакеты с некорректным исходным адресом) протоколируются (logmartians).
  • Опция routefilter предписывает включить в ядре фильтрацию по маршруту, но пользоваться им следует с осторожностью: в схеме с несколькими исходящими каналами возможны трудно диагностируемые неполадки.
  • Опция dhcp - сообщает, что на интерфейсе выполняется DHCP-клиент или сервер;

Политики

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

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

  • Путь на целевом устройстве /etc/shorewall/policy;
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/policy.
...
#SOURCE   DEST    POLICY   LOG LEVEL LIMIT:BURST
# разрешение трафика из зоны локальной сети во внешнюю
loc       net     ACCEPT
	
# запрещение трафика инициированное внешней сетью
net       all     DROP     info
	
# отвергать все другие запросы на соединение
# (Shorewall требует наличия такой политики,
# применимой для всех остальных запросов).
# строка обязательно должна быть последней в файле policy
all       all     REJECT   info

Настройка трансляции сетевых адресов NAT

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

  • Путь на целевом устройстве /etc/shorewall/masq;
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/masq.
...
#INTERFACE		SOURCE		ADDRESS		PROTO	PORT(S)	IPSEC	MARK
eth0          eth1

В колонке INTERFACE указывается интерфейс назначения т.е. внешний интерфейс подключенный к интернету, в нашем случае это eth0. В поле SOURCE перечисляются адреса (исходящие адреса), для которых нужно применить SNAT-преобразование: здесь, как и во многих реальных случаях, это просто eth1, то есть вся локальная сеть целиком. При желании, имя интерфейса можно заменить явным указанием "серых" адресов (скажем, 192.168.0.0/24). Запретить SNAT для избранных узлов сети можно при помощи следующего синтаксиса:

eth1:!192.168.0.1,192.168.0.3

Кстати, он действует и во многих других конфигурационных файлах Shorewall.

Настройка правил фильтрации

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

  • Путь на целевом устройстве /etc/shorewall/rules;
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/rules.
#ACTION  SOURCE DEST  PROTO DEST SOURCE ORIGINAL RATE USER/ MARK
SECTION NEW
	
# запрещать некорректные пакеты из внешней сети
Invalid(DROP)	net		all
	
# Разрешать соединения по протоколу DNS от роутера во внешнюю сеть
# иначе вы не сможете определить ip адрес узла по имени сайта
DNS(ACCEPT)	$FW		net
	
# Разрешать соединение с роутером по протоколу SSH
# из локальной сети для администрирования
SSH(ACCEPT)	loc		$FW
	
# Разрешить работу утилиты ping
# из локальной сети до роутера
Ping(ACCEPT)	loc		$FW
	
# Запретить возможность ping(ования) из внешней сети
Ping(DROP)	net		$FW
	
# разрешить передачу пакетов icmp от роутера
# и в локальную и во внешнюю сеть
ACCEPT		$FW		loc		icmp
ACCEPT		$FW		net		icmp
	
# разрешить передачу пакетов NTP (протокол сетевого времени)
# и в локальную и во внешнюю сеть
NTP(ACCEPT)	loc		$FW
NTP(ACCEPT)	$FW		net

В начале указывается действие (РАЗРЕШЕНИЕ/ЗАПРЕЩЕНИЕ), далее исходящий интерфейс, далее сетевой интерфейс назначения, далее протокол и после этого возможно явно указать номер(а) портов, для которых предназначено данное действие.

Так же по причине безопасности роутера, не рекомендуем вам оставлять возможность удаленного администрирования роутера из Интернета, пример правила: "SSH(ACCEPT) net $FW" в этом случае как минимум необходимо подобрать сложный пароль администратора (root), а также не использовать порт 22 по умолчанию, так как в любой открытой сети всегда приходят пакеты по протоколу ssh с попыткой автоматического подбора пароля.

Такой перебор выполняется специальными программами сканерами в автоматическом режиме, и в 95% случаев достаточно изменить номер стандартного порта, что бы случайным образом не оказаться взломанным

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

Остановка Shorewall

Когда файервол останавливается, маршрутизация разрешается на те хосты, которые указаны в файле routestopped:

  • Путь на целевом устройстве /etc/shorewall/routestopped;
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/routestopped.
#INTERFACE	HOST(S)                  OPTIONS
eth1		-

В данном случае мы указываем что после остановки Shorewall разрешена маршрутизация на любые адреса ("-" значит "0.0.0.0/0") c внутреннего сетевого интерфейса

ПРИМЕЧАНИЕ:  если вы хотите полностью очистить правила внесенные Shorewall в "netfilter", вы должны выполнить команду «shorewall clear»

Конфигурация Shorewall

Основной конфигурационный файл расположен:

  • Путь на целевом устройстве /etc/shorewall/shorewall.conf;
  • Путь в Poky poky-router/meta-router-bs/recipes-connectivity/shorewall/files/shorewall.conf.

В этом файле лежит конфигурация парсера, некоторые особенности поведения. За основу был взять конфигурационный файл из примера настройки Shorewall, файл является достаточно большим и подробно вы можете изучить его самостоятельно. Пример конфигурационного файла на целевом устройстве /usr/share/shorewall/configfiles/shorewall.conf

Примеры настройки Shorewall

В пакет поставки Shorewall входят хорошие, достаточно универсальные примеры настройки для конфигурации сетевых интерфейсов:

однопортовой      /usr/share/doc/shorewall/examples/one-interface
двухпортовой      /usr/share/doc/shorewall/examples/two-interfaces
трех портовой     /usr/share/doc/shorewall/examples/three-interfaces
и универсальной   /usr/share/doc/shorewall/examples/Universal

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

poky-router/build/tmp/work/armv7vehf-neon-poky-linux-gnueabi/shorewall/4.4.27-r0.0/shorewall-4.4.27.3/Samples

Рецепт сборки Shorewall для слоя meta-router-bs

Для того, чтобы собрать пакет Shorewall в нашем дистрибутиве, мы возьмем его рецепт сборки из проекта "OpenEmbedded"

OpenEmbedded — инфраструктура для сборки пакетов для встраиваемого Linux. OpenEmbedded предлагает решение в классе сред для кросс-компиляции. Он позволяет разработчикам создавать целостные дистрибутивы Linux для встраиваемых систем.

Исходный рецепт можно взять вот отсюда, http://git.openembedded.org/openembedded/plain/recipes/shorewall/shorewall_4.4.14.bb

И в дальнейшем модифицируем его, обновив до последней стабильной ревизии в версии 4.4, у нас это 4.4.27

Добавим рецепт shorewall_4.4.27.bb в наш слой сборки "meta-router-bs" предварительно немного изменив его, дописав в секцию установки (do_install_append) замену конфигурационных файлов по умолчанию, файлами, описанными выше: zones, interfaces, policy, masq, rules, routestopped и shorewall.conf

poky-router/meta-router-bs/recipes-connectivity/shorewall/shorewall_4.4.27.bb

LICENSE = "GPL"
LIC_F = "file://${COREBASE}/meta/files/common-licenses/GPL-1.0"
SUM_F = "md5=e9e36a9de734199567a4d769498f743d"
LIC_FILES_CHKSUM = "${LIC_F};${SUM_F}"

SUB_PR = ".3"
require shorewall.inc
# this version (4.4) requires some deps (perl)
require shorewall-deps.inc


# запуск стартового скрипта /etc/init.d/shorewall 
# на определенном уровне исполнения
# последовательность запуска, перед сервисом ssh и dhcp
inherit update-rc.d
INITSCRIPT_NAME = "shorewall"
INITSCRIPT_PARAMS = "start 08 2 3 4 5 . stop 92 0 6 1 ."


PR = "${INC_PR}.0"
SRC_URI = "\
	http://www.shorewall.net/pub/shorewall/4.4/shorewall-${PV}/${PN}-${PV}${SUB_PR}.tar.bz2 \
	file://zones \
	file://interfaces \
	file://policy \
	file://masq \
	file://rules \
	file://shorewall.conf \
	"

# отключаю секцию do_compile, так как /sbin/shorewall является исполняемым скриптом
# и не требует компиляции
do_compile[noexec] = "1"

SRC_URI[md5sum] = "9f0ef6b547526aa33e34941a211ca602"
SRC_URI[sha256sum] = "1f95a04af2cbdd3449aa6fb26ea1b001e7cccd1ad4ed6d7ed8648247ae5d09bb"

do_install_append () {
	install -m 0644 ${WORKDIR}/zones ${D}${sysconfdir}/shorewall/zones
	install -m 0644 ${WORKDIR}/interfaces ${D}${sysconfdir}/shorewall/interfaces
	install -m 0644 ${WORKDIR}/policy ${D}${sysconfdir}/shorewall/policy
	install -m 0644 ${WORKDIR}/masq ${D}${sysconfdir}/shorewall/masq
	install -m 0644 ${WORKDIR}/rules ${D}${sysconfdir}/shorewall/rules
	install -m 0644 ${WORKDIR}/shorewall.conf ${D}${sysconfdir}/shorewall/shorewall.conf
}

poky-router/meta-router-bs/recipes-connectivity/shorewall/shorewall.inc

DESCRIPTION = "Shorewall is a high-level tool for configuring Netfilter."
HOMEPAGE = "http://www.shorewall.net/"
LICENSE = "GPLv2"
SECTION = "network"
PRIORITY = "optional"

INC_PR = "r0"
S = "${WORKDIR}/${PN}-${PV}"

RDEPENDS_${PN} += "iptables"
RRECOMMENDS_${PN} = "kernel-module-ip-tables \
		     kernel-module-ip-conntrack \
		     kernel-module-ipt-conntrack \
		     kernel-module-ipt-multiport \
		     kernel-module-ipt-log \
		     kernel-module-ipt-mac \
		     kernel-module-ipt-mark \
		     kernel-module-ipt-masquerade \
		     kernel-module-ipt-pkttype \
		     kernel-module-ipt-reject \
		     kernel-module-ipt-state \
		     kernel-module-ipt-tos \
		     kernel-module-iptable-filter \
		     kernel-module-iptable-mangle \
		     kernel-module-iptable-nat \
		    "

do_install() {
	export PREFIX=${D}
	${WORKDIR}/${PN}-${PV}${SUB_PR}/install.sh
}

FILES_${PN} += "/usr/share/shorewall/*"

poky-router/meta-router-bs/recipes-connectivity/shorewall/shorewall-deps.inc

# version 4.4.x requires perl + some perl modules
RDEPENDS_${PN} += "\
	perl \
	perl-module-lib \
	perl-module-autouse \
	perl-module-cwd \
	perl-module-file-basename \
	perl-module-file-temp \
	perl-module-getopt-long \
	perl-module-carp \
	perl-module-findbin \
	perl-module-file-spec-unix \
	perl-module-scalar-util \
	perl-module-io \
	perl-module-io-handle \
	perl-module-exporter-heavy \
	perl-module-list-util \
	perl-module-socket \
	perl-module-overloading \
"

Рецепт сборки образа Router-bs

Для того, чтобы в Yocto Project собрать минималистический дистрибутив "router-bs" нам необходимо добавить файл рецепта router-bs-image.bb в слой "meta-router-bs"

poky-router/meta-router-bs/recipes-router-bs/images/router-bs-image.bb

#
# Минималистический дистрибутив Linux, выполняющий функции "Маршрутизатора"
# для платформы Orange PI собранный в "Yocto Project",
#
DESCRIPTION = "The Router BS -  is a simple image to Orange Pi platform"
LICENSE = "MIT"
MD5_MIT = "md5=0835ade698e0bcf8506ecda2f7b4f302"

LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_MIT}"

# добавление нескольких стандартных пакетов в базовый образ
IMAGE_FEATURES += "ssh-server-openssh splash"

# Образ базируется на рецепте сборки содержащем минимальный набор пакетов
# Base this image on core-image-minimal
include recipes-core/images/core-image-minimal.bb

# Установка пароля по умолчанию для пользователя "root"
# - основная административная учетная запись в системе
# Set default password for 'root' user
inherit extrausers
ROOTUSERNAME = "root"
ROOTPASSWORD = "routerbs"
EXTRA_USERS_PARAMS = "usermod -P ${ROOTPASSWORD} ${ROOTUSERNAME};"

###########################################################################
# набор установочных пакетов входящих в образ, разбитый на категории
###########################################################################
# пакеты библиотеки libc входящие в образ, локализация,
# символьные таблицы для различных языков и т.п.
ROUTER_GLIBC = " \
		 glibc-thread-db \
		 glibc-gconv-utf-16 \
		 glibc-gconv-utf-32 \
		 glibc-gconv-koi8-r \
		 glibc-gconv-cp1251 \
		 glibc-gconv-ibm866 \
		 glibc-binary-localedata-en-us \
		 glibc-binary-localedata-ru-ru \
		 glibc-binary-localedata-ru-ru.koi8-r \
		 glibc-charmap-cp1251 \
		 glibc-charmap-koi8-r \
		 glibc-charmap-utf-8 \
		 "
	
# базовые пакеты
ROUTER_BASE = " \
	        kernel-modules \
	        lsb \
	        pciutils \
	        "
	
# сетевые пакеты и модули ядра
ROUTER_NET = "kernel-module-asix \
	     "
	
# приложения входящие в образ
ROUTER_SOFT = " \
		mc \
		ntp \
		resolvconf \
		dhcp-server \
		init-ifupdown \
		shorewall \
		shorewall-doc \
		"
	
# указание всех дополнительных пакетов дистрибутива "Router-bs"
# Include modules in rootfs
IMAGE_INSTALL += " \
	${ROUTER_BASE} \
	${ROUTER_GLIBC} \
	${ROUTER_NET} \
	${ROUTER_SOFT} \
	"

Дополнительные рецепты включенные в слой

В нашей плате Orange Pi R1 отсутствуют встроенные часы реального времени, а значит после выключения компьютера время сбрасывается, что не очень удобно. И поэтому при старте компьютера, текущее время будет запрашиваться из Интернета. Для этого мы установим сервис NTPD.

Сервис ntpd (Network Time Protocol daemon) — программа-демон, которая устанавливает и поддерживает системное время, используется для синхронизации серверами точного времени. Рецепт сборки сервиса ntpd был взят как есть из слоя: https://github.com/openembedded/meta-openembedded на ветке "Sumo".

Примечание: так же в нашем слое meta-router-bs присутствует рецепт bind_9.11.4.bb новой версии,
это зависимость для dhcp_4.4.1.bb и рецепт pps-tools_git.bb от которого зависит ntp_4.2.8p11.bb

Поддерживаемые платформы

Ниже мы приведем общей список поддерживаемых платформ слоя "meta-sunxi", перед публикаций мы проверили сборку прошивки только для плат "Orange Pi R1" и "Orange Pi Zero", но возможность выбора достаточно большая.

  • orange-pi-zero;
  • bananapi;
  • cubieboard2;
  • cubieboard;
  • cubietruck;
  • forfun-q88db;
  • mele;
  • meleg;
  • nanopi-neo-air;
  • nanopi-neo;
  • olinuxino-a10lime;
  • olinuxino-a10s;
  • olinuxino-a13;
  • olinuxino-a13som;
  • olinuxino-a20;
  • olinuxino-a20lime2;
  • olinuxino-a20lime2-emmc;
  • olinuxino-a20lime;
  • olinuxino-a20som;
  • orange-pi-one;
  • orange-pi-pc;
  • orange-pi-pc-plus;
  • orange-pi-zero-plus2;
  • pcduino.

Ну и конечно мы не могли обойти своим вниманием самую распространенную платформу в среде "Гиков" - Raspberry Pi. Для сборки прошивки под эту плату в "Yocto Project" необходимо использовать слой "meta-raspberrypi".  Этот BSP слой поддерживает следующие устройства:

  • raspberrypi;
  • raspberrypi0;
  • raspberrypi0-wifi;
  • raspberrypi2;
  • raspberrypi3-64;
  • raspberrypi3;
  • raspberrypi-cm3;
  • raspberrypi-cm.

Примечание: вся функциональность касающаяся платы Raspberry Pi в нашем примере находится на ветке "raspberry-sumo", см. пункт ниже (загрузка проекта с github).

Краткая инструкция по созданию прошивки

1) Загрузите проект с github:

git clone https://github.com/berserktv/router-bs.git -b orange-sumo

2) Установите Yocto Project (Poky):

cd router-bs
chmod u+x install.sh
./install.sh

3) Соберите проект:

cd ../poky-router
. ./oe-init-build-env
bitbake router-bs-image

4) Время сборки проекта:

Время сборки образа дистрибутива достаточно длительное
и может занимать от одного до N часов в зависимости от производительности
компьютера, также в процессе сборки из "Интернета" должны быть
загружены исходные коды всех программ входящих в дистрибутив,
часто это полные git базы

(т.е. время сборки также зависит от скорости подключения сети "Интернет")

например на машине: Процессор     - Intel(R) Core(TM)i5-3570 CPU@3.40GHz
                    ОЗУ           - 8 Гбайт
                    Жесткий диск  - внутренний SATA 3Tбайт

                    Время сборки  - 1 час 25 минут
                    Размер образа - 144 Мбайт

ПРИМЕЧАНИЕ: размер образа можно значительно уменьшить,
            более чем в три раза, если перейти на
            сжатую файловую систему squashfs,
            а диски перевести в режим только чтения
            но это совсем другая история ...

Размер каталога poky-router/build после завершения сборки
(cache сборки, исходный код всех программ входящих в образ,
в разных форматах, в случае с git базами они загружается целиком
со всей историей, промежуточные файлы сборки, обьектные файлы,
файлы пакетов и т.п.)
занимает примерно 25 ГБайт (du -sh build)

Из этих 25 Гбайт, размер каталога build/downloads
(git базы приложений и tar.gz архивы)
занимают 2.8 Гбайт

5) Запишите проект на карту памяти - "microSDHC"

Административный пароль по умолчанию

В образе Router-bs по умолчанию включена учетная запись:

  • root - пользователь;
  • routerbs - пароль по умолчанию.

ВНИМАНИЕ: обязательно смените пароль по умолчанию на собственный

Пароль можно сменить выполнив команду passwd на самом устройстве, или в случае самостоятельной сборки в файле рецепта router-bs-image.bb.

Первое включение устройства

В том случае если вы не перенастроили проект под ваше сетевое окружение, а сразу включили Orange Pi R1, вы можете подключиться к вашему шлюзу по протоколу SSH (команда ssh root@192.168.0.1 c другого компьютера) по ip адресу по умолчанию: 192.168.0.1.

Для этого вы должны подключить кабель к первому сетевому интерфейсу (eth0), если вы не знаете, какой интерфейс у вас первый, то вы можете последовательно подключить сетевой кабель вначале к одному интерфейсу и проверить, ответ на команду ping, а затем и ко второму. Тот интерфейс, который первым ответит и будет искомым. Если вы не получили ответ ни по одному сетевому интерфейсу, то вначале проверьте находитесь ли вы в правильной подсети 192.168.0.0.

Если все равно ответ не получен, то что то пошло не так и в этом случае мы можете подключить технологический последовательный интерфейс UART к Orange Pi R1 и таким образом понять состояние устройства.

Запись прошивки на карту памяти microSDHC

Собранный образ будет располагаться по пути poky-router/build/tmp/deploy/images/orange-pi-zero

На последний успешно собранный образ всегда будет указывать символическая ссылка: router-bs-image-orange-pi-zero.sunxi-sdimg т.е. poky-router/build/tmp/deploy/images/orange-pi-zero/router-bs-image-orange-pi-zero.sunxi-sdimg, cам файл будет содержать достаточно длинное имя c датой создания и временем в UTC например такое: router-bs-image-orange-pi-zero-20180916164236.rootfs.sunxi-sdimg.

Для записи прошивки на карту памяти используется команда dd. Запуск команды dd выполняется от имени администратора, при этом необходимо указать входной файл и устройство подключения карты памяти "microSDHC", например /dev/sdX, где X может быть a,b,c и т.д. в зависимости от предыдущих подключенных дисковых разделов.

Проще всего название определить по выводу команды blkid. Наберите команду sudo blkid до подключения карты памяти - "microSDHC" и далее наберите команду sudo blkid после подключения карты памяти - "microSDHC"
и тот новый раздел который появился в выводе последней команды и будет искомым. Отмонтируйте разделы карты памяти - "microSDHC" например так, если разделов несколько:

umount /dev/sdX1
umount /dev/sdX2

В команде dd указывается имя диска целиком т.е. без номера раздела так как в образе содержатся таблицы двух разделов, первый раздел загрузочный диск формата fat16, и второй раздел ext4 - корневая файловая система ОС Linux

Примечание: текущем каталогом в примере указанном ниже является каталог poky-router/build

ВНИМАНИЕ: все предыдущие данные на карте памяти "microSDHC"
после выполнения операции записи будут удалены.

sudo bash
cd tmp/deploy/images/orange-pi-zero
dd if=router-bs-image-orange-pi-zero.sunxi-sdimg of=/dev/sdX bs=1M
sync

Выводы

Итак в заключении статьи хотелось бы отметить, что "Yocto Project" достаточно мощный инструмент для сборки специализированных дистрибутивов для встраиваемых систем. В нашем обзоре, мы показали как собрать прошивку с крайне ограниченным набором функций для платы Orange Pi R1.

Конечно каждый инструмент имеет как свои плюсы, так и свои минусы. На наш взгляд главным достоинством подобного инструмента является то, что у вас есть полный контроль над исходным кодом вашей прошивки, а все остальное дело техники, т.е. в любой момент вы можете подключить нужный вам патч в Linux Kernel, обновить DHCP, обновить NTP, обновить Shorewall, установить любой дополнительный "Open Source Soft" под ваши нужды.

5 комментариев

  1. Чукча-писатель Декабрь 1, 2018 Ответить
  2. Юрий Декабрь 1, 2018 Ответить
  3. AlexVit Декабрь 11, 2018 Ответить
  4. AlexVit Декабрь 11, 2018 Ответить
  5. AlexVit Декабрь 11, 2018 Ответить

Ответить

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: