Как построить проверку совместимости iOS с IPv6-only в облачном Mac

DevOps и CI/CD ·~5 мин чтения

Как построить проверку совместимости iOS с IPv6-only в облачном Mac

После перехода мобильной сети, корпоративной Wi-Fi-сети или тестовой среды оператора на IPv6-only чаще всего возникает не полная потеря доступа к сети. Гораздо типичнее ситуации, когда вход выполняется успешно, но загрузить изображение не удаётся, первый запрос проходит нормально, а повторное подключение завершается по тайм-ауту, либо старый интерфейс по-прежнему содержит жёстко заданный IPv4-адрес в конфигурации. Облачный Mac позволяет превратить такие нерегулярные сбои в постоянную проверку: при каждом слиянии сканировать литералы адресов, проверять условия разрешения DNS64, запускать сетевые тесты и архивировать данные о сбоях.

Сначала определите границы проверки

Совместимость с IPv6-only не означает, что сервер обязан предоставлять исключительно записи AAAA. Если в тестовой сети доступны DNS64/NAT64, клиент, который обращается по доменному имени и использует системный резолвер, по-прежнему сможет подключаться к сервисам, доступным только по IPv4. Настоящую опасность представляют клиенты, обходящие системный процесс разрешения имён: например, кэширующие полученный IPv4-адрес, принудительно использующие AF_INET или сохраняющие адреса наподобие 192.0.2.10 в рабочей конфигурации.

Проверку рекомендуется разделить на три уровня:

Уровень Что проверяется Что сохраняется при сбое
Статический анализ IPv4-литералы, константы семейств адресов, сокеты, созданные вручную Имена файлов и номера строк
Предварительная проверка среды DNS, маршрут по умолчанию, разрешение целевого домена Вывод scutil и результаты разрешения
Поведенческие тесты Вход, загрузка файлов, повторные попытки, восстановление длительных соединений Журналы тестов и пакет результатов

Не используйте успешный ping как подтверждение работоспособности приложения. В реальности приложение работает с HTTPS, WebSocket или загрузкой файлов, а пути запросов, правила тайм-аутов и повторное использование соединений могут приводить к другим результатам.

Поиск предположений об IPv4 в репозитории

Сначала выполните консервативное сканирование в рабочей области CI. Приведённое ниже выражение предназначено только для поиска потенциальных проблем. Не следует автоматически считать дефектом каждое совпадение: тестовые фикстуры, документация и loopback-адреса могут быть допустимыми.

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

Список найденных кандидатов нужно один раз классифицировать вручную, после чего добавить допустимые элементы в снабжённый комментариями белый список. Не исключайте каталог Tests целиком: вспомогательный тестовый код также может быть скопирован в рабочий сетевой слой. В обёртках на C или Objective-C особое внимание уделите тому, использует ли поле ai_family функции getaddrinfo значение AF_UNSPEC. Фиксировать одно семейство адресов следует только тогда, когда это явно требуется.

Избегайте ошибочных исправлений

Не преобразовывайте IPv4-адреса механически в IPv4-mapped IPv6 и не формируйте префикс NAT64 самостоятельно. Префикс определяется текущей сетью, поэтому жёстко заданное значение перестанет работать при подключении к другой сети. Правильный подход — сохранять доменное имя и при установлении соединения позволять системному резолверу возвращать доступный в текущей сети адрес.

Сделайте условия DNS64 предварительной проверкой

До начала тестирования зафиксируйте состояние сети, чтобы не получить множество ложных срабатываний, если сама среда не соответствует требованиям. Исполнительный узел облачного Mac должен использовать заранее подготовленную командой контролируемую сеть DNS64/NAT64. Скрипт CI только проверяет необходимые условия и не изменяет временно системные сетевые настройки во время задания.

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

Тестовый домен должен находиться в контролируемой командой среде и возвращать стабильный ответ проверки состояния без конфиденциальных данных. Не используйте публичные веб-страницы как зависимость этой проверки: внешние ограничения частоты запросов, изменения сертификатов или региональные правила лишат результаты сборки детерминированности.

Проверка реального поведения с помощью URLSession

Сетевые тесты должны охватывать два сценария: успешный первый запрос и восстановление после сбоя. Для запросов необходимо задавать конечный тайм-аут, а базовый URL передавать через внедрение зависимостей, чтобы тестовый код снова не содержал жёстко заданный адрес.

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)
    }
}

При запуске зафиксируйте план тестирования, модель симулятора и каталог результатов:

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

Если приложение поддерживает загрузку файлов и длительные соединения, добавьте тесты загрузки небольшого файла, экспоненциальной задержки повторных попыток после разрыва соединения и восстановления после перехода между фоновым и активным режимами. Проверки должны оценивать бизнес-результат и не зависеть от локализованного текста ошибок.

Сохраняйте диагностические данные при сбое

При сбое проверки необходимо сохранить как минимум результаты статического анализа, состояние DNS, результаты разрешения целевого имени, журнал xcodebuild и xcresult. Не записывайте в журналы токены, тела запросов или полные заголовки авторизации. Если сведения о запросе всё же нужны, сохраняйте только метод, обезличенный путь, код состояния, количество повторных попыток и домен ошибки.

Последовательность диагностики можно зафиксировать следующим образом:

  1. Убедитесь, что предварительная проверка среды пройдена, а целевой домен разрешается системными средствами.
  2. Проверьте, использует ли завершившийся сбоем запрос доменное имя, а не закэшированный после разрешения адрес.
  3. Убедитесь, что низкоуровневая библиотека не ограничена значением AF_INET и не создаёт IPv4-сокеты самостоятельно.
  4. Сравните пути первого и повторного подключения и убедитесь, что они используют одинаковую стратегию разрешения имён.
  5. Повторно проверьте ключевые сценарии на физическом устройстве в контролируемой сети DNS64/NAT64.

Проверка на симуляторе отвечает за частое регрессионное тестирование, а физическое устройство — за подтверждение перед выпуском. Разделение этих задач позволяет не привязывать повседневные сборки к ручным операциям, а сетевая команда может по архивным данным определить, находится ли проблема на уровне разрешения имён, установки соединения или бизнес-логики повторных попыток. Исполнительным узлам VPSGit достаточно поддерживать одинаковые версии инструментов, планы тестирования и переменные среды, чтобы эта проверка воспроизводилась постоянно, а не создавалась заново после сообщений пользователей.

Часто задаваемые вопросы

Гарантирует ли использование доменных имён работу в IPv6-only?

Нет. Сервер должен быть доступен через DNS64/NAT64, а приложение не должно сохранять IPv4-адреса, принудительно использовать AF_INET или обходить системный резолвер.

Достаточно ли тестирования только в симуляторе iOS?

Симулятор подходит для постоянной регрессии, но перед выпуском нужна проверка на устройстве в контролируемой сети DNS64/NAT64 для входа, загрузок, обратных вызовов и восстановления соединений.

Выделенный физический узел

Настройте облачный Mac для следующей сборки или задачи машинного обучения

Выберите одну из трёх конфигураций Apple Silicon, шести узлов и фиксированных сроков аренды. Фактическая доступность отображается в консоли в реальном времени.

Настроить облачный Mac