В этой статье я попытаюсь рассказать, как прошить на роутер OpenWrt и установить туда cjdns. По правде говоря, изучение тонкостей этого дела отняло у меня много времени и нервов. В основном потому, что многое в OpenWrt недодокументировано, и приходилось многое искать по форумам и додумывать. Думаю, это как раз тот случай, когда лучшей документацией являются исходники. Так что эту статью я попытаюсь написать такой, какую я хотел бы прочитать в самом начале этого пути.
Итак, первое, что следует сделать, это пойти на сайт OpenWrt и посмотреть список поддерживаемых устройств: wiki.openwrt.org/toh/start
Если не нашли вашу железку, не растраивайтесь. <sarcasm>
Мы ведь всегда можем портировать OpenWrt на новое усекщйство, следуя этой инструкции: kamikaze.openwrt.org/docs/openwrt.html#x1-540002.3 </sarcasm>
Хотя, сначала нужно как-то вытянуть исходники ядра у прооизводителя.
Теперь немного теории. В OpenWrt для хранения rootfs используется две файловые системы: SquashFS и JJFS2. Так же вожможно подключение других, но об этом позже.
SquashFS — сжатая статическая файловая система. Она — то, что собственно и прошивается. За счет своей статичности, сжатие в ней лучше.
JJFS2 — сжатая динамическая файловая система, в которую записываются изменения файлов. Она монтируется как-бы поверх SquashFS при помощи фичи ядра Linux Overlayfs. Появилась она начиная с версии ядра 3.11.
Среду для сборки OpenWRT можно скачать в 4-х вариантах.
- OpenWrt Buildroot — эдакий монстр Франкенштейна, написаный на make, который сам качает исходники всего, что нужно, сам же патчит все это, сам собирает кросскомпилятор, собирает пакеты и образы для прошивки. Форк Buildroot Насчет формата этих makefil-ов. Тут достаточно процитировать документацию:
«Глядя на Makefile из какого либо пакета, вы вряд ли узнаете в нем обычный Makefile. Это может быть охарактеризовано как вопиющее пренебрежение и жестокое обращение с традиционным форматом make, однако, преобразование Makefile пакета в объектно-ориентированный шаблон позволило упростить весь процесс портирования приложений.» - OpenWrt Image Builder — то же самое, но грузиту уже откомпиленые пакеты и собирает из них образ.
- OpenWrt SDK — то же самое, но набор програм для кросскомпиляции уже собран и собирать образы оно уже не может. Предназначено для сборки отдельных пакетов.
- OpenWrt based Toolchain — уже откомпиленый набор програм для кросскомпиляции, выдраный из Openwrt Buildroot.
Последние три могут быть собраны из OpenWrt Buildroot.
Как уже было сказано выше, в SquashFS сжатие лучше, так что у нас есть больше шансов уместить все, что нужно, собрав прошивку самостоятельно, чем скачав готовый образ и доставив нужный пакет. Для тех, кто собирается ставить готовую минимальную прошивку вот сборки от разработчиков. Они рассортированы по архитектурам (колонка target в списке поддерживаемого оборудования) и по типу памяти (nand и все остальные), названия файлов включают в себя названиероутера. Прошивки, содержащие в названии «sysupgrade» предназначены для перепрошивуи средствами уже установленой OpenWrt. Содержащие «factory» можно скормить вебформе заводской прошивки. Не перепутайте.
Приступим к сборке.
Внимание! Сборка не должна проводится от суперпользователя или в fakeroot.
Для начала загрузим buildroot. Здесь есть список веток и команд для их загрузки. Мы же будем собирать Attitude Adjustment stable:
git clone git://git.openwrt.org/12.09/openwrt.git
Репозиториев с beta, beta2, rc1 и rc2, видимо, нету, а жаль, потому что пакет, собраный для stable на beta не стал, только ругнулся, что git commit id ядра не тот, который нужен (хотя верси совпадали).
Далее, следуя инструкции добавляем в список мест, откуда будут грузится исходники «репозиторий» с openwrt:
cd ./openwrt
cp feeds.conf.default feeds.conf
Добавляем в файл feeds.conf строку
src-git cjdns git://github.com/cjdelisle/cjdns-openwrt.git
Далее, грузим исходники всех пакетов:
./scripts/feeds update -a
./scripts/feeds install -a
Теперь запускаем
make menuconfig
и настраиваем все, что нужно.
Выбираем «Target System» (ту, которая указана в списке поддерживаемых устройств возле названия вашего роутера), Subtarget (если в роутере постоянная память не NAND, смело выбираем Generic), «Target Profile» (ищем название роутера, под который будем собирать). В «Target Images» обычно ничего менять не надо. Выбираем пробелом.
На данном этапе все нужные драйверы уже отмечены (благодаря «Target Profile») Далее ходим по остальным веткам и выбираем нужные нам пекеты (Именно нам. По идее, и так работать будет). Поиска здесь не предусмотрено, так что искать будем так:
find ./feeds/ -name nano
Благо, большинство пакетов рассортировано по разделам. Хотя они могут находится и в ./package и тогда вы их таким образом не найдете. В выводе видим ./feeds/packages/utils/nano, что значит, что nano нам нужно искать в разделе «Utilities». Для полной уверенности можно почитать makefile пакта. Для nano это ./feeds/packages/utils/nano/Makefile. В нем мы видим такой фрагмент:
define Package/nano
SUBMENU:=Editors
SECTION:=utils
CATEGORY:=Utilities
TITLE:=An enhanced clone of the Pico text editor
URL:=http://www.nano-editor.org/
MAINTAINER:=Bernhard Loos <bernhardloos@googlemail.com>
DEPENDS:=+libncurses
endef
«CATEGORY» — название раздела, «SUBMENU» — название подраздела. Кстати, такая запись может быть не одна. Дело в том, что из одного набора исходников может собиратся несколько разных пакетов.
Итак, пакеты, которые нам могут понадобится.
- nano — чтобы не пришлось править конфиги с помощью vi или cat/echo
- htop — просмотрщик процесов
- iftop — програмка для отслеживания сетевой активности (кто, с кем, на какой порт, с какой скоростью)
- tcpdump — ну куда ж без него?
- kmod-usb-storage — модуль ядра для подключения внешних носителей памяти по usb
- kmod-usb-storage-extras — модуль ядра для подключения некоторых экзотических внешних носителей памяти по usb (например, кардридера)
- block-mount — набор скриптов для автоматического монтирования по /etc/fstab. Для автомонтирования файловых систем по конфигам в формате uci (об этом позже) хватит и mount из busybox, но swap автоматически без них не монтируется.
- swap-utils — необходим для монтирования swap
- Всевозможные драйверы файловых систем. Найти можно в «Kernel modules»->«Filesystems»
- shadow-groopadd, shadow-groupdel, shadow-groupmod, shadow-groups, shadow-passwd, shadow-su, shadow-useradd, shadow-userdel, shadow-usermod — набор утилит для управления пользователями и группами. Обычно можно обойтись и без них.
- ip,iw,iptables,ip6tables — для ручной настройки сети
- bind-dig — dns-клиент
Следует отметить, что все может и не поместится. В таком случае одраз для роутера собран не будет, но пакеты соберутся. Пакет можно отметить и так, чтобы он собрался, но в образ не включался. Для этого нужно нажать клавишу m.
А теперь расскажу одном баге, который мешает сборке cjdns. В зависимостях cjdns есть пакет с чудным названием nacl. Он используется при сборке других пакетов, но при этом бинарный пакет из него не собирается. В то же время, он появляется и в зависимостях бинарного пакета cjdns. В результате, чтобы установить уже собраный пакет с cjdns, нужно перед єтим установить не существующий в собраном виде пакет nacl.
Теперь, как его обойти. Открываем ./openwrt/feeds/cjdns/cjdns/Makefile в текстовом редакторе, находим этот фрагмент:
define Package/cjdns
SECTION:=net
CATEGORY:=Network
SUBMENU:=Routing and Redirection
TITLE:=Experimental self configuring routing protocol.
DEPENDS:=+kmod-tun +kmod-ipv6 +libnl +nacl +libpthread
MAINTAINER:=cjd -- #cjdns on irc.efnet.org
endef
и убераем из «DEPENDS» "+nacl". Должно получится так:
define Package/cjdns
SECTION:=net
CATEGORY:=Network
SUBMENU:=Routing and Redirection
TITLE:=Experimental self configuring routing protocol.
DEPENDS:=+kmod-tun +kmod-ipv6 +libnl +libpthread
MAINTAINER:=cjd -- #cjdns on irc.efnet.org
endef
В menuconfig находим nacl (в разделе «Libraries») и устанавливаем в <M>
.
Далее собираем nacl отдельно:
make package/nacl/compile
Советую при сборке использовать не какой-то mate-terminal, а, к примеру tmux. Будет не очень приятно, если за время сборки, к примеру, упадут иксы.
Еще один нюанс. Чтобы после прошивки поднялась сеть, в прошивке должны быть конфиги настройки сети. Однако, для некоторых роутеров при сборке прошивки соответствующий конфиг не генерируется. В результате, роутер вроде-бы работает, но сеть не поднялась и мы получаем прекрасно работающий кирпич. Я, когда в первый раз собирал прошивку под свой tl-mr3220, столкнулся с этим и потом довольно долго искал нужный кабель и паял так называемый serial hack adapter, чтобы достучатся до железки.
Теперь о формате конфигов. В OpenWrt используется самопальный собственный формат конфигов UCI, общий для всего. Насколько я понял, они потом преобразуются в нормальные. Он, как мне кажется, достаточно хорошо документирован, так что останавливатся на нем не буду. Скажу только, что хранятся они в папке /etc/config/.
Чтобы добавить какие-то свои файлы, в том числе и конфиги, в прошивку, в папке с Buildroot нужно создать папку files и положить в нее нужные файлы. Например, тот же конфиг сети я положил в файл ./files/etc/config/network. Вот и сам конфиг для tl-mr3220 v1.2:
config interface 'loopback'
option ifname 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'
config interface 'lan'
option type 'bridge'
option proto 'static'
option netmask '255.255.255.0'
option _orig_ifname 'eth0 radio0.network1'
option _orig_bridge 'true'
option ifname 'eth0'
option ipaddr '192.168.5.1'
option gateway '192.168.5.2'
option broadcast '192.168.5.255'
option dns '192.168.5.2'
config switch
option name 'eth0'
option reset '1'
option enable_vlan '1'
config switch_vlan
option device 'eth0'
option vlan '1'
option ports '0 1 2 3 4'
Его я извлек из прошивки, взятой с сайта OpenWrt и немножко подправил. Что значат поля _orig_ifname и _orig_bridge не спрашивайте, сам не знаю. Отмечу, что этот конфиг предусматривает, что роутер торчит в одну и ту же сеть всеми своими портами, а не, например, каким-то одним в интернет.
Теперь вернемся к cjdns. Чтобы пакет таки собрался, нужно его отметить в menuconfig: «Network»->«Routing and Redirection»->«cjdns».
Итак, настал торжественный момент:
make
После сборки файлы должны оказатся в ./bin, рассортированые по target-ам (пока он у нас один). К примеру, у меня собраные образы лежат в ./bin/ar71xx, а пакеты в ./bin/ar71xx/packages/. Теперь открываем архив ./bin/ar71xx/openwrt-ar71xx-generic-rootfs.tar.gz (или аналогичный для вашего target) и проверяем, действительно ли там есть конфиг сети.
Теперь можно прошивать.
Как уже говорилось выше, openwrt-ar71xx-generic-tl-mr3220-v1-squashfs-factory.bin можно скормить вебморде заводской прошивки. Еще раз повторю уже стандартное предупреждение, встречаемое чуть ли не везде, где пишут о процесе прошивки: ни в коем случае не прошивайте по wi-fi!
Прошивка при помощи уже установленого OpenWrt.
Заходим по ssh, проверяем, сколько оперативной памяти свободно:
free
Файл с новой прошивкой должен будет лежать в tmpfs.
Далее правим файл /etc/sysupgrade.conf. В нем должны лежать имена файлов и папок, которые сохранятся при перепрошивке (путем занесения в jffs2). Комментарии выделяются символом #. При сохранении конфигов таким образом возможны разные казусы, так как их формат может поменятся.
Копируем в /tmp на роутере (туда примонтирован tmpfs):
scp ./bin/ar71xx/openwrt-ar71xx-generic-tl-mr3220-v1-squashfs-sysupgrade.bin root@192.168.5.1:/tmp
Проверяем целостность образа. На роутере считаем хеш файла образа:
cd /tmp
md5sum openwrt-ar71xx-generic-tl-mr3220-v1-squashfs-sysupgrade.bin
и сверяем с хешем файла на компьютере.
Скрещиваем пальцы и прошиваем:
sysupgrade -v /tmp/openwrt-ar71xx-generic-tl-mr3220-v1-squashfs-sysupgrade.bin
Если все прошло хорошо, роутер должен перезапустится. Заходим по ssh и с помощью passwd устанавливаем пароль root.
Существуют так же и другие способы прошивки, которые вариируются в зависимости от модели роутера. На части роутеров возможна прошивка с помощью загрузчика, есть и более хардкорные методы, предаологающие работу с паяльником.
Пакетный менеджер.
В OpenWrt в качестве пакетного менеджера используется opkg. Опции:
- update — Загрузить список пакетов в репозитории. Загружается он в /tmp/opkg-lists/snapshots, а в /tmp примонтирована tmpfs. Так что, после прерзагрузки для каких-либо действий с пакетами прийдется опять грузить список пакетов.
- upgrade — Начнем с того, что эта опция вам, скорей всего, не понадобится. Пакеты в репозиториях разработчиков меняются только в trunc. Если прописать другой репозиторий от другой версии, возможны казусы. Крайне не рекомендуется обновлять таким образом модули ядра (названия их пакетов начинаются на kmod-). Действия «обновить все под ряд» opkg не умеет вообще.
- install принимает название пакета, имя файла или url для скачивания:
opkg install hiawatha opkg install http://downloads.openwrt.org/snapshots/trunk/ar71xx/packages/hiawatha_7.7-2_ar71xx.ipk opkg install /tmp/hiawatha_7.7-2_ar71xx.ipk
- configure — Не совсем понятно, что делает. По видимому, еще раз выполняет конфигурационные скрипты пакета.
- remove — Удалить пакет.
- list — список пакетов.
- list-installed — список установленніх пакетов.
Полный список опций здесь: wiki.openwrt.org/doc/techref/opkg
Чтобы добавить репозиторий, в файл /etc/opkg.conf нужно добавить строку вида
src/gz <название репозитория> <url репозитория>
Пример:
src/gz attitude_adjustment http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages
Чтобы добавить репозиторий, находящийся в папке, нужно дописать
src/gz local file:////путь/к/папке
Отмечу, что подписывание пакетов, как в apt-get, не предусмотрено, как и забирание их по https. Насчет https, конечно, можно извернутся, но все упирается в неправильно подписаный сертификат на downloads.openwrt.org. Хотя, он не самоподписный, а значит, что, извернувшись вдвойне, может что-то получится.
Монтируем дополнителную память с флешки (если нужно).
На флешке должны быть соответствующие разделы. Для монтирования файловой системы лучше всего подойдет ext4. Итак, у нас есть размеченая флешка, которую мы втыкаем в порт на роутере. Проверяем, появились ли в /dev файлы раделов флешки. Если нет, доставляем нужные модули.
Далее, пытаемся монтировать:
mount /dev/sda1 /mnt
Если не получилось, опять же, ставим нужные пакеты. Далее
rm -rf /mnt/*
tar -C /overlay -cvf - . | tar -C /mnt -xf - # копируем содержимое overlay
Почему именно tar, а не по-нормальному? Должно быть, чтобы сохранить атрибуты файлов. Именно этот способ предлагается в wiki.openwrt.org/doc/howto/extroot#installation1.
Далее, отмонтирываем и правим /etc/config/fstab. В него дописываем или меняем соответствующую секцию на это:
config mount
option target /overlay
option device /dev/sda1
# option uuid <uuid>
option fstype ext4
option options rw,sync
option enabled 1
option enabled_fsck 0
Чтобы изменения вступили в силу, делаем
uci commit fstab
Можно так-же монтировать по uuid, чтобы не было казусов при подключении нескольких устройств по usb. Для этого нужно убрать параметр «device» и добавить «uuid» с, собственно, uuid раздела.
Подробнее о параметрах здесь: wiki.openwrt.org/doc/uci/fstab#mounting.filesystem
Монтируем swap.
Для этого нужно, чтобы в конфиге было нечто вроде этого:
config swap
option device /dev/sda2
# option uuid <uuid>
option enabled 1
Здесь все аналогично. По поводу выбора размера swap. Для linux на десктопах часто советуют делать swap немного больше, чем размер оперативной памяти, чтобы при переходе в «спящий режим» (или как там оно называется?) все, что есть в оперативной памяти, поместилось в swap. Согласитесь, для роутера «спящий режим» — это бред. Так что для них действует другое правило — выделяйте побольше. 512 MiB, думаю, хватит всегда и всем!
Просмотреть обьем оперативной памяти и swap можно с помощью команды free.
И не забываем про uci commit.
Cтавим cjdns (если он не поместился в squashfs).
Копируем пакет с помощью scp в /tmp на роутере и устанавливаем с помощью opkg. Далее создаем конфиг cjdns. На некоторых роутерах это может длится долго. Далее добавляем в конфиг ноды, раскомментирываем раздел ETHInterface и прописываем интерфейс br-lan вместо eth0.
Настраиваем wi-fi в режиме ad-hoc.
Открываем /etc/config/wireless и добамляем секцию вроде этой:
config wifi-iface
option device radio0
option mode adhoc
option ssid hype
option bssid 66:77:55:88:44:aa
option disabled 0
Опция «device» должна содержать название «устройства», обозначеного в секции «wifi-device». У меня она выглядит так:
config wifi-device 'radio0'
option type 'mac80211'
option macaddr 'ab:cd:ef:ab:cd:ef'
option hwmode '11ng'
option htmode 'HT40+'
list ht_capab 'SHORT-GI-40'
list ht_capab 'TX-STBC'
list ht_capab 'RX-STBC1'
list ht_capab 'DSSS_CCK-40'
option channel 'auto'
option txpower '18'
option country 'RU'
Тут есть один нюанс. Не все роутеры умеют поднимать несколько беспроводных сетей с одного физического устройства. Так что если после uci commit wireless; /etc/init.d/wireless restart одна из сетей не поднялась, то прийдется обойтись одной. Чтобы отключить одну из сетей, достаточно установить опцию disabled в 1.
Теперь проверяем, не попала ли новосозданная сеть в bridge с нашей локальной сетью. Сначала определяем, какому интерфейсу какая сеть соответствует:
iw dev
</code>
А потом проверяем мосты:
<source>
brctl show
Если наш ad-hoc таки слинковался с локальной сетью, идем править /etc/config/network. Ищем секцию interface с опцией «type» установленой в «bridge» вроде этой:
config interface 'lan'
option type 'bridge'
option proto 'static'
option netmask '255.255.255.0'
option _orig_ifname 'eth0, radio0.network1'
option _orig_bridge 'true'
option ifname 'eth0 wlan0'
option ipaddr '192.168.5.1'
option gateway '192.168.5.2'
option broadcast '192.168.5.255'
option dns '192.168.5.2'
Для этого случая нужно убрать из "_orig_ifname" «radio0.network1», а из «ifname» — «wlan0»
Теперь прописываем нужный интерфейс в конфиге cjdns. Секция ETHInterface, кстати, может выглядеть и так:
"ETHInterface":
[
{
"bind": "wlan0",
"beacon": 2,
},
{
"bind":"br-lan",
"beacon": 2
}
]
На десктопе такое работает, но на роутере, почему-то, с таким конфигом cjdroute падает. Так что, если у вас тоже это не работает, то прописываем что-то одно.
Создаем скрипт автозапуска.
Скрипты запуска должны лежать в папке /etc/init.d/. Создаем файл /etc/init.d/cjdns:
#!/bin/sh /etc/rc.common
START=93
STOP=51
start() {
cjdroute < /etc/cjdroute.conf
}
stop() {
killall cjdroute
}
$START и $STOP определяют последовательность запуска скриптов при старте и выключении роутера. «start()» — набор команд, выполняемый для запуска чего-либо. «stop()» — для остановки. Честно говоря, я слабо понимаю, чем может может помочь функционал запуска скриптов при выключении, если роутеры принято выключать, просто выдергивая из розетки, а соответствующей кнопки обычно не предусмотрено. Вообще-то, в последних версиях cjdns предусмотрена опция конфига «pidFile», но это изменение пока не в ветке «master», из которой он собирается под OpenWrt.
Теперь осталось сделать
chmod u+rwx /etc/init.d/cjdns
/etc/init.d/cjdns enable
Подробнее о стартовых скриптах в OpenWrt можно почитать здесь: wiki.openwrt.org/doc/techref/initscripts
Фух, вроде, все. Удачной прошивки, и да не прийдется вам после нее работать паяльником!
Автор: DinoAsm