Eine iOS IPv6-only-Kompatibilitätsprüfung auf dem Cloud Mac aufbauen

DevOps & CI/CD ·ca. 5 Min. Lesezeit

Eine iOS IPv6-only-Kompatibilitätsprüfung auf dem Cloud Mac aufbauen

Nach der Umstellung eines Mobilfunknetzes, Unternehmens-WLANs oder Testnetzes eines Netzbetreibers auf IPv6-only äußern sich die häufigsten Fehler nicht in einem vollständigen Verbindungsausfall. Typischer sind erfolgreiche Anmeldungen bei gleichzeitig fehlschlagenden Bilduploads, eine funktionierende erste Anfrage mit anschließendem Timeout beim erneuten Verbindungsaufbau oder ältere Schnittstellen, bei denen weiterhin eine IPv4-Adresse fest in der Konfiguration hinterlegt ist. Mit einem Cloud Mac lassen sich solche sporadischen Probleme in eine feste CI-Prüfung überführen: Bei jedem Merge werden Adressliterale gesucht, die Voraussetzungen für die DNS64-Auflösung geprüft, Netzwerktests ausgeführt und Fehlerartefakte archiviert.

Zuerst die Grenzen der Prüfung festlegen

IPv6-only-Kompatibilität bedeutet nicht, dass der Server ausschließlich AAAA-Einträge bereitstellen muss. Solange das Testnetz DNS64/NAT64 unterstützt, können Clients, die Domainnamen verwenden und die Namensauflösung dem System überlassen, weiterhin auf Dienste zugreifen, die nur über IPv4 erreichbar sind. Gefährlich wird es, wenn ein Client die systemeigene Auflösung umgeht, etwa indem er aufgelöste IPv4-Adressen zwischenspeichert, AF_INET erzwingt oder eine Adresse wie 192.0.2.10 direkt in die Anwendungskonfiguration schreibt.

Die Prüfung sollte in drei Ebenen aufgeteilt werden:

Ebene Prüfgegenstand Bei Fehlern aufbewahren
Statische Prüfung IPv4-Literale, Konstanten für Adressfamilien, manuell implementierte Sockets Dateiname und Zeilennummer
Umgebungsprüfung DNS, Standardroute, Auflösung der Zieldomain scutil-Ausgabe und Auflösungsergebnisse
Verhaltenstest Anmeldung, Upload, Wiederholungsversuche, Wiederherstellung langlebiger Verbindungen Testprotokolle und Ergebnispakete

Ein erfolgreicher ping ersetzt keine fachliche Abnahme. Anwendungen verwenden tatsächlich HTTPS, WebSocket oder Datei-Uploads. Anfragepfade, Timeout-Strategien und die Wiederverwendung von Verbindungen können dabei zu ganz unterschiedlichen Ergebnissen führen.

Das Repository auf IPv4-Annahmen prüfen

Führen Sie zunächst einen konservativen Scan im CI-Arbeitsverzeichnis aus. Der folgende Ausdruck sucht lediglich nach möglichen Fundstellen. Nicht jeder Treffer sollte automatisch als Fehler eingestuft werden, da Test-Fixtures, Dokumentation und Loopback-Adressen legitime Inhalte sein können.

set -euo pipefail

mkdir -p artifacts/ipv6
rg -n \
  --glob '*.{swift,m,mm,h,plist,json,yaml,yml,xcconfig}' \
  '([0-9]{1,3}\.){3}[0-9]{1,3}|AF_INET([^6]|$)|sockaddr_in([^6]|$)' \
  . | tee artifacts/ipv6/ipv4-candidates.txt

if rg -n \
  --glob 'Sources/**' \
  --glob 'Config/**' \
  'https?://([0-9]{1,3}\.){3}[0-9]{1,3}' .; then
  echo "Production configuration contains an IPv4 URL" >&2
  exit 1
fi

Die Trefferliste sollte einmal manuell klassifiziert werden. Zulässige Einträge kommen anschließend in eine kommentierte Allowlist. Schließen Sie nicht einfach das gesamte Verzeichnis Tests aus, denn auch Hilfscode für Tests kann später in die produktive Netzwerkschicht übernommen werden. Bei Wrappern in C oder Objective-C ist besonders darauf zu achten, ob ai_family für getaddrinfo auf AF_UNSPEC gesetzt ist. Eine feste Adressfamilie sollte nur verwendet werden, wenn ausdrücklich genau eine Adressfamilie erforderlich ist.

Fehlerhafte Korrekturen vermeiden

IPv4-Adressen dürfen weder mechanisch in IPv4-mapped IPv6-Adressen umgeschrieben noch durch ein selbst zusammengesetztes NAT64-Präfix ergänzt werden. Das Präfix hängt vom jeweiligen Netzwerk ab; ein fest codierter Wert funktioniert nach einem Netzwerkwechsel nicht mehr. Speichern Sie stattdessen den Domainnamen und lassen Sie den Systemresolver beim Verbindungsaufbau die aktuell verfügbaren Adressen ermitteln.

DNS64-Bedingungen als Vorabprüfung einrichten

Zeichnen Sie vor Beginn der Tests den Netzwerkstatus auf, damit eine ungeeignete Umgebung nicht zu zahlreichen Fehlalarmen führt. Die Ausführungsknoten des Cloud Mac sollten das vom Team vorbereitete, kontrollierte DNS64/NAT64-Netz verwenden. Das CI-Skript prüft lediglich die Voraussetzungen und darf die Systemnetzwerkkonfiguration nicht erst während des Jobs ändern.

set -euo pipefail

OUT="artifacts/ipv6"
mkdir -p "$OUT"

scutil --dns > "$OUT/scutil-dns.txt"
route -n get default > "$OUT/default-route.txt" 2>&1 || true
dscacheutil -q host -a name api.test.example \
  > "$OUT/target-resolution.txt"

if ! grep -Eq 'ipv6_address|ip_address' "$OUT/target-resolution.txt"; then
  echo "Target hostname did not resolve in the test environment" >&2
  exit 2
fi

Die Testdomain sollte zu einer kontrollierten Umgebung des eigenen Teams gehören und eine stabile Health-Check-Antwort ohne vertrauliche Informationen liefern. Verwenden Sie keine öffentliche Website als Abhängigkeit dieser Prüfung. Externe Ratenbegrenzungen, Zertifikatsänderungen oder regionale Richtlinien würden die Deterministik der Build-Ergebnisse beeinträchtigen.

Tatsächliches Verhalten mit URLSession prüfen

Die Netzwerktests müssen sowohl den erfolgreichen Erstzugriff als auch die Wiederherstellung nach einem Fehler abdecken. Für Anfragen sind begrenzte Timeouts festzulegen. Die Basis-URL muss per Dependency Injection übergeben werden, damit auch der Testcode keine Adresse fest einprogrammiert.

import XCTest

final class IPv6ReadinessTests: XCTestCase {
    func testHealthEndpointReturnsExpectedStatus() async throws {
        let value = try XCTUnwrap(
            ProcessInfo.processInfo.environment["TEST_BASE_URL"]
        )
        let baseURL = try XCTUnwrap(URL(string: value))
        let url = baseURL.appending(path: "health")

        let configuration = URLSessionConfiguration.ephemeral
        configuration.timeoutIntervalForRequest = 15
        configuration.timeoutIntervalForResource = 30

        let session = URLSession(configuration: configuration)
        let (_, response) = try await session.data(from: url)
        let http = try XCTUnwrap(response as? HTTPURLResponse)

        XCTAssertEqual(http.statusCode, 200)
    }
}

Legen Sie bei der Ausführung Testplan, Simulatormodell und Ergebnisverzeichnis fest:

set -o pipefail

xcodebuild test \
  -workspace App.xcworkspace \
  -scheme AppNetworkTests \
  -testPlan IPv6Readiness \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -resultBundlePath artifacts/ipv6/IPv6Readiness.xcresult \
  TEST_BASE_URL='https://api.test.example/' \
  | tee artifacts/ipv6/xcodebuild.log

Wenn die Anwendung Uploads und langlebige Verbindungen nutzt, ergänzen Sie Tests für den Upload kleiner Dateien, exponentielles Backoff nach Verbindungsabbrüchen sowie die Wiederherstellung nach dem Wechsel zwischen Vorder- und Hintergrund. Assertions sollten fachliche Ergebnisse prüfen und nicht von lokalisierten Fehlermeldungen abhängen.

Bei Fehlern aussagekräftige Diagnoseartefakte aufbewahren

Nach einer fehlgeschlagenen Prüfung sollten mindestens die Ergebnisse des statischen Scans, der DNS-Status, die Auflösung des Zielhosts, das xcodebuild-Protokoll und das xcresult aufbewahrt werden. Protokolle dürfen keine Token, Anfrageinhalte oder vollständigen Autorisierungsheader enthalten. Falls Anfrageinformationen protokolliert werden müssen, beschränken Sie sich auf die Methode, einen anonymisierten Pfad, den Statuscode, die Anzahl der Wiederholungsversuche und die Fehlerdomain.

Für die Fehlersuche kann eine feste Reihenfolge verwendet werden:

  1. Prüfen Sie, ob die Umgebungsprüfung erfolgreich war und die Zieldomain vom System aufgelöst wurde.
  2. Kontrollieren Sie, ob die fehlgeschlagene Anfrage einen Domainnamen und nicht eine zwischengespeicherte, bereits aufgelöste Adresse verwendet.
  3. Prüfen Sie, ob eine zugrunde liegende Bibliothek die Adressfamilie auf AF_INET beschränkt oder selbst einen IPv4-Socket erstellt.
  4. Vergleichen Sie den ersten Verbindungsaufbau mit dem erneuten Verbindungsaufbau und stellen Sie sicher, dass beide denselben Auflösungsmechanismus verwenden.
  5. Testen Sie die kritischen Abläufe erneut auf einem physischen Gerät in einem kontrollierten DNS64/NAT64-Netz.

Die Prüfung im Simulator übernimmt häufige Regressionstests, während das physische Gerät zur abschließenden Kontrolle vor einer Veröffentlichung dient. Sind diese Aufgaben klar getrennt, benötigen alltägliche Builds keine manuellen Eingriffe. Anhand der archivierten Artefakte kann das Netzwerkteam zudem feststellen, ob die Ursache in der Namensauflösung, im Verbindungsaufbau oder in der Wiederholungslogik der Anwendung liegt. Solange die Ausführungsknoten auf VPSGit dieselbe Toolchain, denselben Testplan und dieselben Umgebungsvariablen verwenden, bleibt die Prüfung dauerhaft reproduzierbar. Eine Testumgebung muss dann nicht erst nach einer Fehlermeldung von Benutzern kurzfristig nachgebaut werden.

Häufig gestellte Fragen

Garantieren Domainnamen die Kompatibilität mit IPv6-only?

Nein. Der Dienst muss über DNS64/NAT64 erreichbar sein, und die App darf weder IPv4-Adressen zwischenspeichern noch AF_INET erzwingen oder die Systemauflösung umgehen.

Reichen Tests im iOS-Simulator aus?

Der Simulator eignet sich für kontinuierliche Regressionstests. Vor der Veröffentlichung sollten Anmeldung, Uploads, Rückrufe und Verbindungswiederherstellung zusätzlich auf einem Gerät in einem kontrollierten DNS64/NAT64-Netz geprüft werden.

Exklusiver physischer Knoten

Konfigurieren Sie einen Cloud-Mac für Ihren nächsten Build- oder Inferenz-Job

Wählen Sie aus drei Apple-Silicon-Konfigurationen, sechs Knoten und festen Laufzeiten. Die tatsächliche Verfügbarkeit wird in Echtzeit in der Konsole angezeigt.

Cloud-Mac konfigurieren