воскресенье, 15 апреля 2018 г.

Локальный просмотр роликов с Youtube: утилиты cclive, mpv, rename

Иногда я скачиваю файлы с Youtube, чтобы смотреть их на телевизоре. Иногда это бывают сериалы. В таких случаях мне пригождается несколько утилит: cclive, mpv и rename. Рассмотрим их использование на примере мультсериала Гравити Фоллз.

cclive

cclive - это утилита командной строки, при помощи которой можно скачать ролик с Youtube. Утилита есть в репозиториях Debian, поэтому установить её очень легко. Для этого нужно установить одноимённый пакет:
# apt-get install cclive
Использование очень простое - надо вызвать эту программу, указав ей в качестве аргумента ссылку на страницу Youtube с роликом. Стоит заключить ссылку в одиночные кавычки, чтобы знаки амперсанда и вопроса не интерпретировались оболочкой:
$ cclive 'https://www.youtube.com/watch?v=uKjjDctxD6w&list=PLVtYY3Ujl33NFDWuw_E-OJcngyWayn7pA'
После скачивания в текущем каталоге появится файл с именем "Гравити Фолз Зомбикараоке Серия 1 Сезон 2.webm".

mpv

Мой медиаплеер WD TV Play, про который я ранее уже писал в заметке Настройка MiniDLNA для цифрового мультимедийного плеера WD TV Play и при помощи которого я смотрю видео на телевизоре, имеет ограниченную поддержку видеоформатов и кодеков. В частности, он не умеет воспроизводить видео в контейнере WebM, не поддерживает кодеки VP8 и Vorbis. Чтобы просматривать такие ролики на этом плеере, их нужно перекодировать. Пожалуй самым широко распространённым сочетанием контейнеров и кодеков, которое поддерживается большинством видеоплееров, являются контейнер AVI и кодеки MPEG4 и MP3.

Ранее в целях перекодирования видео я пользовался утилитой mencoder, которая разрабатывалась вместе с видеоплеером mplayer. Одно из достоинств этой утилиты заключалось в том, что она поддерживала двухпроходное кодирование, что позволяло достичь наилучшего качества при необходимости уместить результат в файл определённого размера. Это было очень полезно для перекодирования DVD-дисков в 700-мегабайтные AVI-файлы, которые умещались на компакт-диск. В репозиториях Debian Jessie пакет mencoder отсутствовал, поэтому тогда я подыскал замену для mencoder'а - утилиту mpv, которая совмещает в себе как функции видеоплеера, так и функции перекодировщика.

Установим mpv при помощи команды:
# apt-get install mpv
Теперь внесём ряд правок в файл /etc/mpv/encoding-profiles.conf с настройками профилей перекодирования.

Во-первых, я задал битрейт 128 килобит/с, частоту дискретизации 22 килогерца - для фильмов этого, как правило, бывает достаточно и 16-битные целочисленные отсчёты со знаком:
[enc-a-mp3]
profile-desc = "MP3 (LAME)"
oac = libmp3lame
oacopts = b=128k
audio-samplerate = 22050
audio-format = s16
Во-вторых, задал изменение соотношения сторон видео. Для телевизоров с электронно-лучевой трубкой не имеет особого смысла делать ширину видео более 720 пикселей, т.к. физическое разрешение электронно-лучевой трубки такого телевизора составляет 768x576 пикселей. На деле размер видимой области может оказаться и того меньше - 640x480 пикселей. В настройках укажем, что ширина видео должна равняться 720 пикселям, а высота должна рассчитываться исходя из отображаемого на экране соотношения сторон. Бывает что видео имеет не квадратный пиксель и при отображении дополнительно растягивается, чтобы убрать искажения. Опция предписывает использовать именно отображаемое соотношение сторон, чтобы при воспроизведении видео не нужно было масштабировать с разными коэффициентами по разным осям.
[enc-v-mpeg4]
profile-desc = "MPEG-4 Part 2 (FFmpeg)"
ovc = mpeg4
ovcopts = qscale=4
vf = scale=720:-2
В-третьих, оба профиля объединяются в один общий:
[enc-f-avi]
profile-desc = "MPEG-4 + MP3 (for AVI)"
of = avi
ocopyts = no
oautofps = yes
profile = enc-v-mpeg4
profile = enc-a-mp3
ofopts-clr = yes
Перекодировать видео с использованием этого профиля можно при помощи такой команды:
$ mpv --profile=enc-f-avi "Гравити Фолз Зомбикараоке Серия 1 Сезон 2.webm" -o "Гравити Фолз Зомбикараоке Серия 1 Сезон 2.avi"
Для последовательного перекодирования всех файлов с расширением webm в текущем каталоге можно воспользоваться таким однострочным скриптом:
$ ls *.webm | while read webm ; do avi=`echo "$webm" | sed 's/\.webm$/\.avi/g'` ; mpv --profile=enc-f-avi "$webm" -o "$avi" ; done

rename

rename - это утилита командной строки, позволяющая переименовывать файлы в соответствии с регулярными выражениями в стиле Perl. К слову, сама утилита представляет собой крохотный скрипт на Perl, использующий пару модулей. Утилита написана самим "великим и ужасным" Ларри Уоллом, если вам это о чём-то говорит. Утилита, несмотря на кажущуюся простоту, очень мощная и удобная. Во всяком случае, для тех, кто знает регулярные выражения Perl. Тот самый случай, когда подход Unix одерживает верх надо всеми приложениями с графическим интерфейсом.

Установка, как и в предыдущих случаях, очень проста:
# apt-get install rename
Для отладки регулярного выражения для переименования файлов можно воспользоваться опцией n:
$ rename -n 's/^Гравити Фолз (.*) Серия (\d+) Сезон (\d+).avi$/Гравити Фолз, E$3S$2 - $1.avi/' *.avi
После того, как результат будет соответствовать ожиданиям, можно выполнить ту же команду уже без опции n:
$ rename -n 's/^Гравити Фолз (.*) Серия (\d+) Сезон (\d+).avi$/Гравити Фолз, E$3S$2 - $1.avi/' *.avi
Вот ещё пример регулярного выражения - к номерам серий, состоящим из одной цифры, слева добавляется ноль:
$ rename 's/^Гравити Фолз, E(\d+)S(\d{1}) - (.*)\.avi$/Гравити Фолз, E$1S0$2 - $3\.avi/' *.avi
Остаётся положить файлы в каталог, к которому имеет доступ minidlna, чтобы через медиаплеер файлы можно было просматривать на телевизоре.

P.S. Медиаплеер WD TV Play позволяет просматривать ролики с Youtube прямо из интернета, но мне такой способ просмотра не кажется удобным, поэтому я им не пользуюсь.

воскресенье, 18 марта 2018 г.

Linux Capabilities и ping

Перевод: Linux Capabilities and Ping
Автор: Джим Макдоннелл (Jim McDonnell)

Примечания переводчика:
Перевод вдогонку к прошлой статье Пересборка uwsgi с поддержкой Linux Capabilities. Пока искал документацию о том, как скрестить uwsgi и POSIX Capabilities, наткнулся на эту статью. Сразу добавил ссылку в закладки, чтобы впоследствии перевести. Кстати, описанная в этой статье ошибка попадалась коллегам на работе. Я посоветовал просто принудительно переустановить пакет командой apt-get --reinstall install ping и это помогло. Причины были мне понятны, но вот о существовании команд для раздачи "возможностей" я не подозревал: мне почему-то казалось, что программы самостоятельно запрашивают необходимые им привилегии у ядра операционной системы.

Если вы используете свежую версию Linux (время написания заметки - май 2016), вы могли столкнуться с ошибкой утилиты ping:
$ ping somehost
ping: icmp open socket: Operation not permitted
Так происходит, потому что двоичный файл ping больше не устанавливается с правами setuid. Он не имеет необходимых привилегий для открытия сокета и завершается аварийно. Это легко исправить при помощи команды:
$ sudo setcap cap_net_raw+p /bin/ping
Предполагается, что двоичный файл ping находится в /bin/ping. Теперь он работает:
$ ping somehost
PING somehost (123.123.123.123) 56(84) bytes of data.
64 bytes from 123.123.123.123: icmp_seq=1 ttl=53 time=9.14 ms
Вы только что добавили возможность - capability к двоичному файлу ping, что дало ping право открыть raw-сокет, который позволил выполнить проверку доступности удалённой системы.

Linux Capabilities - возможности Linux

Возможности Linux позволяют точно управлять видами привилегий, которые может использовать процесс или поток. Традиционно имелось только два уровня привилегий: root и не-root. Процесс, выполняющийся от имени root или суперпользователя, может выполнять с системой любые действия. Процесс, выполняющийся от имени других пользователей, может получить доступ только к тем файлам, которыми он владеет или к которым предоставлен доступ.

Ранее, до появления возможностей, ping и другие системные инструменты устанавливались с флагом setuid, позволяющим им работать от имени пользователя root. Вот так:
$ ls -l /bin/ping
-rwsr-xr-x 1 root root 44168 May 7 2014 /bin/ping
Символ "s" в строке разрешений соответствует флагу setuid, который означает, что ping будет выполняться с правами пользователя root, даже если он запущен обычным пользователем. Ping требует для работы повышенных привилегий. Вот несколько других программ, которые в Red Hat 6.5 по умолчанию устанавливаются с флагом setuid, который предписывает системе запускать их с правами root:
$ find /bin -perm +4000 -ls
652330 76 -rwsr-xr-x 1 root root 77336 Aug 6 2013 /bin/mount
656520 32 -rwsr-x--- 1 root fuse 32336 Nov 3 2011 /bin/fusermount
652317 36 -rwsr-xr-x 1 root root 36488 Sep 17 2013 /bin/ping6
652333 56 -rwsr-xr-x 1 root root 53472 Aug 6 2013 /bin/umount
652316 40 -rwsr-xr-x 1 root root 40760 Sep 17 2013 /bin/ping
651661 36 -rwsr-xr-x 1 root root 34904 Oct 17 2013 /bin/su

Опасность программ с флагом setuid

Механизм setuid отлично работает и широко распространён. Однако, он обладает низкой безопасностью. Процесс с флагом setuid во время работы получает гораздо больше привилегий, чем ему требуется на самом деле. Утилите ping требуется лишь открыть raw-сокет и права root, полученные ей через флаг setuid, позволяют это сделать, но также дают ей много других прав, которые ей не требуются. Если двоичный файл ping, например, был заменён взломанной версией, то код злоумышленника будет запущен с полными правами суперпользователя.

Это одна из причин, по которой предпочтительнее использовать возможности Linux, нежели флаг setuid. Вот почему они с каждым выпуском Linux стали использоваться всё шире.

Наборы возможностей

Выше двоичному файлу ping были выданы права, которые называются cap_net_raw. сap_net_raw - это одна из большого количества возможностей, которых, согласно странице руководства, насчитывается 38 штук.

Каждый поток или процесс, обладает тремя наборами связанных с ним возможностей: Permitted - разрешённые, Inheritable - наследуемые и Effective - действующие. В примере выше, символы "+p" в команде "setcap cap_net_raw+p /bin/ping" добавили возможность cap_net_raw к набору разрешённых возможностей двоичного файла ping, которые означают, что последующий процесс (или поток) ping получит соответствующие права. Соотношения наборов возможностей, файлов и потоков, объясняются на соответствующей странице руководства.

CAP_NET_RAW

Возникает вопрос. Если ping для работы требуется определённая возможность или флаг setuid, почему тогда они не требуются другим сетевым утилитам, таким как ssh, ftp, wget и т.д.? И тем более, браузерам вроде Firefox и Safari? Разве им не требуется тоже открывать сетевые сокеты? Да, требуется, но не такие сокеты.

Давайте воспользуемся strace и посмотрим, как ping открывает сокет:
$ strace -e socket ping 192.168.1.254
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
...
ping открывает сокет типа SOCK_RAW.

Попробуем сделать то же самое с FTP и увидим, что он не открывает сокет типа SOCK_RAW. Он использует сокет типа SOCK_STREAM:
$ strace -e socket ftp 192.168.1.254
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
ftp: connect: Connection refused
Как и ожидалось. SOCK_STREAM создаёт полное транспортно-ориентированное подключение через сокет TCP для длительной связи. С другой стороны, SOCK_RAW просто даёт доступ к нижестоящему уровню IP, позволяя ping отправлять пакеты ICMP напрямую.

Таким образом, CAP_NET_RAW позволяет открывать сокет типа SOCK_RAW, но не требуется для сокетов SOCK_STREAM.

ping в различных дистрибутивах Linux

Утилита ping полезна для пользователей, администраторов и разработчиков. В действительности, нет никакого смысла давать к ней доступ только пользователю root. Некоторые дистрибутивы согласны с этим мнением и в них необходимые возможности назначены ping по умолчанию. В более старых выпусках зачастую в ядре имеется поддержка возможностей, но ping не настроен для их использования.

Выпуски, в которых утилите ping уже предоставлены возможности:
  • Red Hat 7.0, где утилите ping предоставлены возможности cap_net_admin,cap_net_raw+ep
  • Raspbian (Debian 8 Jessie) в выпуске мая 2016 года (но не в феврале 2016)
Выпуски, в которых возможности не установлены:
  • Red Hat 6.5
  • SLES 12 (getcap/setcap по умолчанию не установлены)
  • Ubuntu 14.04/Mint 17

Благодарности

При написании этой статьи была использована информация из Linux Audit.

воскресенье, 11 марта 2018 г.

Пересборка uwsgi с поддержкой Linux Capabilities

Понадобилось мне сделать веб-приложение, которое, среди прочих функций, позволяло бы проверить, отвечает ли указанный IP-адрес на ICMP-запросы. Проблема в том, что ICMP-запросы может выполнять только пользователь root, а запускать веб-приложение от имени root мне не хотелось, потому что оно будет доступно из сети и если я допущу в нём ошибку, это может позволить злоумышленнику получить доступ к серверу, на котором работает это приложение. Не хотелось бы, чтобы взломщик сразу получил бы все карты в руки - всё же гораздо безопаснее, если он сможет хозяйничать на сервере только от имени пользователя, под которым работает веб-сервер, а не сразу от имени root.

Мне в голову сразу пришли две идеи. Первая идея - сделать отдельное небольшое веб-приложение, которое будет работать от имени пользователя root, но будет уметь только пинговать и будет доступно только на локальном петлевом интерфейсе. Основное веб-приложение будет обращаться к этому небольшому веб-приложению только для выполнения ICMP-запросов, а все остальные функции будет выполнять самостоятельно. Вторая идея - воспользоваться POSIX Capabilities. POSIX Capabilities позволяет выполнять лишь определённые функции, доступные пользователю root, не работая при этом от имени пользователя root.

Так как в качестве сервера веб-приложений я использую uwsgi, то поддержку POSIX Capabilities нужно искать в нём. И такая поддержка имеется. Её описание можно увидеть на странице Setting POSIX Capabilities

Реализовать мне пришлось обе идеи, т.к. это веб-приложение должно работать в том числе и на FreeBSD, где POSIX Capabilities не поддерживается. В случае Linux положение немного осложняется тем, что в стандартной поставке uwsgi из репозитория Debian Wheezy поддержка POSIX Capabilities остутствует. К счастью, исправить это сравнительно просто: нужно пересобрать пакеты, предварительно установив в систему пакет libcap-dev.

Установим инструменты для сборки и нужную нам библиотеку:
# apt-get install dpkg-dev devscripts fakeroot libcap-dev
Распакуем в текущий каталог исходные тексты uwsgi, из которых можно собрать как двоичные пакеты, так и пакеты с исходными текстами:
# apt-get source uwsgi
Установим все зависимости, необходимые для сборки uwsgi:
# apt-get build-dep uwsgi
Внесём в журнал изменений пакета описание последнего изменения, которое мы добавляем. Для этого запустим команду:
# dch -i
И приведём запись о последних изменениях к следующему виду:
uwsgi (1.2.3+dfsg-5+deb7u2) UNRELEASED; urgency=low

* Compiled with libcap-dev to support linux capabilities

-- Vladimir Stupin <stupin_va@ufanet.ru>  Mon, 11 Sep 2017 09:53:11 +0500
Теперь осталось собрать пакеты:
# cd uwsgi-1.2.3+dfsg
# dpkg-buildpackage -us -uc -rfakeroot
И можно устанавливать готовые пакеты, которые были помещены в вышестоящем каталоге:
# cd ..
# dpkg -i uwsgi_1.2.3+dfsg-5+deb7u2_amd64.deb uwsgi-core_1.2.3+dfsg-5+deb7u2_amd64.deb uwsgi-plugin-python_1.2.3+dfsg-5+deb7u2_amd64.deb
Для использования функции, нужно добавить в файл конфигурации веб-приложения, например, в моём случае это файл /etc/uwsgi/apps-available/ncc.ini, одну строчку:
cap = net_raw
P.S. Понадобилось недавно повторить все эти действия. Был уверен, что описал всё в блоге, но, неожиданно, записей не нашёл. Зато нашёл черновик, где были записаны команды по сборке, пример текста для журнала изменений и ссылка на документацию uwsgi. Повторил сборку по черновику и заодно довёл заметку для вида, пригодного к публикации.