Včera jsem řešil celkem zajímavý problém. Zákazník má několik serverů odříznutých od vnějšího světa i podnikové sítě, ke kterým se dá přistoupit pouze skrze SOCKS proxy. Úkolem bylo na všech serverech updatovat instalované balíčky na jejich nejnovější verze, nacházející se v oficiálních repozitářích.
Kudy tudy cestička?
Zamyslel jsem se tedy, co vlastně potřebuju k tomu, abych servery, které jsou úmyslně odříznuté od internetu, dostal na internet. Užité operační systémy byly převážně Ubuntu 12.04, takže na mě čekal relativně příčetný balíčkovací systém apt-get, který si drtivou většinu dat tahá po HTTP. Moje první myšlenky tedy zamířily k HTTP proxy, kterou bych si rozmotal na svém laptopu a předhodil ji balíčkovacímu systému. Jelikož jsou ale vzdálené systémy za SOCKS proxy, nemohly by k mé HTTP proxy přistoupit přímo a musel bych jim skrze SSH svůj port protunelovat. Po chvíli jsem řešení zavrhl jako příliš těžkopádné a téměř až inženýrsky cílené na naprosto konkrétní symptom problému a ignorování problému jako takového. Taky jsem tak trochu pochyboval, že cvičené opice, které dělají místní adminy, by byly schopny můj postup podle návodu zopakovat.
Dovnitř a ven
Myšlenku na tunelování SSH portů jsem ale nezavrhl. Vzpomněl jsem si, že SSH umí pomocí parametru -D dynamicky forwardovat porty na úrovni aplikačních protokolů, čímž efektivně vytvoří vlastní SOCKS server. Nevýhodou je, že takto lze požádat o dynamický port pouze na straně SSH serveru, ale v mém případě bych jej potřeboval vytvořit na straně SSH klienta a SSH serveru na vzdálených systémech poskytnout. Můžu ale vytvořit rovnák na vohejbák, vzdálenému systému poskytnout port svého SSH serveru a s jeho pomocí vytvořit další, vnořenou SSH relaci, kde vzdálený systém bude SSH klientem a můj laptop SSH serverem. V takovém případě pak dynamické forwardování „správným směrem“ budu moci použít a dokonce bude i fungovat. Následně na vzdálené systémy dopravím a nainstaluju nějakou aplikaci nebo knihovnu, která se SOCKS servery bude umět komunikovat a budu tak moci vylézt na internet nejen s balíčkovacím systémem, ale i s libovolnou jinou aplikací, u které to bude zapotřebí.
Jak jsem již řekl, servery jsou schovány za SOCKS proxy, takže aplikaci, která se skrze SOCKS umí prohnat, potřebuju i pro připojení k nim. Na svém laptopu pro tento účel používám tsocks.
user@laptop:~$ tsocks ssh -R 2222:localhost:22 root@12.34.56.78
Po zadání tohoto příkazu se připojím ke vzdálenému systému a ten na svém portu 2222 dosáhne na SSH server mého laptopu. Na vzdáleném systému pak naťukám
root@server:~# ssh -p 2222 -D 10800 <uživatel_na_laptopu>@localhost
Čímž vytvořím tunel v tunelu, na jehož portu 10800 bude naslouchat SOCKS proxy SSH serveru mého laptopu.
Vejce nebo slepice
Jako software, který nainstaluju na vzdálený systém, jsem si vybral proxychains, protože umí zachytit getaddrinfo() a jiná volání libc a dokáže zajistit bezproblémový překlad DNS názvů, což jsou věci, u kterých tsocks trochu pokulhává. Dostávám se teď ale do docela vtipného začarovaného kruhu, protože na vzdálený systém potřebuju skrze balíčkovací systém nainstalovat balíček, díky němuž budu moci používat balíčkovací systém. Tohle jednoduše vyřeším stažením balíčku na svém laptopu a zkopírováním na vzdálené systémy skrze SCP.
user@laptop:~$ wget https://launchpad.net/ubuntu/+archive/primary/+files/libproxychains3_3.1-3_amd64.deb
user@laptop:~$ tsocks scp libproxychains3_3.1-3_amd64.deb root@12.34.56.78:~/
A na vzdáleném systému pak pomocí dpkg nainstaluji
root@server:~# dpkg -i libproxychains3_3.1-3_amd64.deb
Proxychains
Kdybych byl fajnovka, můžu stáhnout a nainstalovat i samotný balíček proxychains, ale „binárka“ v něm obsažená je jen skript, který prachsprostě preloadne libproxychains a spustí to, co po něm chcete, což si můžu stejně tak dobře udělat sám.
Konfigurační soubor /etc/proxychains.conf pak upravím následovně
strict_chain
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks5 127.0.0.1 10800
A můžu vesele surfovat.
export LD_PRELOAD=libproxychains.so.3
apt-get update
apt-get upgrade