Установка 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.
Все дальнейшие команды выполняем на сервере:
- Устанавливаем 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
