Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер

Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер

Некоторые из нас не пользуются интернетом без VPN по тем или иным причинам: кому-то нужен выделенный IP, и проще и дешевле купить VPS с двумя IP, чем покупать адрес у провайдера, кто-то хочет получать доступ ко всем веб-сайтам, а не только разрешенным на территории РФ, третьим нужен IPv6, а провайдер его не предоставляет…
Чаще всего VPN-соединение устанавливают на самом устройстве, которое используется в определенный момент, что вполне оправданно, если у вас только один компьютер и один телефон, и вы их редко используете одновременно. Если же в вашей домашней сети множество устройств, или, например, есть такие, на которых VPN настроить нельзя, было бы удобнее поднимать туннель прямо на домашнем роутере, чтобы не задумываться о настройке каждого устройства по отдельности.

Если вы хоть раз устанавливали OpenVPN на свой маршрутизатор, вы, вероятно, были неприятно удивлены скоростью его работы. SoC’и даже дешевых роутеров без особых проблем пропускают через себя окологигабитный трафик, за счет выноса функций маршрутизации и NAT на отдельный чип, предназначенный исключительно для выполнения этой задачи, а основные процессоры таких роутеров довольно слабы, т.к. нагрузки на них практически никакой нет. Такой компромисс позволяет достигнуть высокой скорости работы роутера и заметно снизить цену готового устройства — маршрутизаторы с мощными процессорами стоят в несколько раз дороже, и позиционируются уже не только как коробка для раздачи интернета, но и в качестве NAS, торрентокачалки и домашней мультимедиа-системы.

Мой роутер, TP-Link TL-WDR4300, нельзя назвать новым — модель появилась в середине 2012 года, и обладает 560 МГц-процессором архитектуры MIPS32 74Kc, мощности которого хватает лишь на 20-23 Мб/с шифрованного трафика через OpenVPN, что по меркам скорости современного домашнего интернета совсем немного.
Как бы нам повысить скорость шифрованного туннеля? Мой роутер довольно функциональный, поддерживает 3×3 MIMO, да и вообще, хорошо работает, не хотелось бы его менять.
Так как сейчас принято делать 10-мегабайтные интернет-страницы, писать десктопные приложения на node.js и паковать их в 100-мегабайтный файл, наращивать вычислительные мощности вместо оптимизации, мы совершим нечто ужасное — переложим VPN-подключение на производительный одноплатный «компьютер» Orange Pi One, который установим в корпус роутера, не занимая существующие сетевые и USB-порты, всего за $9.99*!
* + доставка, + налоги, + на пиво, + MicroSD.

OpenVPN

Нельзя назвать процессор роутера совсем уж слабым — он способен шифровать и хешировать данные алгоритмом AES-128-CBC-SHA1 со скоростью 50 Мб/с, что заметно быстрее того, как работает OpenVPN, а современный поточный шифр CHACHA20 с хешем POLY1305 и вовсе развивает 130 мегабит в секунду! Почему же скорость VPN-туннеля такая невысокая? Все дело в переключении контекста между пространством пользователя и пространством ядра: OpenVPN шифрует трафик и общается с внешним миром в контексте пользователя, а в контексте ядра происходит сама маршрутизация. Операционной системе приходится постоянно переключаться то туда, то сюда, на каждый принятый или переданный пакет, а эта операция небыстрая. Данная проблема присуща всем VPN-приложениям, работающим через TUN/TAP-драйвер, и нельзя сказать, что проблема низкой скорости вызвана плохой оптимизацией OpenVPN (хотя, конечно, там есть места, которые нужно бы переделать). Ни один userspace VPN-клиент не выдает даже гигабита с отключенным шифрованием на моем ноутбуке, что уж говорить про системы со слабым процессором.

Orange Pi One

Одноплатник Orange Pi One от компании Xunlong — самое выгодное предложение по соотношению производительность/цена на данный момент. За $9.99* вы получаете добротный четырехядерный процессор ARM Cortex-A7, (стабильно) работающий на частоте 1008 МГц, и явно производительней соседей Raspberry Pi Zero и Next Thing C.H.I.P. по ценовой категории. На этом плюсы заканчиваются. Компания Xunlong уделяет софту своих плат ровно ноль внимания, и на момент запуска One в продажу не предоставляла даже файл конфигурации платы, не говоря уже о готовых образах. Allwinner — производитель SoC — тоже не особо трепетно относится к поддержке своего продукта. Их интересует только минимальная работоспособность в ОС Android 4.4.4, а значит, мы вынуждены использовать ядро версии 3.4 с Android-патчами. К счастью, есть энтузиасты, которые собирают дистрибутивы, правят ядро, пишут код для поддержки плат в mainline-ядре, т.е. фактически делают работу за производителя, заставляя это говно приемлемо работать. Для своих целей я выбрал дистрибутив Armbian, он часто и удобно обновляется (новые ядра устанавливаются прямо через пакетный менеджер, а не копированием файлов на специальный раздел, как это обычно бывает у Allwinner), да и поддерживает большинство периферии, в отличие от остальных.

Роутер

Для того, чтобы не загружать слабый процессор роутера шифрованием и ускорить наше VPN-соединение, мы можем переложить эту задачу на плечи более производительного процессора Orange Pi, подключив его к роутеру каким-либо образом. На ум приходит подключение либо по Ethernet, либо по USB — оба этих стандарта поддерживаются обоими устройствами, но не хотелось занимать уже существующие порты. К счастью, выход есть.

Микросхема USB-хаба GL850G, которая используется в роутере, поддерживает работу 4 USB-портов, два из которых не распаяны. Неясно, почему производитель не стал их распаивать, предполагаю, чтобы не дать возможность пользователям подключить сразу 4 устройства с высоким потреблением тока (например, жестких дисков), т.к. штатный блок питания роутера не рассчитан на такую нагрузку. В любом случае, это нам на руку.
Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер
Для того, чтобы получить еще один USB-порт, достаточно допаять два провода к 8(D-) и 9(D+) или 11(D-) и 12(D+) пинам.

Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер

Однако недостаточно просто так подключить два USB-устройства и надеяться, что все заработает само собой, как это бы произошло с Ethernet. Во-первых, нам нужно заставить одного из них работать в режиме USB Client, а не USB Host, во-вторых, нам нужно определиться с тем, как устройства будут определять друг друга. Существует множество драйверов так называемых USB Gadgets (по названию подсистемы Linux-ядра), которые позволяют эмулировать различные типы USB-устройств: сетевой адаптер, аудиокарту, клавиатуру и мышь, флешку, фотоаппарат, консоль через последовательный порт. Так как наше устройство будет работать с сетью, нам лучше всего подойдет эмуляция Ethernet-адаптера.

Существует три стандарта Ethernet-over-USB:

  • Remote NDIS (RNDIS). Устаревший стандарт от Microsoft, использовался преимущественно во времена Windows XP.
  • Ethernet Control Model (ECM). Простой стандарт, который инкапсулирует Ethernet-фреймы в USB-пакеты. Отлично подходит для проводных модемов с USB-подключением, где удобно передавать кадры без обработки, но из-за своей простоты и ограничений USB-шины работает не слишком быстро.
  • Ethernet Emulation Model (EEM). Более умный протокол, который учитывает ограничения USB и оптимально агрегирует несколько фреймов в один, повышая таким образом пропускную способность.
  • Network Control Model (NCM). Самый новый протокол. Обладает преимуществами EEM и еще больше оптимизирует работу с шиной.

Чтобы заставить работать любой из этих протоколов на нашей плате, как всегда, придется встретиться с некоторыми трудностями. Из-за того, что Allwinner интересуют только Android-части ядра, нормально работает только Android Gadget — тот код, который реализует связь с adb, экспорт устройства по протоколу MTP и эмуляцию флешки на Android-устройствах. Сам Android Gadget поддерживает и протокол RNDIS, но в ядре Allwinner он сломан. Если вы попробуете скомпилировать ядро с любым другим USB Gadget, устройство просто не появится в системе, что бы вы ни делали.
Для решения проблемы, по-хорошему, необходимо найти место инициализации USB-контроллера в модифицированном разработчиками коде Android-гаджета android.c, но существует и обходной маневр, чтобы заставить работать, как минимум, эмуляцию Ethernet через USB:

--- sun8i/drivers/usb/sunxi_usb/udc/sunxi_udc.c 2016-04-16 15:01:40.427088792 +0300
+++ sun8i/drivers/usb/sunxi_usb/udc/sunxi_udc.c 2016-04-16 15:01:45.339088792 +0300
@@ -57,7 +57,7 @@
 static sunxi_udc_io_t g_sunxi_udc_io;
 static u32 usb_connect = 0;
 static u32 is_controller_alive = 0;
-static u8 is_udc_enable = 0;   /* is udc enable by gadget? */
+static u8 is_udc_enable = 1;   /* is udc enable by gadget? */
 
 #ifdef CONFIG_USB_SUNXI_USB0_OTG
 static struct platform_device *g_udc_pdev = NULL;

Этот патч насильно включает режим USB-клиента, что позволяет использовать обычные USB Gadgets из Linux.
Теперь следует пересобрать ядро с этим патчем и необходимым гаджетом. Я выбрал EEM, т.к. по результатам тестов он оказался производительней NCM.
Команда Armbian предоставляет очень простую и удобную сборочную систему для всех поддерживаемых плат в дистрибутиве. Достаточно скачать ее, положить наш патч в userpatches/kernel/sun8i-default/otg.patch, немного отредактировать compile.sh и выбрать необходимый gadget:

Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер

Ядро соберется в deb-пакет, который не составит труда установить на плату через dpkg.
Остается только подключить плату по USB и настроить наш новый сетевой адаптер на получение адреса через DHCP. Для этого необходимо добавить примерно следующее в /etc/network/interfaces:

auto usb0
        iface usb0 inet dhcp
        hwaddress ether c2:46:98:49:3e:9d
        pre-up /bin/sh -c 'echo 2 > /sys/bus/platform/devices/sunxi_usb_udc/otg_role'

MAC-адрес лучше задать вручную, т.к. он будет случайным при каждой перезагрузке устройства, что неудобно и хлопотно.
Подключаем MicroUSB-кабель к OTG-разъему, подключаем питание с роутера (его можно подавать на 2 и 3 пины гребенки, а не только на разъем питания).

Осталось настроить роутер. Достаточно установить пакет с EEM-драйвером и добавить наше новое сетевое USB-устройство в бридж локальной firewall-зоны:

opkg install kmod-usb-net-cdc-eem

Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер
Чтобы маршрутизировать весь трафик в VPN-туннель, нужно либо добавить SNAT-правило на IP-адрес платы на стороне роутера, либо раздавать в качестве адреса шлюза адрес платы через dnsmasq. Последнее делается добавлением следующей строки в /etc/dnsmasq.conf:

dhcp-option = tag:lan, option:router, 192.168.1.100

где 192.168.1.100 — IP-адрес вашей платы. Не забудьте прописать адрес машрутизатора в настройках сети на самой плате!

Для изоляции контактов платы от контактов роутера использовалась меламиновая губка. Получилось как-то так:
Ускоряем OpenVPN за $9.99* или встраиваем Orange Pi One в роутер

Заключение

Работает сеть через USB на удивление быстро: 100-120 Мб/с, я ожидал меньшего. OpenVPN пропускает через себя около 70 Мб/с шифрованного трафика, что тоже не сильно много, но для моих нужд хватает. Крышка маршрутизатора закрывается неплотно, оставляя небольшой зазор. Эстеты могут выпаять Ethernet и USB Host-разъемы у платы, что позволит крышке закрыться полностью, и еще место останется.
А лучше не заниматься такой порнографией и купить Turris Omnia.

Источник: habr.com