Приключения на ровном месте

Приключения на ровном месте

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

Начало

Третьего дня было замечено, что Спотифай выдаёт рекламу на основании страны ip-адреса. Там же было замечено, что в некоторых странах рекламу не завезли совсем. Например, в РБ. И тут же созрел «гениальный» план по отключению рекламы в не премиумном аккаунте.

Немного про Spotify

Вообще говоря, у Спотифая странная политика. Нашему брату приходится изрядно извращаться, чтобы купить премиум: менять локацию в профиле на заморскую, искать подходящий гифткард, который можно оплатить только paypal-ом, который в последнее время чудит и хочет ворох документов. В общем, тоже приключение, но иного порядка. Хотя, большинство этим занимается ради мобильной версии, меня таковая не интересует. Поэтому всё нижеследующее поможет только в случае с десктопной версией. Мало того, никакого расширения функций не будет. Только отрезание некоторых лишних.

А чего сложного?

И я так думал, прописывая данные socks-proxy в конфиге Spotify. Проблема оказалась в том, что у них не работает аутентификация в socks по логину и паролю. Плюс разработчики регулярно что-то крутят вокруг проксика: то разрешая, то запрещая, то ломая его, что порождает целые полотнища обсуждений на офф.сайте.

Было решено не полагаться на нестабильные функции и найти что-то более надёжное и любопытное.

Где-то здесь читатель должен спросить: а чего бы не взять ssh с ключиком -D и дело с концом? И, в общем-то, будет прав. Но, во-первых, это ещё нужно демонизировать и подружить с autossh, чтобы не думать о рвущихся конектах. И во-вторых: это слишком просто и скучно.

По-порядку

Как обычно, давайте пойдём слева направо, сверху вниз и опишем всё что нам нужно для реализации нашей «простой» затеи.

Для начала нужен прокси

И сразу много альтернатив:

  • можно просто пойти и взять из открытых проксилистов. Дёшево (точнее даром), но абсолютно ненадёжно и время жизни таких проксиков стремится к нулю. Поэтому надо бы найти/написать парсер прокси списков, фильтровать их по нужному типу и стране и вопрос подстановки найденного прокси в Spotify остаётся открытым (ну, разве что, через HTTP_PROXY передавать и кастомную обёртку для бинарника делать, чтобы весь остальной трафик туда же не отправить).
  • Можно купить аналогичный прокси и избавить себя от большинства вышеописанных проблем. Но при цене прокси можно сразу купить премиум на Спотифай, а это не спортивно в рамках исходной задачи.
  • Поднять свой. Как вы, наверное, догадались — это наш выбор.

Чисто случайно может оказаться, что у вас есть друг с сервером в РБ или иной небольшой стране. Этим нужно пользоваться и раскатывать на нём желаемый проксик. Особые же ценители, могут довольствоваться другом с роутем на DD-WRT или аналогичном ПО. Но там свой дивный мир и в рамки сего рассказа этот мир явно не поместится.

Итак, наши варианты: Squid — не вдохновляет, да и не хочется HTTP-проксик, сего протокола и так слишком много вокруг. А в области SOCKS ничего толкового кроме Dante пока не завезли. Посему, берём его.

Манула по установке и настройке Данте не ждите. Он просто гуглится и особого интереса не представляет. В минимальной комплектации надо накидать всяких client pass, socks pass, правильно прописать интерфейсы да не забыть добавить socksmethod: username. В таком виде для аутентификации логопас будет браться из пользователей системы. А часть про безопасность: запрет доступа к локалхосту, ограничение по юзерам и прочее — это уже чисто индивидуально в зависимости от личной паранойи.

Развернуть прокси лицом в сеть

Спектакль в двух актах.

Акт первый

С прокси разобрались, теперь надо получить к нему доступ из глобальной паутины. Если у вас есть машинка с белым IP в нужной стране, то можете смело пропускать этот пункт. У нас же таковой нет (мы, как говорилось выше, хостимся у друзей дома) и ближайший белый айпи где-то в Германии, поэтому будем изучать сети.

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

Задача: есть прокси где-то далеко за NAT-ом, надо его повесить на один из портов VPS, имеющей белый IP и расположенной на краю света.

Логично предположить, что это решается либо пробросом порта (который реализуется через вышеупомянутый ssh), либо объединением железок в виртуальную сеть через VPN. С ssh работать умеем, autossh брать скучно, поэтому возьмём OpenVPN.

У DigitalOcean есть замечательный манул по этому делу. Добавить к нему мне нечего. А полученный конфиг можно довольно легко подружить клиентом OpenVPN и systemd. Достаточно положить его (конфиг) в /etc/openvpn/client/ и не забыть сменить расширение на .conf. После этого дёрнуть службу [email protected], не забыть сделать для неё enable и радоваться тому, что всё полетело.

Конечно же, нужно отключить любое перенаправление трафика в свежесозданный VPN, ведь мы не хотим порезать скорость на клиенской машине за счёт перегона трафика через полшарика.

И да, нужно прописать статический ip-адрес на VPN-сервере для нашего клиента. Это понадобится чуть далее по повествованию. Для этого нужно включить ifconfig-pool-persist, поредактироввть ipp.txt, идущий в комплекте с OpenVPN и включить client-config-dir, плюс поредактировать конфиг нужного клиента, добавив ifconfig-push с правильной маской и желаемым IP-адресом.

Акт второй

Теперь у нас в «сети» есть машина, которая повёрнута лицом в интернет и ей можно воспользоваться в корыстных целях. А именно, перенаправить часть трафика через неё.

Итак, новая задача: нужно завернуть трафик, прилетающий на один из портов VPS с белым айпи так, чтобы этот трафик улетел в свежеподключенную виртуальную сеть и ответ смог оттуда вернуться.

Способ решения: конечно же iptables! Когда ещё представится такая замечательная возможность с ним поупражняться?

Нужна конфигурация находится довольно скоро, за тройку часов, сотню бранных слов и пригоршню потраченных нервов, ибо дебаг сетей — это очень специфическая процедура.

Во-первых, нужно включить перенаправление трафика в ядре. Эта штука называется ipv4.ip_forward и включается немного по-разному в зависимости от ОС и сетевого менеджера.

Во-вторых, нужно выбрать порт, на VPS и завернуть весь трафик, идущий на него в виртуальную подсеть. Это можно сделать, например, вот так:

iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 8080 -j DNAT --to-destination 10.8.0.2:8080

Здесь мы перенаправляем весь TCP-трафик, пришедший на порт 8080 внешнего интерфейса на машину с айпи 10.8.0.2 и такой же порт 8080.

Тем, кто хочет грязных подробностей работы netfilter, iptables и вообще роутинга, абсолютно необходимо созерцать это или это.

Итак, теперь у нас пакеты улетают в виртуальную подсеть и… там и остаются. Точнее ответ от socks-прокси улетает обратно через дефолтный gateway на машине с Dante и адресат его дропает, ибо в сетях не принято отправлять запрос на один IP, а получать ответ — с другого. Посему, нужно колдовать дальше.

Итак, теперь нужно перенаправить все пакеты от проксика обратно в виртуальную подсеть в сторону VPS с белым IP. Тут ситуация немного хуже, так как просто iptables нам не хватит, ибо если мы поправим адрес назначения до роутинга (PREROUTING), то наш пакет в интернет не улетит, а если не поправим — пакет уйдёт в default gateway. Итак, нужно делать следующее: вспомнить про цепочку mangle, дабы пометит пакеты через iptables и завернуть их в кастомную таблицу маршрутизации, которая отправит их куда следует.

Сказано — сделано:

iptables -t mangle -A OUTPUT -p tcp --sport 8080 -j MARK --set-mark 0x80
ip rule add fwmark 0x80 table 80
ip route add default via 10.8.0.1 dev tun0 table 80

Берём исходящий трафик, маркируем всё, что летит с порта, на котором сидит прокси (8080 в нашем случае), перенаправляем весь помеченный трафик в таблицу маршрутизации с номером 80 (вообще номер ни от чего не зависит, просто так захотелось) и добавляем единственное правило, по которому все пакеты, попавшие в эту таблицу улетают в подсеть VPN.

Отлично! Теперь пакеты улетают обратно в сторону VPS… и умирают там. Потому что VPS не в курсе что с ними делать. Поэтому, если не заморачиваться, то можно просто взять и перенаправить весь трафик, прилетающих из виртуальной подсети обратно в интернет:

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j SNAT --to-source 172.42.1.10

Здесь всё, что прилетает из подсети 10.8.0.0 с маской 255.255.255.000 заворачивается в source-NAT и улетает в дефолтный интерфейс, который повернут в интернет. Важно отметить, что эта штука будет работать только если мы прозрачно пробрасываем порт, то есть входящий порт на VPS совпадает с портом нашего прокси. Иначе нужно будет страдать чуть больше.

Где-то сейчас всё должно начать работать. И останется самая малость: не забыть сделать так, чтобы все конфиги iptables и route не продолбались после рестарта. Для iptables есть специальные файлики типа /etc/iptables/rules.v4(в случае Ubuntu), а для роутов всё немного сложнее. Я их затолкал в up/down скрипты OpenVPN-а, хотя, думается мне, можно было и поприличнее сделать.

Завернуть трафик от приложения в proxy

Итак, у нас есть прокси с аутентификацией в нужной стране, доступный по статическому белому IP-адресу. Осталось им воспользоваться и перенаправить туда трафик от Spotify. Но есть нюанс, как говорилось выше, логин-пароль для проксика в Спотифае не работает, поэтому будем искать как извернуться.

Для начала, вспомним про proxifier. Отличная штука, только стоит как звездолёт (40$). Мы за эти деньги снова можем купить премиум и дело с концом. Поэтому поищем более бесплатные и открытые аналоги на мак (таки да, мы же на маке хотим музыку слушать). Обнаружим целый один инструмент: proximac. И радостно пойдём его тыкать.

Но радость будет недолгой, ибо окажется, что нужно включить режим дебага и кастомные расширений ядра в MacOS, запилить несложный конфиг и понять, что у этой тулзы ровно так же проблема, что и у Spotify: она не может пройти аутентификацию по логину-паролю на socks-proxy.

Где-то здесь пора психануть и таки купить премиум… но нет! Попробуем попросить починить, этож опенсорс! Делаем тикет. И в ответ получаем душещипательную историю о том, что у единственного мэйнтейнера больше нет макбука и хрен вам, а не фикс.

Снова расстроимся. Но потом вспомним молодость и Си, включим дебаг режим в Dante, покопаемся в сотне килобайт логов, сходим в RFC1927 за информацией о протоколе SOCKS5, разберёмся с Xcode и таки найдём проблему. Достаточно поправить один символ в списке кодов методов, которые предлагает клиент для аутентификации и всё начинает работа как часы. Радуемся, собираем релизный бинарник, делаем пул-реквест и уходим в закат идём к следующему пункту.

Автоматизируй это

Раз Proximac заработал, его нужно демонизировать и забыть про него. Для этого подходит целая одна система инициализации, которая есть в MacOS, а именно launchd.

Быстро находим мануал и понимаем, что это совсем не systemd и тут почти совок и xml. Никаких тебе красивых конфигов, никаких команд вида status, restart, daemon-reload. Только хардкор вида start-stop, list-grep, unload-load и ещё много странностей. Превозмогая всё это пишем plist, загружаем. Не работает. Изучаем способ дебага демона, дебажим, понимаем что там в ENV даже PATH не завезли нормальный, ругаемся, завозим (добавляя /sbin и /usr/local/bin) и наконец-то радуемся автостарту и стабильной работе.

Выдыхаем

Что в итоге? Неделя приключений, наколеночный зоопарк из сервисов, который дорог сердцу и делает то, что от него требуется. Немного знаний в сомнительных технических областях, капелька опенсорса и улыбка на лице от мысли «Я сделяль!»

P.S.: это не призыв к байкоту капиталистов, к экономии на спичках или к тотальной хитропопости, а всего лишь указание на возможности исследования и развития там, где их, в общем-то, не ожидаешь.

Источник: habr.com