Dynamisk SSH-vidarebefordran som SOCKS-proxy över din VPN
En app som bara talar SOCKS har ingen proxy-slutpunkt på en vanlig VPN. Två hopp, en enda loopback-lyssnare och ett namnsök som SSH-servern måste göra själv.
Ett program som bara talar SOCKS har inget att tala med på en vanlig VPN, eftersom tunneln bär paket och appen vill ha en proxy-slutpunkt. OpenSSH kan leverera den slutpunkten när åtkomstägaren tillåter det, eftersom dynamisk vidarebefordran gör en SSH-session till en lokal proxy. Sedan finns det två hopp att hålla isär: tunneln som når SSH-värden och anslutningen som den värden öppnar vidare. Att skilja dem förklarar både varför arrangemanget fungerar och vad det aldrig kommer att göra.
Vad SSH-lyssnaren blir och vad den inte blir
Dynamisk vidarebefordran får SSH-klienten att lyssna lokalt och tala SOCKS4 eller SOCKS5 med allt som ansluter. Varje begäran namnger ett mål och SSH-servern öppnar den vidare anslutningen, vilket är varför målsökningen kan ske på andra sidan. Det här är TCP-vidarebefordran på programnivå, inte en VPN för hela enheten. Den bär ingen UDP-association, ingen ICMP och ingenting för program som helt ignorerar proxyinställningar. Inte heller hoppet från SSH-servern till programmet ligger inuti din tunnel, vilket spelar roll när målet bara tar emot trafik från kända nätverk.
Förutsättningarna är verkliga: en väg till SSH-värden, ett auktoriserat konto, en verifierad värdnyckel för servern och tillstånd att vidarebefordra. Ingen av dem skapas av proxyn, och den sista saknas vanligtvis först. Bekräfta alla fyra innan du felsöker något annat, eftersom felet ser likadant ut från klienten, vilken som än saknas.
Starta den på loopback med en uttrycklig port
Välj en oanvänd lokal port och bind den uttryckligen till loopback i stället för att utelämna adressen. De tre alternativen nedan finns var och en av ett skäl.
ssh -D 127.0.0.1:1080 -NT -o ControlPath=none -o ExitOnForwardFailure=yes \
[email protected]
-N hoppar över fjärrkommandot och -T hoppar över pseudoterminalen, så sessionen finns bara för att vidarebefordra. ExitOnForwardFailure låter klienten avsluta när lyssnaren inte kan skapas, i stället för att köra utan den vidarebefordran du bad om. ControlPath=none håller sessionen utanför en befintlig multiplexad anslutning som kan lägga till egna vidarebefordringar. Loopback håller lyssnaren utanför LAN, men på en delad maskin är det ingen auktoriseringsgräns, eftersom andra lokala processer också kan nå den. Referensen för OpenSSH-klienten dokumenterar alla dessa flaggor, och loopback-varningen följer av vad en lyssnande socket är.
Skicka namn genom proxyn, inte runt den
En SOCKS5-klient kan slå upp målet själv eller be proxyn göra det, och det valet avgör vilken resolver som svarar. Med socks5h skickar curl värdnamnet genom proxyn, så uppslaget sker på SSH-servern. Med vanlig socks5 slår laptopen upp först och bara anslutningen reser, vilket tyst undergräver poängen när namnet är internt. Begäran nedan tömmer också listan utan proxy, så ett ärvt NO_PROXY-värde inte kan leda den runt proxyn.
curl -sS --noproxy '' --proxy socks5h://127.0.0.1:1080 https://app.corp.example/health
Certifikatvalidering och programmets egen inloggning gäller fortfarande, eftersom proxyn inte ersätter någon av dem. Det återstår två uppslag: laptopen måste nå SSH-värden via den tillåtna VPN- och DNS-vägen, och SSH-servern måste själv slå upp programnamnet. Det andra kan testas separat innan någon trafik går genom proxyn.
ssh [email protected] getent hosts app.corp.example
Bevisa ett tillåtet mål och stäng sedan sessionen
Testa ett mål som policyn tillåter och ett som den borde avvisa, eftersom en fungerande vidarebefordran bara bevisar att lyssnaren fungerar och inget mer. Programmet ser källadressen som SSH-servern väljer, och det är inte tunneladressen för din laptop. Där den andra änden loggar anslutningar efter källa är den skillnaden det första att kontrollera när en begäran avvisas.
Stoppa sessionen genom processen som äger den i stället för att döda ett orelaterat skal. Bekräfta sedan att lyssnaren är borta, eftersom en port som fortfarande svarar är en session du inte egentligen har stängt. Ta bara bort den proxyinställning som den här övningen införde, och låt resten av programmets konfiguration vara. En terminal utan tillsyn som håller en vidarebefordringsregel är inte en tjänst, och en permanent proxy behöver en godkänd livscykel, inte ett glömt fönster.
ss -ltn | grep 1080
Fel som det här arrangemanget inte kan åtgärda
Vissa symtom pekar rakt på gränserna ovan, och att känna igen dem tidigt sparar en eftermiddag av proxyfelsökning. Tabellen kopplar det du ser till det det vanligtvis betyder. Allt i den sista kolumnen är en designfråga, inte ett konfigurationsfel.
| What you see | What it usually means | Where to look |
|---|---|---|
| The app connects and nothing follows | It ignores proxy settings entirely | Its own network settings, not the SSH session |
| A name resolution error for the destination | The SSH server cannot resolve it | Server resolver and search domains |
| A UDP-only application fails | Dynamic forwarding carries TCP only | This arrangement cannot serve it |
| curl works, the browser does not | The browser is not using the socks5h endpoint | Browser proxy configuration |
| The listener answers after the session ended | Another process owns port 1080 | The ss output, then the owning process |
De tre första raderna är de som folk feldiagnostiserar, eftersom var och en ger ett anslutningsförsök i stället för ett fel om själva proxyn. Ett namn som löses upp på laptopen säger ingenting om serverns resolver, och felet läses i stället som ett certifikat- eller timeoutproblem. Program som bara använder UDP står utanför designen, inte trasiga inuti den, och ingen extra ssh-flagga ändrar det. Webbläsarraden är den vanliga påminnelsen om att proxyinställningar gäller per program. Den sista raden är anledningen till att avslutningskontrollen finns: en port som fortfarande lyssnar betyder att något annat äger den nu.