OpenVPN Server auf Port 443 für Android-Client
10. März 2020 um 19:27 Uhr von Atari-Frosch
Ich bekam vorgestern aus meinem Umfeld die Bitte, einen OpenVPN-Zugang auf Port 443 für ein Android-Smartphone zur Verfügung zu stellen. 443 ist ja eigentlich der Port, der für https vorgesehen ist, der verschlüsselten Übertragung von Webseiten; für OpenVPN ist Port 1194 üblich. Das ist, wie in diesem Fall, sinnvoll, wenn man nur einen stark eingeschränkten Internet-Zugang zur Verfügung hat, bei dem nur die Standard-Ports für WWW und E-Mail zugänglich und alle anderen gesperrt sind. Außerdem sind wohl auch bestimmte IP-Ranges gesperrt. Nein, nicht Iran oder China. Ein Patienten-WLAN in einem deutschen Krankenhaus.
Auf meinem Hauptserver habe ich zwar einen OpenVPN-Server laufen, aber natürlich auf einem anderen Port, denn 443 ist hier für den Webserver reserviert. Allerdings habe ich ja vor gut zwei Monaten für ein Projekt zusätzlich einen kleinen V-Server angemietet, und auf dem läuft kein Webserver. Also habe ich da vorgestern mal ein neues OpenVPN draufgebaut, dem Nutzer die nötigen Dateien incl. Client-Konfiguration gemailt und – es funktionierte nicht. „TLS handshake failed“, sagte der Client.
Das Testen erwies sich als schwierig, denn entweder das Android des Nutzers oder das Netzwerk, in dem er derzeit hängt, läßt keinen ping durch. Also weder nach außen noch nach innen. Was genau die pings frißt, läßt sich nicht sicher feststellen, aber es heißt halt, daß zum Testen der generellen Erreichbarkeit etwas anderes herangezogen werden muß. Dazu kam, daß der Server vom Client offenbar gar nichts gesehen hatte. Das Log meldete jedenfalls keine Kontaktversuche.
Da ich vorgestern Abend dann doch schon recht müde war, habe ich das Herumprobieren dann mal auf gestern verschoben.
Gestern fing ich an mit Änderungen an der client.conf. Ich fügte einen Dateinamen für ein Logfile ein und setzte die Verbosity auf 9, damit mir wenigstens und hoffentlich der Client erzählen kann, was da schiefläuft. Diese Datei wollte ich mit einer recht langen Mail zusammen verschicken.
Ich vermutete zu diesem Zeitpunkt das Problem noch bei dem Android-Client („OpenVPN für Android“) und hatte überlegt, ob das eingestellte Netzwerk-Device tun da vielleicht nicht zur Verfügung gestellt werden kann. „TLS handshake failed“ wäre dann möglicherweise ein Folgefehler, wenn der eigentliche Fehler nicht abgefangen wird. Aber ich kenne OpenVPN anders, das sollte sofort meckern, wenn das konfigurierte Device nicht existiert. Dann fehlt es nämlich im Kernel. In diesem Fall hätte ich Server und Client auf tap umkonfigurieren müssen. (Später gelernt: Android kennt gar kein tap, aber mit Sicherheit tun.)
Dann hatte ich noch — ja, das ist ziemlich paranoid gedacht, aber heutzutage weiß man ja nie … – die Idee gehabt, daß in diesem Patienten-WLAN eventuell deep packet inspection (dpi) durchgeführt wird, wodurch man unabhängig von der Portnummer erkennen könnte, welches Protokoll tatsächlich „gesprochen“ wird. Dies unter anderem zu dem Zweck, den Aufbau von VPN-Verbindungen auf den Standard-Ports zu unterbinden. Ich habe sowas vor über zehn Jahren einmal gesehen, da saß der Client allerdings im Iran. Jedoch gab es auch in diesem Fall damals einen ersten Verbindungsaufbau, den ich im Server-Log sehen konnte. Ein Router des Zugangsanbieters übernahm dann die IP des Clients und schickte dem Server einen Reset, den der Server dem echten Client bestätigte. Dadurch konnte die verschlüsselte Verbindung nicht aufgebaut werden, weil der Verbindungsaufbau ständig resettet wurde. Lange Rede, kurzer Sinn: Eine solche Störung durch den Zugangsprovider hätte ich trotz allem im Log des Servers sehen müssen. Aber das Log schwieg sich aus.
Da wir bereits herausgefunden hatten, daß die Websites auf meinem Hauptserver definitiv erreicht werden können – und das ist immer Port 443, weil ich eine Zwangsumleitung von Port 80 auf Port 443 im Webserver eingetragen habe –, hatte ich noch die Idee gehabt, da etwas mit Proxy-Zeug zu basteln, um den Webserver dazu zu bringen, die Verbindungen für das OpenVPN an dieses durchzureichen. Das wäre vermutlich recht tricky geworden, denn das ist ja hier quasi laufender Betrieb. Aber es blieb bei der theoretischen Erwägung.
In der E-Mail hatte ich dann unter anderem noch auf Telnet-Apps im Playstore hingewiesen und wollte darum bitten, so eine zu installieren und dann zu versuchen, den V-Server mit telnet auf Port 25 (ja, da läuft ein Mailserver) und dann auf Port 443 zu erreichen. Um sicher zu sein, daß ich weiß, welche Meldungen da jeweils zurückkommen sollten, probierte ich das selbst vorher aus und bekam bei Port 25 die erwartete Antwort des Mailservers. Auf Port 443 erhielt ich jedoch eigenartigerweise nur ein „Connection refused“.
Das brachte mich auf die Idee, mal nmap (Port-Scanner) auf den Host loszulassen. Und siehe da, Port 443 war gar nicht offen, ja nicht einmal irgendwie sichtbar, obwohl der OpenVPN-Server in der Prozeßliste stand.
Huch? 🤔
Zwar habe ich iptables auf dem Host laufen, aber explizite Ports blockierte der nicht. Umgekehrt, wenn ein Dienst gestartet wird, macht der ja seinen konfigurierten Port von selbst auf, da muß die Firewall gar nichts mehr tun.
An diesem Punkt löschte ich dann den größten Teil der E-Mail wieder 😉 Denn offenbar lag das Problem weder beim Android-Client, noch hatte dieses Patienten-WLAN was damit zu tun. Der Dienst war nach außen schlicht unsichtbar.
Nur, wo anfangen? Klar, mit einer Suchmaschine. Die Such-Ente (DuckDuckGo) fand mir schließlich einen Forumseintrag, der zwar nicht explizit was zu meinem Problem sagte, aber mir trotzdem den entscheidenden Hinweis gab: OpenVPN Port: use 1194 UDP or 443 TCP?
Auch wenn man einen OpenVPN-Server nicht auf dem üblichen Port 1194 betreibt, wird eigentlich eher UDP eingestellt. Der Trick ist wohl nun, für Port 443 TCP zu wählen. Das schien mir zwar zunächst weit hergeholt, aber dann konfigurierte ich den Server auf TCP um und startete ihn neu. Und siehe da: nmap konnte den Port sehen, und ich bekam eine ordentliche Antwort auf meine Anfrage per telnet.
Das hieß aber leider noch nicht, daß der Client jetzt sauber verbinden konnte. Zunächst vermutete ich, daß die Verbindung am falsch eingestellten Parameter topology scheiterte. Die hatte ich versehentlich aus der Server-Konfiguration rausgenommen. Der muß da aber mit topology subnet zwingend rein, sonst wird eine andere Topologie übermittelt, die eigentlich wohl nur für Windows-Zeugs relevant ist. Und dann kam der Client rein, erzählte mir aber was von einer lokalen 10er-Adresse, von der mir völlig unklar war, wo er die her hatte, denn ich hatte ein 192.168.-Netz definiert. Ich tippte zunächst auf NAT beim Zugangsprovider, aber letztendlich konnte ich nicht herausfinden, wo diese 10er-Adresse herkommt. Erik Pusch hat mir heute noch diesen Eintrag bei Serverfault gezeigt: MULTI: bad source address from client - any one-off solutions? – ich habe mich allerdings noch nicht genauer damit befaßt.
Nach der Änderung an der Topologie kam die Verbindung zunächst zustande. Aber nach kurzer Zeit – mal 40 Sekunden, mal 3,5 Minuten – brach sie wieder ab; der Client kam auch nicht raus. Der Server meldete einen Reset. Der serverseitige Logeintrag liest sich so, als ob der Client diesen Reset ausgelöst hätte. Und dann schließt der Server den Socket (echte IP des Clients mit $ClientIP maskiert):
Mon Mar 9 19:51:26 2020 us=223528 $ClientIP:56816 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 ECDHE-RSA-AES256-GCM-SHA384, 2048 bit RSA
Mon Mar 9 19:51:26 2020 us=223788 $ClientIP:56816 [client1] Peer Connection Initiated with [AF_INET]$ClientIP:56816
Mon Mar 9 19:51:26 2020 us=223921 client1/$ClientIP:56816 MULTI_sva: pool returned IPv4=192.168.23.4, IPv6=(Not enabled)
Mon Mar 9 19:51:26 2020 us=224057 client1/$ClientIP:56816 MULTI: Learn: 192.168.23.4 -> client1/$ClientIP:56816
Mon Mar 9 19:51:26 2020 us=224142 client1/$ClientIP:56816 MULTI: primary virtual IP for client1/ClientIP:56816: 192.168.23.4
Mon Mar 9 19:51:27 2020 us=398891 client1/$ClientIP:56816 PUSH: Received control message: 'PUSH_REQUEST'
Mon Mar 9 19:51:27 2020 us=399164 client1/$ClientIP:56816 SENT CONTROL [client1]: 'PUSH_REPLY,redirect-gateway def1 bypass-dhcp,compress lz4-v2,route-gateway 192.168.23.1,topology subnet,ping 10,ping-restart 120,ifconfig 192.168.23.4 255.255.255.0,peer-id 0,cipher AES-256-GCM' (status=1)
Mon Mar 9 19:51:27 2020 us=399279 client1/$ClientIP:56816 Data Channel MTU parms [ L:1552 D:1450 EF:52 EB:406 ET:0 EL:3 ]
Mon Mar 9 19:51:27 2020 us=399472 client1/$ClientIP:56816 Data Channel Encrypt: Cipher 'AES-256-GCM' initialized with 256 bit key
Mon Mar 9 19:51:27 2020 us=399557 client1/$ClientIP:56816 Data Channel Decrypt: Cipher 'AES-256-GCM' initialized with 256 bit key
Mon Mar 9 19:52:03 2020 us=583474 client1/$ClientIP:56816 MULTI: bad source address from client [10.14.149.249], packet dropped
Mon Mar 9 19:52:44 2020 us=732735 client1/$ClientIP:56816 Connection reset, restarting [0]
Mon Mar 9 19:52:44 2020 us=733095 client1/$ClientIP:56816 SIGUSR1[soft,connection-reset] received, client-instance restarting
Mon Mar 9 19:52:44 2020 us=733923 TCP/UDP: Closing socket
Da wir leider feststellen mußten, daß der Android-Client sich penetrant weigert, das in der client.conf konfigurierte Log zu schreiben, war nicht herauszufinden gewesen, was da jetzt eigentlich schiefläuft. Die Angaben im Server-Log genügten mir nicht, um die Ursache für den Verbindungsabbruch herauszufinden. Daß der Hinweis bei Serverfault das Grundproblem lösen würde, glaube ich irgendwie auch nicht; denn auch bei den Versuchen, bei denen diese Meldung nicht durchkam, brach die Verbindung früher oder später und mit denselben Meldungen ab.
… wir haben das dann heute erstmal anders gelöst: Da das Hauptproblem des Nutzers darin bestand, seine externen SSH-Zugänge nicht erreichen zu können, öffnete ich in der Konfiguration des sshd auf dem V-Server zusätzlich Port 443 und beschränkte den Zugang zu diesem Port per iptables auf die IP-Range, in welcher sich der Nutzer derzeit befindet.
Als neugieriger Mensch wüßte ich aber dann doch mal ganz gerne, warum das mit dem OpenVPN nicht funktionieren wollte. Ist ja durchaus möglich, daß ich die Situation irgendwann mal wieder auf den Tisch bekomme.
11. März 2020 at 0:10
UDP wird sicher eh seltener oft freigegeben, da die meisten erwünschten Anwendungen (Mail, Web) TCP nutzen und UDP, mangels eines Verbindungsstatus, schlechter zu NATten ist.
Telnet läuft über eine TCP-Verbindung, deshalb ist es wohl kein Wunder, dass da auch nichts ankommen konnte. Ein einfaches „nmap host.example.com“ für nur einen -sS oder -sT Scan aus, die beide nur TCP-Ports scannen. Vermutlich ginge ein nmap -sU -p U:443 host.example.com
Aber weiter weiß ich jetzt auch nicht, zu selten Bedarf an OpenVPN gehabt.
12. März 2020 at 14:41
UDP kann man auch NATten. Die „Verbindugen“ werden dann einfach mit einem Timeout gemappt. Zusammen mit dem Keep-Alive von OpenVPN sollte dann alles geritzt sein.
15. Januar 2021 at 19:29
Hallo, ich stehe momentan vor dem exakt selben Problem. Es will einfach nicht laufen. Das ist nicht in allen WLANs dieser Welt der Fall aber doch in so manchen. Habe es auch mit Port 443 und TCP probiert. Von unterwegs klappt es aber nicht aus dem WLAN im Unternehmen bei dem ich öfter als Gast bin.
16. Januar 2021 at 10:48
@Aurin: Wenn die Verbindung zustandekommt, aber irgendwann wieder abbricht, bestehen gute Chancen, das Problem bei MTU/MSS zu finden. Ja, das ist einigermaßen eklig.
@Hans: Dein erster Ansprechpartner wäre dann wohl die IT des Unternehmens, in dem Dein VPN nicht funktioniert. Möglicherweise wollen sie es ja nicht.
16. Januar 2021 at 16:09
@Hans Da hatte ich wohl vergessen, hier ein Update zu machen: Das war ein Fall von PEBKAC gewesen. Ich hatte schlicht vergessen gehabt, dem Client die Nameserver mitzuteilen. Es lag also nicht am Android-Client und auch nicht am Port.