Het herstellen van iChat Audio- en Videoconferenties

157.230.2.213 configuration.apple.com

Let op: als je een BSD-gebaseerde router gebruikt, zoals pfSense of OPNsense, moet je source port preservation inschakelen in je outbound NAT-instellingen.

iChat AV en de iSight

Ik was vroeger het meest irritante soort Apple-fanaticus. In het begin van de jaren 2000 dacht ik dat alles van Apple beter was dan wat er elders beschikbaar was, of dat nu waar was of niet. Er was echter één gebied waar dat daadwerkelijk waar was: videobellen en audioconferenties.

De grote spelers in consumentenvideoconferenties waren in die tijd Microsoft met MSN Messenger, Yahoo! met Yahoo! Messenger en AOL met AOL Instant Messenger (AIM). Tijdens de World Wide Developer Conference (WWDC) van Apple in juni 2003 kondigde Apple, samen met de G5-processor en OS X 10.3 Panther, "iChat AV" aan.

Tegelijkertijd introduceerden ze de "iSight", een prachtige, over-engineered webcam die hierbij hoorde. Ik had zelf een G4-laptop en een iSight. Het voelde alsof ik in de toekomst leefde en ik hield ervan. Dit artikel gaat over hoe ik de videoconferentie-functionaliteit van iChat op vroege versies van OS X weer werkend heb gekregen over het internet.

De eerste poging

In het begin van 2023 besloten mijn vriend (hierna aangeduid als "Methodius") en ik om het simpelweg te proberen. We wilden een iChat-audioverbinding testen op OS X Leopard. Die versie van iChat werkt met XMPP (Jabber) servers. We maakten beiden een account aan op jabb.im en drukten op de groene belknop. Het toestel aan de andere kant ging over, er verscheen een melding dat er geprobeerd werd te verbinden, en toen... mislukte de verbinding.

Het is nooit zo eenvoudig.

iChat debuggen en het netwerk inspecteren

Het werd tijd om het netwerkverkeer te inspecteren met tcpdump. Gelukkig is dit vooraf geïnstalleerd op de OS X-versies van die tijd. Naast de pakketinspectie startte ik iChat in debugmodus via de terminal met het volgende commando:

/Applications/iChat.app/contents/MacOS/iChat -errorLogLevel 7

De debugmodus van iChat was zeer nuttig, maar nauwelijks gedocumenteerd, dus ik leg het hier vast voor toekomstig gebruik.

Hoe het zou moeten werken

  1. iChat stuurt een HTTP-verzoek naar http://configuration.apple.com/configurations/macosx/ichat/1/snatmap.txt om het adres van een SNATMAP-server op te vragen.
  2. iChat stuurt een UDP-verzoek naar die SNATMAP-server om zijn eigen publieke IP-adres te achterhalen.
  3. Beide iChat-clients wisselen hun publieke IP-adressen en poorten uit via hun tekstcommunicatiekanaal (in ons geval XMPP).
  4. Beide clients proberen vervolgens een peer-to-peer RTP-verbinding op te zetten door pakketten naar elkaar te sturen via de publieke IP-adressen en poorten die via de SNATMAP-server zijn ontdekt. Omdat NAT-verbindingen stateful zijn en uitgaande NAT-verbindingen een inkomende verbinding openen voor de machine die het verzoek doet, kunnen iChat-clients achter NAT-routers met elkaar verbinden zonder dat er vooraf poortforwarding hoeft te worden ingesteld.

Wat er werkelijk gebeurde

  • iChat probeerde een HTTP-verzoek te sturen naar http://configuration.apple.com/configurations/macosx/ichat/1/snatmap.txt, maar werd omgeleid naar HTTPS. iChat kon hier geen verbinding mee maken omdat de TLS-suite van OS X te oud is.
  • Omdat dit verzoek mislukte, wisselden de clients geen publieke IP-adressen uit, maar private LAN-IP's. Dit leidde logischerwijs tot een mislukte verbinding over NAT.

De HTTPS-URL is op het moment van schrijven nog steeds online en bevat daadwerkelijk informatie: snatmap://snatmap.apple.com:5678

Ik heb toen een eigen eenvoudige webserver opgezet, dat bestand zelf gehost en het /etc/hosts-bestand van OS X aangepast om configuration.apple.com naar een IP-adres naar keuze te laten wijzen. Dit hielp echter niet. De SNATMAP-server van Apple reageert namelijk niet meer. Op dat moment liepen we vast, omdat we niet wisten hoe de SNATMAP-server precies werkte of wat iChat als antwoord verwachtte.

Enkele jaren later

In de zomer van 2026 besloten Methodius en ik het opnieuw te proberen, maar ditmaal met hulp van een LLM. Met onze eerdere netwerkcaptures konden we het LLM gebruiken om het videoconferentie-framework van iChat te reverse-engineeren. Zo kwamen we erachter hoe het verzoek aan de SNATMAP-server eruitziet en welk antwoord iChat verwacht. Op basis daarvan konden we een specificatiedocument voor het SNATMAP-protocol genereren.

Hoewel ik niet de kennis heb om iChat te decompileren en assembly-code te lezen, kon ik aan de hand van het door het LLM gegenereerde specificatiedocument leren hoe ik een eenvoudige UDP-server moest schrijven.

De allereerste server

Ik ben van beroep systems engineer en beheerder; ik installeer en configureer servers, maar ik heb er nooit zelf een geschreven. Deze SNATMAP-server bleek een uitstekend project om mee te oefenen.

Het protocol:

  • Communiceert via UDP op poort 5678.
  • Het request-pakket bevat vier velden in 16 bytes:
  • Type ("1" voor een verzoek)
  • Nonce (een willekeurig getal om een verzoek aan een antwoord te koppelen)
  • Client lokaal IP (niet gebruikt)
  • Client lokale poort (niet gebruikt)
  • Het response-pakket bevat vier velden in 16 bytes:
  • Type ("2" voor een antwoord)
  • Nonce (hetzelfde willekeurige getal als in het verzoek)
  • Extern IP van het UDP-verzoek
  • Externe poort van het UDP-verzoek

De resultaten testen

Omdat Methodius kinderen heeft en minder vrije tijd dan ik, moest ik een manier vinden om iChat over het internet alleen te testen. Aangezien ik geen twee aparte internetverbindingen heb, bouwde ik een "internet" in een labomgeving.

Dit realiseerde ik door twee NAT-routers (OpenWrt) als virtuele machines te draaien op een KVM-host (Proxmox), die verbonden waren via een plat netwerk dat als het "internet" fungeerde. Vervolgens sloot ik fysiek twee Macs aan op de KVM-host (via USB-netwerkadapters), waarbij de VM-routers hen IP-adressen toewezen in hun eigen private LAN achter een NAT. Op het "internet-netwerk" liet ik de Jabber- (ejabberd), web- (lighttpd) en SNATMAP-servers draaien in een Debian Linux VM.

Met deze opstelling kon ik snel testen en itereren.

Specificaties en broncode

Het specificatiedocument kan worden gebruikt om een eigen versie van de server te maken. De broncode is handmatig in Python geschreven op basis van dat document en is klaar voor gebruik op vrijwel elk besturingssysteem dat Python 3 ondersteunt.

Zelf hosten

Als je dit zelf wilt hosten, zorg dan voor een webserver die reageert op verzoeken aan configuration.apple.com en die het bestand snatmap.txt serveert via het pad: /configurations/macosx/ichat/1/snatmap.txt

In snatmap.txt moet de volgende tekst staan: snatmap://JOUWSERVERIP:5678

Vervang JOUWSERVERIP door het publieke IP-adres van de server waarop de SNATMAP-server draait.

De makkelijke manier

Je kunt ook gewoon mijn server gebruiken. Ik houd deze online voor de 1 tot 5 mensen ter wereld die nog steeds willen videobellen met deze antieke software.

Voeg op je oude Mac met OS X Leopard of Snow Leopard (mogelijk werkt het ook op oudere versies, maar dit is niet getest) het volgende toe aan je /etc/hosts-bestand:

157.230.2.213 configuration.apple.com

Laat de persoon die je wilt bellen hetzelfde doen. Daarna kun je op de groene belknop drukken!

Je hebt geen iSight nodig

Dat klopt! Je kunt zelfs een moderne Logitech-webcam gebruiken. Ik heb dit getest op OS X Leopard met een Logitech C920.

Het eindresultaat

Het is gelukt: Methodius en ik kunnen nu weer chatten over het echte internet met iChat AV. Veel plezier en fijne gesprekken!