воскресенье, 14 июля 2013 г.

Pulseaudio, twitch and broadcasting

Как-то ради интереса решил постримить то, как я играю в WoT на http://www.twitch.tv/skogut. Первой проблемой было запилить, собственно, захват видео. Я нашел скриптик, и он, в общем-то работает. Но я немного его подправил под реалии wine + World Of Tanks и свои 4 ядра:
 #! /bin/bash  
 # originaly from http://tinyurl.com/twitch-linux from taladan  
 # www.youtube.com/user/taladan  
 # gist created by brodul  
 INRES=`xwininfo -name "WoT Client" | awk '/geometry/ {print $2}' | sed -e 's/\+.*//g'`  
 #INRES="1280x800" # input resolution  
 #OUTRES="1280x720" # Output resolution  
 OUTRES="640x380" # Output resolution  
 #OUTRES="$INRES" # Output resolution  
 FPS="18" # target FPS  
 QUAL="fast" # one of the many FFMPEG preset on (k)ubuntu found in /usr/share/ffmpeg  
 # If you have low bandwidth, put the qual preset on 'fast' (upload bandwidth)  
 # If you have medium bandwitch put it on normal to medium  
 CORNER=`xwininfo -name "WoT Client" | awk '/Corners/ {print $2}' | sed -re 's/\+(.*)\+(.*)/+\1,\2/'`  
 echo "INRES: $INRES CORNER: $CORNER"  
 # Write your key in a file named .twitch_key in your home directory  
 STREAM_KEY=$(cat ~/.twitch_key) # This is your streamkey generated by jtv/twitch found at: http://www.justin.tv/broadcast/adv_other  
 URL="rtmp://live-ams.twitch.tv/app/"   
 #BITRATE=2048000   
 BITRATE=1024000   
 nice taskset -c 1,2,3 avconv \  
 -f x11grab -s $INRES -r "$FPS" -i :0.0"$CORNER" \  
 -f alsa -ac 2 -i pulse \  
 -vcodec libx264 -s $OUTRES -preset $QUAL \  
 -acodec libmp3lame -ar 44100 -threads 3 -qscale 3 -b $BITRATE -bufsize 512k \  
 -f flv "${URL}${STREAM_KEY}"  

Основное изменение - это поиск окна WoT и определение его местоположения на экране.

С этим все ясно. Следующей проблемой было сделать так, чтобы можно было и говорить в микрофон и зрители стрима могли это слышать. После гугления был обнаружен хинт про module-loopback в pulse. Так я и сделал :)

 pactl load-module module-loopback latency_msec=1 sink=alsa_output.usb-Logitech_Logitech_G930_Headset-00-Headset.analog-stereo  

Однако, с таким подходом, я слышу и себя, что делает для моего мозга ужасную обратную связь, которая мешает нормально говорить.
После вдумчивого чтения документации по модулям pulseaudio, меня осенило.
В pulse есть модуль null-sink, который ничего никуда не выводит. Так вот, достаточно его загрузить, выбрать как устройство, с которого будет идти запись в стрим (через pavucontrol, например).
Далее загружаем аж два module-loopback:

 pactl load-module module-loopback latency_msec=1 sink=null  
 pactl load-module module-loopback latency_msec=1 sink=null  

После чего в том же pavucontrol источником звука для этих (для этого надо включить отображение Virtual streams в Recording) мы выбираем 1) Monitor o НашаЗвуковаяПлата для захвата звука из приложения (в данном случае World Of Tanks и любые другие звуки), для второго loopback мы выбираем, собственно, саму звуковую плату (для захвата микрофона). И вуаля - мы слышим звук из игры, мы не слышим себя, зато зритель слышит всё!

Следующим шагом, видимо, будет запиливание автоматического выбора источников звука для loopback с помощью pactl, чтобы не нужно было ничего делать руками в pavucontrol, но я так спешил поделиться радостью, что пока не сделал этого.

воскресенье, 2 июня 2013 г.

Как же подгружать правила iptables через Network Manager?

Network Manager - пожалуй, самая ненавистная всеми вещь, которую я, несмотря на общественное мнение, с удовольствием использую.

Так вот, в ней есть замечательная вещь - в ответ на разные события, связанные с интерфейсами, он способен запускать скрипты, которые лежат в /etc/NetworkManage/dispatcher.d, и это можно использовать, в том числе, для подгрузки правил iptables. Самое главное, чтобы скрипт был 1) обычным файлом; 2) владельцем был root; 3) не был доступен на запись кому-то еще; 4) не был suid; 5) разрешен для исполнения владельцем (короче, права должны быть не более разрешающими, чем 755).
Все подробности о том, как этот скрипт исполняется и какие параметры получит, можно выгрести в man NetworkManager(8). Единственная печаль - он не получает никакого имени профиля настроек для интерфейса, а только его имя.
Но уже имея это, можно сунуть пару простых скриптов для настройки IPv4 или IPv6 фильтров (просто сменив iptables на ip6tables):

1:  if [ -x /usr/bin/logger ]; then  
2:      LOGGER="/usr/bin/logger -s -p daemon.info -t FirewallHandler"  
3:  else  
4:      LOGGER=echo  
5:  fi  
6:  case "$2" in  
7:      up)  
8:          if [ ! -r /etc/iptables.rules ]; then  
9:              ${LOGGER} "No iptables rules exist to restore."  
10:              return  
11:          fi  
12:          if [ ! -x /sbin/iptables-restore ]; then  
13:              ${LOGGER} "No program exists to restore iptables rules."  
14:              return  
15:          fi  
16:          ${LOGGER} "Restoring iptables rules"  
17:          /sbin/iptables-restore -c < /etc/iptables.rules  
18:          ;;  
19:      down)  
20:          if [ ! -x /sbin/iptables-save ]; then  
21:              ${LOGGER} "No program exists to save iptables rules."  
22:              return  
23:          fi  
24:          ${LOGGER} "Saving iptables rules."  
25:          /sbin/iptables-save -c > /etc/iptables.rules  
26:          ;;  
27:      *)  
28:          ;;  
29:  esac  
Скрипт нужно назвать, например, /etc/NetworkManager/dispatcher.d/01firewall и обязательно установить разрешения 0755.

UFW - Ubuntu firewall - такая нужная вещь? :)

Была как-то давно мысль посмотреть на все эти фронтенды к iptables, написанные для "упрощения жизни". Да, возможно, не все могут понимать синтаксис правил iptables, всю его гибкость и мощь, так что им нужно пользоваться чем-то более простым. Итак, сейчас речь пойдет про ufw - Ubuntu-фронтенд к iptables.
Наверное, использовать именно его - самый простой способ "защититься". Включается он просто -

$ sudo ufw enable


По-умолчанию он запрещает весь входящий траффик и разрешает исходящий:

$ ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing)
New profiles: skip

Теперь посмотрим, что же стоит за всем этим...

На самом деле ufw создает примерно полтора десятка разных цепочек iptables, рассовывая по ним кучу разных правил, так что разобраться, что же сломалось после его применения будет в разы сложнее:

# iptables -L -v -n
Chain INPUT (policy DROP 2 packets, 64 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  344 31500 ufw-before-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  344 31500 ufw-before-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
   23  2608 ufw-after-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    5   160 ufw-after-logging-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    5   160 ufw-reject-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    5   160 ufw-track-input  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ufw-before-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ufw-before-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ufw-after-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ufw-after-logging-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    0     0 ufw-reject-forward  all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  254 23653 ufw-before-logging-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
  254 23653 ufw-before-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
   56  3591 ufw-after-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
   56  3591 ufw-after-logging-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
   56  3591 ufw-reject-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
   56  3591 ufw-track-output  all  --  *      *       0.0.0.0/0            0.0.0.0/0          

Что радует (или огорчает) - он по-умолчанию сразу разрешает DHCP запросы, так что хотя-бы DHCP-клиент у вас ломаться не должен. Одновременно с этим он разрешает и сервис avahi. Все остальное нужно разрешать самим. Кроме того, он настраивает логирование заблокированных пакетов, так что в dmesg или syslog они будут.

Как же после этого разрешать что-либо?

$ sudo ufw allow 22/tcp

Просто разрешить ssh. Или только себе, скажем:
 
$ ufw allow from 172.20.1.4 to any port 22 proto tcp

На этом моменте начинает казаться, что ufw писали фанатики синтаксиса ipfw. :)

Дальше - хуже. Удобства от ufw кончаются, как только вам нужно что-то более сложное, например, nat. Тут вам придется таки учить синтаксис iptables:

/etc/ufw/before.rules:
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE
COMMIT

Такие вот дела, может кому-нибудь и нужен такой малофункциональный фронтенд к пакетному фильтру. У него есть одно достоинство - он загружает и сохраняет правила, что обычно является проблемой. А если кто не хочет и хочет что-то посложнее, в следующей заметке я расскажу, как ноутбучным и десктопным пользователям к NetworkManager прикрутить загрузку правил iptables.

воскресенье, 3 февраля 2013 г.

Centos 6, как удалить старые ядра или немного про малоизвестные способности yum

Как и вы, наверное, буквально сегодня обнаружил, что после установки обновлений в, например, CentOS 6, в меню загрузчика появляются все новые и новые ядра, такие ненужные в большинстве случаев. И сразу стало интересно, почему так, как бы их поудобнее удалить, и как вообще сделать, чтобы там их не было.

Конечно, это легко найти в Google, но ведь мало просто решить проблему, интересно разобраться во всем этом :)

Так вот, некоторые пакетики при апдейтах могут поддерживать фичу "installonly", то есть пакет не удаляется, не заменяется, а просто устанавливается. Очевидно, при этом критически важные файлы такого пакета ни с чем конфликтовать не должны. По-умолчанию yum считает такими пакетами все, что может содержать ядра, и по-умолчанию в CentOS настроено сохранять 5 последних версий ядра.
Очевидно, связано это с потенциальными проблемами с новым ядром и необходимостью сохранять старые версии. Однако, в большинстве случаев, когда обновления делаются руками и потом делается перезагрузка, умолчательные 5 последних версий как-то слишком уж избыточно (а для случаев ежедневных апдейтов без перезагрузки - как-то слишком уж мало, ведь ядро, скажем, за год, может обновиться раз 10, последнее загруженное ядро уже давно затрется).
В таком случае идем в /etc/yum.conf и правим там installonly_limit на какое-то другое число, после чего будет заметен позитивный эффект на число одновременно установленных версий ядра.
Однако, иногда просто хочется удалить лишние ядра, ничего не меняя. Для этого в пакете yum-utils (yum install yum-utils) есть нехитрая утилита package-cleanup:
# package-cleanup --oldkernels --count=2

И останутся только 2 последних ядра.


После всего этого всем интересующимся рекомендуется почитать man 5 yum.conf, где есть множество интересных и [бес]полезных опций, например, ограничение используемой пропускной способности сети, сохранение пакетов на локальном диске после установки и т.п. Ну и ознакомиться с пакетом yum-utils поближе.