Установка udpxy в контейнере LXC для просмотра IPTV

Обычно для просмотра IPTV каналов дома выделяют отдельный порт на роутере, в который подключают IPTV приставку или SmartTV. Второй вариант — пропустить весь IPTV мультикаст в локальную сеть. Но тогда могут возникнуть проблемы с WiFi из-за огромного количества мелких UDP пакетов. Причём эти пакеты будут передаваться на ВСЕ устройства в сети при просмотре IPTV хотя бы на одном из них.

Решение существует уже давно: использовать IPTV прокси. Для этого существует программа udpxy. Она преобразует UDP мультикаст трафик в TCP юникаст, направляя его только на то устройство, на котором идёт просмотр канала. При этом появляется возможность просмотра каналов на любом устройстве в сети: ТВ, компьютере, смартфоне и т.д., даже если они изначально не могли принимать IPTV.

Один из способов использования я уже описывал в предыдущей статье Mikrotik + IPTV через Udpxy. Вариант с микротиком неплох, но на FullHD каналах процессор роутера загружается на 70-80% и при более-менее активной сетевой деятельности нагрузка поднимается до 100% и трансляция прерывается. Здесь же я опишу процесс установки udpxy в LXC контейнер на домашнем сервере.

LXC (англ. Linux Containers) — система виртуализации на уровне операционной системы для запуска нескольких изолированных экземпляров операционной системы Linux на одном узле. LXC не использует виртуальные машины, а создаёт виртуальное окружение с собственным пространством процессов и сетевым стеком. Все экземпляры LXC используют один экземпляр ядра операционной системы.

Википедия

Изначальная конфигурация сети:

Все клиенты находятся в одной подсети 192.168.1.0/24. Сервер имеет два сетевых интерфейса, один из которых (eno1) подключен в локальную сеть. Второй — не подключен. Сервер работает под управлением Ubuntu Server 18.04 LTS.

Все дальнейшие команды выполняем на сервере:

  1. Устанавливаем LXC:
sudo apt-get install lxc

2. У меня не заладилось с настройками netplan, поэтому вернёмся к старому доброму формату файла interfaces. Для этого выполняем следующие команды:

sudo apt-get install ifupdown bridge-utils
sudo systemctl stop networkd-dispatcher
sudo systemctl disable networkd-dispatcher
sudo systemctl mask networkd-dispatcher
sudo apt-get purge nplan netplan.io

Файл /etc/network/interfaces приводим к следующему виду:

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eno1
iface eno1 inet manual

auto br0
iface br0 inet static
        address 192.168.1.2
        network 192.168.1.0
        netmask 255.255.255.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        bridge_ports eno1
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0

Если моста br0 нет, то необходимо его создать командой:

sudo brctl addbr br0

Файл resolv.conf:

nameserver 192.168.1.1

Перезагружаемся и проверяем, что Интернет на сервере доступен, и всё работает.

3. Чтобы на внешнем сетевом интерфейсе не висело вообще никаких IP адресов, отключаем IPv6. Для этого в файл /etc/sysctl.d/99-sysctl.conf добавляем строки:

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

И применяем настройки:

sudo sysctl -p

4. Создаём новый LXC контейнер:

sudo lxc-create -n iptv -t ubuntu

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

sudo lxc-create -t download -n iptv

При этом будет выведен большой список всех доступных шаблонов, из которых можно будет выбрать необходимый.

Редактируем конфигурацию контейнера /var/lib/lxc/iptv/config , а конкретно строки касающиеся сети. MAC-адрес можно оставить тот, который будет в вашем файле конфигурации:

# тип сети виртуальной машины
lxc.net.0.type = veth
# обозначение сетевого интерфейса в контейнере
lxc.net.0.name = eth0
# его "пара" в хост-машине
lxc.net.0.veth.pair = veth-01
# интерфейс для связи с внешним миром
lxc.net.0.link = br0
# шлюз
lxc.net.0.ipv4.gateway = 192.168.1.1
# MAC адрес виртуалки
lxc.net.0.hwaddr = 00:16:3e:01:02:03
# IP и именно в таком виде для создания корректной маски
lxc.net.0.ipv4.address = 192.168.1.3/24
# включаем контейнеру сеть
lxc.net.0.flags = up

5. Запускаем контейнер и подключаемся к нему:

sudo lxc-start -n iptv
sudo lxc-attach -n iptv

Теперь мы находимся «внутри» контейнера, точнее в его консоли. Проверяем доступность Интернета и ставим необходимые пакеты. По-умолчанию в консоли контейнера мы окажемся под рутом, поэтому sudo не указываю:

apt-get update
apt-get install mc
apt-get install sudo inetutils-ping psmisc wget net-tools
apt-get install iptables
apt-get install build-essential

mc только для удобства, можно не ставить. iptables — для блокировки лишних соединений. build-essential понадобится для сборки пакета udpxy из исходников.

6. В контейнере тоже отключаем IPv6, для этого повторяем в нём действия пункта 3.

7. Ставим udpxy. Для этого скачаем исходники, распакуем и откомпилируем:

cd /tmp
wget https://19dx.ru/downloads/udpxy/udpxy-src.tar.gz
tar -xzvf ./udpxy-src.tar.gz
cd udpxy-1*
make
make install

8. Выходим из контейнера и завершаем его работу:

exit
sudo lxc-stop -n iptv

Добавляем в конфигурацию контейнера ещё один интерфейс (eth1). Он будет напрямую связан со свободным физическим интерфейсом сервера (eno2) и подключен к сети провайдера:

lxc.net.1.type=phys
lxc.net.1.link=eno2
lxc.net.1.name=eth1
lxc.net.1.hwaddr = bc:76:4e:01:02:03
lxc.net.1.flags = up

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

lxc.start.auto=1
lxc.start.delay=15
lxc.start.order=50

Также, закомментируем строку шлюза, так как интернет в контейнере нам больше не нужен:

#lxc.net.0.ipv4.gateway = 192.168.1.1

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

9. Соединяем Ethernet кабелем интерфейс eno2 сервера и свободный порт на микротике.

В настройках микротика соединяем этот порт и WAN порт в один мост:

В настройках моста включаем IGMP Snooping:

P.S. Рекомендую проверить стабильность работы с этой галочкой и без неё. После всех настроек запустите скачивание большого файла или спидтест и посмотрите, не будет ли зависаний картинки.

Получили следующую конфигурацию сети:

Отсутствие IP адреса на интерфейсе eno2 — это не ошибка. Он не требуется для работы IPTV.

10. Снова запускаем контейнер и подключемся к нему:

sudo lxc-start -n iptv
sudo lxc-attach -n iptv

Пробуем запустить udpxy:

udpxy -a eth0 -p 1234 -S -B 2048K -c 10

Теперь введём в браузере следующий URL и убедимся, что видим страницу статистики udpxy:

http://192.168.1.3:1234/status

Уже хорошо. Но для работы IPTV пока недостаточно. Нужно добавить маршруты:

route add -net 235.19.101.0 netmask 255.255.255.0 dev eth1
route add -net 239.0.0.0 netmask 255.0.0.0 dev eth1
route add -net 225.0.0.0 netmask 255.0.0.0 dev eth1
route add default dev eth1

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

Теперь необходимо изменить плейлист. Все ссылки вида udp://@x.x.x.x:1234 заменить на http://192.168.1.3:1234/udp/x.x.x.x:1234 . Это легко делается с помощью поиска и замены в любом текстовом редакторе.

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

Всё отлично! Осталось только сделать так, чтобы маршруты и udpxy стартовали автоматически. Создаём файлик:

vi /etc/iptvstart.sh

Со следующим содержимым:

#!/bin/sh
iptables -F INPUT 
iptables -F FORWARD
iptables -F OUTPUT 
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT 
iptables -P FORWARD DROP
iptables -A INPUT -p tcp -i eth0 --dport 1234 -j ACCEPT
iptables -A INPUT -p udp -i eth0 --dport 1234 -j ACCEPT
iptables -A INPUT -p udp -i eth1 --dport 1234 -j ACCEPT
iptables -A INPUT -p igmp -i eth1 -j ACCEPT

route add -net 235.19.101.0 netmask 255.255.255.0 dev eth1
route add -net 239.0.0.0 netmask 255.0.0.0 dev eth1
route add -net 225.0.0.0 netmask 255.0.0.0 dev eth1
route add default dev eth1
udpxy -a eth0 -p 1234 -S -B 2048K -c 10

Здесь кроме команд маршрутов и запуска udpxy я добавил настройки iptables для блокировки всего ненужного трафика.

Редактируем файл автозагрузки /etc/rc.local . Добавим в него строку:

/etc/iptvstart.sh &

Осталось сделать файл исполняемым:

chmod +x /etc/iptvstart.sh
Предупреждение!
Автор не несёт ответственности за возможную порчу оборудования. Всё, что вы делаете — вы делаете на свой страх и риск!