Как Spotify может помочь в изучении демонов, RFC, сетей и продвижении опенсорса. Или что бывает, если заплатить не получается, а некоторые премиумные плюшки очень хочется. Третьего дня было замечено, что Спотифай выдаёт рекламу на основании страны ip-адреса. Там же было замечено, что в некоторых странах рекламу не завезли совсем. Например, в РБ. И тут же созрел "гениальный" план по отключению рекламы в не премиумном аккаунте. Вообще говоря, у Спотифая странная политика. Нашему брату приходится изрядно извращаться, чтобы купить премиум: менять локацию в профиле на заморскую, искать подходящий гифткард, который можно оплатить только paypal-ом, который в последнее время чудит и хочет ворох документов. В общем, тоже приключение, но иного порядка. Хотя, большинство этим занимается ради мобильной версии, меня таковая не интересует. Поэтому всё нижеследующее поможет только в случае с десктопной версией. Мало того, никакого расширения функций не будет. Только отрезание некоторых лишних. И я так думал, прописывая данные socks-proxy в конфиге Spotify. Проблема оказалась в том, что у них не работает аутентификация в socks по логину и паролю. Плюс разработчики регулярно что-то крутят вокруг проксика: то разрешая, то запрещая, то ломая его, что порождает целые полотнища обсуждений на офф.сайте. Было решено не полагаться на нестабильные функции и найти что-то более надёжное и любопытное. Где-то здесь читатель должен спросить: а чего бы не взять ssh с ключиком -D и дело с концом? И, в общем-то, будет прав. Но, во-первых, это ещё нужно демонизировать и подружить с autossh, чтобы не думать о рвущихся конектах. И во-вторых: это слишком просто и скучно. Как обычно, давайте пойдём слева направо, сверху вниз и опишем всё что нам нужно для реализации нашей "простой" затеи. И сразу много альтернатив: Чисто случайно может оказаться, что у вас есть друг с сервером в РБ или иной небольшой стране. Этим нужно пользоваться и раскатывать на нём желаемый проксик. Особые же ценители, могут довольствоваться другом с роутем на 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. После этого дёрнуть службу openvpn-client@openvpn-client-config-name.service, не забыть сделать для неё enable и радоваться тому, что всё полетело. Конечно же, нужно отключить любое перенаправление трафика в свежесозданный VPN, ведь мы не хотим порезать скорость на клиенской машине за счёт перегона трафика через полшарика. И да, нужно прописать статический ip-адрес на VPN-сервере для нашего клиента. Это понадобится чуть далее по повествованию. Для этого нужно включить ifconfig-pool-persist, поредактироввть ipp.txt, идущий в комплекте с OpenVPN и включить client-config-dir, плюс поредактировать конфиг нужного клиента, добавив ifconfig-push с правильной маской и желаемым IP-адресом. Теперь у нас в "сети" есть машина, которая повёрнута лицом в интернет и ей можно воспользоваться в корыстных целях. А именно, перенаправить часть трафика через неё. Итак, новая задача: нужно завернуть трафик, прилетающий на один из портов VPS с белым айпи так, чтобы этот трафик улетел в свежеподключенную виртуальную сеть и ответ смог оттуда вернуться. Способ решения: конечно же iptables! Когда ещё представится такая замечательная возможность с ним поупражняться? Нужна конфигурация находится довольно скоро, за тройку часов, сотню бранных слов и пригоршню потраченных нервов, ибо дебаг сетей — это очень специфическая процедура. Во-первых, нужно включить перенаправление трафика в ядре. Эта штука называется ipv4.ip_forward и включается немного по-разному в зависимости от ОС и сетевого менеджера. Во-вторых, нужно выбрать порт, на VPS и завернуть весь трафик, идущий на него в виртуальную подсеть. Это можно сделать, например, вот так: Здесь мы перенаправляем весь TCP-трафик, пришедший на порт 8080 внешнего интерфейса на машину с айпи 10.8.0.2 и такой же порт 8080. Тем, кто хочет грязных подробностей работы netfilter, iptables и вообще роутинга, абсолютно необходимо созерцать это или это. Итак, теперь у нас пакеты улетают в виртуальную подсеть и… там и остаются. Точнее ответ от socks-прокси улетает обратно через дефолтный gateway на машине с Dante и адресат его дропает, ибо в сетях не принято отправлять запрос на один IP, а получать ответ — с другого. Посему, нужно колдовать дальше. Итак, теперь нужно перенаправить все пакеты от проксика обратно в виртуальную подсеть в сторону VPS с белым IP. Тут ситуация немного хуже, так как просто iptables нам не хватит, ибо если мы поправим адрес назначения до роутинга (PREROUTING), то наш пакет в интернет не улетит, а если не поправим — пакет уйдёт в default gateway. Итак, нужно делать следующее: вспомнить про цепочку mangle, дабы пометит пакеты через iptables и завернуть их в кастомную таблицу маршрутизации, которая отправит их куда следует. Сказано — сделано: Берём исходящий трафик, маркируем всё, что летит с порта, на котором сидит прокси (8080 в нашем случае), перенаправляем весь помеченный трафик в таблицу маршрутизации с номером 80 (вообще номер ни от чего не зависит, просто так захотелось) и добавляем единственное правило, по которому все пакеты, попавшие в эту таблицу улетают в подсеть VPN. Отлично! Теперь пакеты улетают обратно в сторону VPS… и умирают там. Потому что VPS не в курсе что с ними делать. Поэтому, если не заморачиваться, то можно просто взять и перенаправить весь трафик, прилетающих из виртуальной подсети обратно в интернет: Здесь всё, что прилетает из подсети 10.8.0.0 с маской 255.255.255.000 заворачивается в source-NAT и улетает в дефолтный интерфейс, который повернут в интернет. Важно отметить, что эта штука будет работать только если мы прозрачно пробрасываем порт, то есть входящий порт на VPS совпадает с портом нашего прокси. Иначе нужно будет страдать чуть больше. Где-то сейчас всё должно начать работать. И останется самая малость: не забыть сделать так, чтобы все конфиги iptables и route не продолбались после рестарта. Для iptables есть специальные файлики типа /etc/iptables/rules.v4(в случае Ubuntu), а для роутов всё немного сложнее. Я их затолкал в up/down скрипты OpenVPN-а, хотя, думается мне, можно было и поприличнее сделать. Итак, у нас есть прокси с аутентификацией в нужной стране, доступный по статическому белому 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.: это не призыв к бойкоту капиталистов, к экономии на спичках или к тотальной хитропопости, а всего лишь указание на возможности исследования и развития там, где их, в общем-то, не ожидаешь. Web Developer