Вве­де­ние

Сей­час все чаще у про­вай­де­ров можно встре­тить услугу «IPTV» - это циф­ро­вое теле­ви­де­ние. Тех­но­ло­гия, как пра­вило, харак­те­ри­зу­ется высо­ким каче­ством пере­да­ва­е­мого изоб­ра­же­ния и отлич­ным зву­ком. В этой ста­тье я рас­скажу о том, как, имея шлюз на основе «Gentoo GNU/Linux», полу­чить воз­мож­ность поль­зо­ваться услу­гой «IPTV» на всех ком­пью­те­рах локаль­ной сети.

Схема сети довольно про­стая. На входе стоит ADSL-модем, вклю­чен­ный в режиме бри­джа, за ним стоит шлюз на «Gentoo GNU/Linux», далее идет локаль­ная сеть с несколь­кими кли­ен­тами, кото­рые имеют доступ в интер­нет через «NAT».

Опре­де­лимся с име­нами сете­вых интер­фей­сов. Интер­фейс, к кото­рому под­клю­чем ADSL-модем, будет «eth0», а интер­фейс, смот­ря­щий в локаль­ную сеть - «eth1». Интер­фейсу ADSL-модема назна­чен «10.2.0.1» сете­вой адрес с мас­кой «255.255.255.0», соот­вет­ственно интер­фейсу «eth0» назна­чен сете­вой адрес «10.2.0.2» с такой же мас­кой. Локаль­ная сеть имеет диа­па­зон сете­вых адре­сов «192.168.0.0/24», а сете­вому интер­фейсу «eth1», смот­ря­щего в локаль­ную сеть, назна­чен «192.168.0.1» сете­вой адрес с мас­кой «255.255.255.0». В вашем слу­чае интер­фейсы и их сете­вые адреса могут отличаться.

Настройка ADSL-модема

Мой про­вай­дер предо­став­ляет доступ к услуге «IPTV» по отдель­ному соеди­не­нию, поэтому ADSL-модем дол­жен под­дер­жи­вать воз­мож­ность уста­нав­ли­вать несколько соеди­не­ний с обо­ру­до­ва­нием про­вай­дера с раз­лич­ными пара­мет­рами «VPI/VCI». В моем слу­чае про­вай­дер предо­став­ляет интер­нет по соеди­не­нию со сле­ду­ю­щими пара­мет­рами.
Интер­нетEncapsulation = RFC 1483
Multiplexing = LLC-based
VPI #= 1
VCI #= 32

А услуга «IPTV» предо­став­ля­ется по соеди­не­нию с такими пара­мет­рами.
IPTVEncapsulation = RFC 1483
Multiplexing = LLC-based
VPI #= 1
VCI #= 33

У вас все эти пара­метры могут быть совер­шенно другими.

Обя­за­тельно про­верьте в настрой­ках ADSL-модема вклю­чен ли multicast на его сете­вом интер­фейсе и его вер­сию. В моем слу­чае настройки сете­вого интер­фейса ADSL-модема выгля­дят так, как пока­зано ниже.
IP Address = 10.2.0.1
IP Subnet Mask = 255.255.255.0
Multicast = IGMP-v2

На этом настройку ADSL-модема можно счи­тать законченной.

На самом деле не имеет боль­шого зна­че­ния, какой тип под­клю­че­ния к про­вай­деру исполь­зу­ется. Самое глав­ное чтобы сете­вой интер­фейс шлюза, смот­ря­щий в сто­рону про­вай­дера, имел воз­мож­ность при­ни­мать multicast поток. В выводе команды «ifconfig» должно при­сут­ство­вать слово «MULTICAST».
# ifconfig eth0
eth0     Link encap:Ethernet  HWaddr 00:11:22:33:44:55
          inet addr:10.2.0.2  Bcast:10.2.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:17

С пара­мет­рами внеш­него сете­вого интер­фейса закон­чили. Идем далее.

Пара­метры ядра и настройка системы

На шлюзе в кон­фи­гу­ра­ции ядра дол­жен быть вклю­чен пара­метр «IP_MULTICAST».
# cat /usr/src/linux/.config|grep MULTICAST
CONFIG_IP_MULTICAST=y

Так же необ­хо­димо доба­вить роутинг для multicast паке­тов на внеш­нем сете­вом интер­фейсе «eth0». Это можно сде­лать сле­ду­ю­щей коман­дой.
# route add -net 224.0.0.0/4 dev eth0

Или доба­вить в файл «/etc/conf.d/net» сле­ду­ю­щую строку.
/etc/conf.d/netroutes_eth0="224.0.0.0/4"

После этого пере­за­пус­каем сете­вой интер­фейс «eth0» и смот­рим таб­лицу роутинга. Должно полу­чится при­мерно сле­ду­ю­щее.
# /etc/init.d/net.eth0 restart
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
195.5.5.201     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
10.2.0.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
127.0.0.0       127.0.0.1       255.0.0.0       UG    0      0        0 lo
224.0.0.0       0.0.0.0         240.0.0.0       U     4      0        0 eth0
0.0.0.0         195.5.5.201     0.0.0.0         UG    4009   0        0 ppp0

Исполь­зо­ва­ние «udpxy»

Самым про­стым, а ино­гда и един­ствен­ным, спо­со­бом вос­поль­зо­ваться услу­гой «IPTV» в локаль­ной сети будет орга­ни­за­ция на шлюзе спе­ци­аль­ного прокси-сервера, кото­рый при­ни­мает multicast поток, иду­щий по UDP-протоколу и посту­па­ю­щий на внеш­ний интер­фейс, под­клю­чен­ный к про­вай­деру, и отдает его по запросу со сто­роны ком­пью­тера локаль­ной сети уже по TCP-протоколу.

Таким прокси-сервером явля­ется про­грамма «udpxy», о настройке кото­рой и будет рас­ска­зано в этой главе.

Кратко рас­скажу, почему же спо­соб с исполь­зо­ва­нием «udpxy» может являться един­ственно воз­мож­ным. При транс­ля­ции multicast тра­фика в локаль­ную сеть все узлы сети начи­нают при­ни­мать этот поток дан­ных. Бес­про­вод­ные точки доступа, при­сут­ству­ю­щие в локаль­ной сети, так же начи­нают про­пус­кать через себя multicast тра­фик. Но они могут про­сто захлеб­нуться от нахлы­нув­ших дан­ных и пере­стают работать.

Так что рас­смат­ри­ва­е­мый спо­соб явля­ется наи­бо­лее про­стым и уни­вер­саль­ным для реа­ли­за­ции постав­лен­ной задачи.

Уста­нав­ли­ваем пакет «udpxy».
# emerge udpxy

Пакет «udpxy» все­гда можно найти в моем овер­лее.

После уста­новки пакета «udpxy» можно про­ве­рить работу услуги «IPTV», запи­сав неболь­шой медиа-файл. Напри­мер, если в списке кана­лов при­сут­ствует строка вида «udp://@232.0.2.47:3000», то работу «IPTV» можно про­ве­рить так.
# udpxrec -M 10Mb -T -v -c 232.0.2.47:3000 /tmp/test.mpg

При этом будет создан файл «/tmp/test.mpg» раз­ме­ром 10 мега­байт, содер­жа­щий неболь­шой фраг­мент теле­пе­ре­дачи, кото­рый можно про­смот­реть любым медиа-проигрывателем.

Настройка «udpxy» пре­дельно про­ста. В файле «/etc/conf.d/udpxy» про­сто задаем зна­че­ния пара­метра «UDPXYOPTS» при­мерно сле­ду­ю­щим обра­зом.
/etc/conf.d/udpxyUDPXYOPTS="-a eth1 -p 4022 -m eth0"

Где пара­метр «-a» - сете­вой интер­фейс локаль­ной сети, «-p» - порт для при­ема HTTP-запросов из локаль­ной сети, «-m» - внеш­ний сете­вой интер­фейс, на кото­рый посту­пает multicast поток со сто­роны про­вай­дера. Осталь­ные пара­метры запуска «udpxy» можно про­смот­реть в выводе команды «udpxy» без параметров.

Запус­каем «udpxy» и добав­ляем сер­вис «udpxy» в авто­за­пуск.
# /etc/init.d/udpxy start
# rc-update add udpxy default

Оста­лось только раз­ре­шить в пра­ви­лах фай­р­вола прием запро­сов на порту, задан­ного в пара­мет­рах опцией «-p», для локаль­ной сети и прием multicast потока на внеш­нем интерфейсе.

Для «iptables» все про­сто.
# iptables -A INPUT -i eth0 -d 224.0.0.0/240.0.0.0 -j ACCEPT
# iptables -A INPUT -i eth1 -p tcp --dport 4022 -j ACCEPT
# /etc/init.d/iptables save

Для тех, кто исполь­зует про­грамму «shorewall» для гене­ра­ции пра­вил «iptables», нужно доба­вить в файл «/etc/shorewall/rules» сле­ду­ю­щие строки.
/etc/shorewall/rulesACCEPT        modem         $FW:224.0.0.0/4
ACCEPT        loc           $FW                  tcp     4022

При этом файл «/etc/shorewall/interfaces» дол­жен выгля­деть при­мерно так.
/etc/shorewall/interfacesmodem   eth0            detect
ppp     ppp+            -
loc     eth1            detect

Обно­вим «shorewall».
# /etc/init.d/shorewall refresh

Оста­нется только немного изме­нить спи­сок кана­лов, предо­став­лен­ный вашим про­вай­де­ром. Напри­мер, строку вида «udp://@232.0.2.47:3000» надо заме­нить на «http://192.168.0.1:4022/udp/232.0.2.47:3000». Это можно сде­лать одной коман­дой, напри­мер так, как пока­зано ниже.
# sed -e 's/^udp:\/\/\@/http:\/\/192.168.0.1:4022\/udp\//' -i playlist.m3u

Откры­ваем полу­чен­ный спи­сок кана­лов в любом видео-проигрывателе, напри­мер в «VLC» или «Kaffeine», и наблю­даем результат.

Исполь­зо­ва­ние «igmpproxy»

Про­грамма «igmpproxy» пред­став­ляет собой про­грамм­ный роу­тер multicast трафика.

В кон­фи­гу­ра­ции ядра шлюза дол­жен быть вклю­чен пара­метр «IP_MROUTE».
# cat /usr/src/linux/.config|grep IP_MROUTE
CONFIG_IP_MROUTE=y

Уста­нав­ли­ваем пакет «igmpproxy».
emerge igmpproxy

Про­ве­рим, какие сете­вые интер­фейсы поз­во­ляют пере­да­вать multicast тра­фик. Немного позже это потре­бу­ется.
# cat /proc/net/dev_mcast
2    eth0            1     0     01005e000001
3    eth1            1     0     01005e000001
4    eth2            1     0     01005e000001

Редак­ти­руем файл «/etc/igmpproxy.conf».
/etc/igmpproxy.confphyint eth0 upstream  ratelimit 0  threshold 1
        altnet 10.0.0.0/8

phyint eth1 downstream  ratelimit 0  threshold 1

phyint eth2 disabled

В дан­ном при­мере multicast тра­фик посту­пает на внеш­ний сете­вой интер­фейс «eth0», к кото­рому под­клю­чем ADSL-модем, и пере­да­ется на сете­вой интер­фейс локаль­ной сети «eth1». На все осталь­ные сете­вые интер­фейсы пере­дача multicast тра­фика запре­щена. Это видно на при­мере сете­вого интер­фейса «eth2».

В файле кон­фи­гу­ра­ции «igmpproxy» необ­хо­димо опи­сать все сете­вые интер­фейсы, име­ю­щие воз­мож­ность пере­да­вать multicast трафик.

Запус­каем «igmpproxy» и добав­ляем его в авто­за­пуск.
# /etc/init.d/igmpproxy start
# rc-update add igmpproxy default

Оста­лось только настро­ить фай­р­вол.
Для «iptables».
# iptables -A INPUT -d 224.0.0.0/240.0.0.0 -j ACCEPT
# iptables -A INPUT -s 224.0.0.0/240.0.0.0 -j ACCEPT
# iptables -A FORWARD -d 224.0.0.0/240.0.0.0 -j ACCEPT
# iptables -A FORWARD -s 224.0.0.0/240.0.0.0 -j ACCEPT
# /etc/init.d/iptables save

Для поль­зо­ва­те­лей «shorewall» необ­хо­димо раз­ре­шить прием multicast тра­фика на всех направ­ле­ниях. Изме­ним файл «/etc/shorewall/rules» сле­ду­ю­щим обра­зом, если файл «/etc/shorewall/interfaces» выгля­дит так, как пока­зано в преды­ду­щей главе.
/etc/shorewall/rulesACCEPT        all           $FW:224.0.0.0/4
ACCEPT        all           modem:224.0.0.0/4
ACCEPT        all           loc:224.0.0.0/4

После этого обно­вим «shorewall».
# /etc/init.d/shorewall refresh

Оста­лось настро­ить кли­ент­ские ком­пью­теры в локаль­ной сети. На них нужно про­сто раз­ре­шить прием multicast трафика.

Для «iptables» будет так.
# iptables -A INPUT -s 224.0.0.0/240.0.0.0 -j ACCEPT
# /etc/init.d/iptables save

Для «shorewall» в файле «/etc/shorewall/rules» доба­вим сле­ду­ю­щую строку.
/etc/shorewall/rulesACCEPT        all           $FW:224.0.0.0/4

Обно­вим «shorewall».
# /etc/init.d/shorewall refresh

Теперь оста­лось открыть спи­сок кана­лов, предо­став­лен­ный про­вай­де­ром, в любом медиа-проигрывателе и про­ве­рить результат.

Про­хож­де­ние multicast тра­фика на шлюзе можно про­смот­реть сле­ду­ю­щей коман­дой.
# watch cat /proc/net/ip_mr_vif

Реше­ние воз­мож­ных проблем

Пер­вая про­блема может воз­ник­нуть с вер­сией IGMP-протокола. Может потре­бо­ваться при­ну­ди­тельно выста­вить вто­рую вер­сию на шлюзе и кли­ент­ском ком­пью­тере. Сде­лать это можно, выпол­нив сле­ду­ю­щую команду.
# echo 2 >/proc/sys/net/ipv4/conf/all/force_igmp_version

Или доба­вить в файл «/etc/sysctl.conf» сле­ду­ю­щую строку.
/etc/sysctl.confnet.ipv4.conf.all.force_igmp_version=2

И затем при­ме­нить изме­не­ния.
# sysctl -p

Дру­гая про­блема - это филь­тра­ция паке­тов, кото­рые не могут уйти через тот же интер­фейс что и при­шли. Про­верьте уста­нов­лен­ные зна­че­ния пара­метра «rp_filter» и, если он вклю­чен, то отклю­чите его.
# echo 0 >/proc/sys/net/ipv4/conf/default/rp_filter
# echo 0 >/proc/sys/net/ipv4/conf/all/rp_filter

Это же самое можно сде­лать, отре­дак­ти­ро­вав файл «/etc/sysctl.conf».
/etc/sysctl.confnet.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0

И при­ме­нив его сле­ду­ю­щей коман­дой.
# sysctl -p

Еще одной про­бле­мой может являться низ­кий «TTL» multicast паке­тов, при­хо­дя­щих от про­вай­дера. Для того, чтобы уве­ли­чить «TTL», нужно выпол­нить сле­ду­ю­щее.
# modprobe ipt_TTL
# iptables -t mangle -A PREROUTING -d 224.0.0.0/240.0.0.0 -j TTL --ttl-inc 1
# /etc/init.d/iptables save

Заклю­че­ние

Какой из двух пред­став­лен­ных спо­со­бов выбрать для орга­ни­за­ции веща­ния «IPTV» в локаль­ную сеть - каж­дый решает сам. Мне нра­вится пер­вый спо­соб с исполь­зо­ва­нием «udpxy», так как он решает про­блему с бес­про­вод­ными сег­мен­тами моей сети и проще в настройке. Хотя спо­соб с при­ме­не­нием «igmpproxy» - более пра­виль­ный, так как при про­смотре одного и того же канала несколь­кими кли­ен­тами в локаль­ной сети, нагрузка на сеть не уве­ли­чится, как в слу­чае с исполь­зо­ва­нием «udpxy».