Емулятор Android і VPN на хості: знімок DNS і NAT
Гость сидить за NAT емулятора і зберігає список DNS, скопійований під час завантаження. Підніміть тунель до завантаження, а потім перевірте розв'язання імен зсередини гость.
Коли емулятор не може дістатися до сервера збірки, який браузер на хості відкриває без проблем, корисне питання не в тому, чи працює VPN. Питання в тому, якого з двох механізмів бракує гостьовій системі. Віртуальний пристрій запускає власний мережевий стек за NAT емулятора, а його список резолверів — це копія, знята під час завантаження, тому тунель, піднятий пізніше, змінює шлях хоста, але не змінює те, про що запитує гость. Розуміння цих двох шарів пояснює майже кожен варіант цієї проблеми.
Гость — це окремий стек за фіксованим NAT
Мережа QEMU в режимі користувача розміщує гость на 10.0.2.15 із шлюзом на 10.0.2.2 та службою DNS на 10.0.2.3–10.0.2.6. Вихідний трафік гость не пересилається ядром хоста; він перетворюється на сокети на боці хоста, по одному на кожне з'єднання гость, і ці сокети виходять з адресного простору хоста. Тому з'єднання гость успадковує рішення маршрутизації хоста в момент створення, і тому в таблиці маршрутів гость немає запису, який називав би ваш тунель.
Той самий механізм дає гость корисний вихід. 10.0.2.2 — це псевдонім інтерфейсу loopback хоста, тому служба, що слухає 127.0.0.1 на ноутбуці, доступна з гость за цією адресою. Усе, що клієнт відкриває лише на loopback, можна дістати цим шляхом, і це основа описаної нижче схеми з проксі.
Чого гость не може — це спостерігати мережу хоста так, ніби вона є його простором імен. Немає мосту, немає спільної таблиці маршрутів і немає успадкованого резолвера; є лише служба NAT, що приймає його пакети, і знімок, який зробив завантажувач під час старту віртуального пристрою.
DNS — це знімок, а не жива картина
Під час запуску емулятор читає список резолверів хоста і передає гость до чотирьох серверів, відкритих на адресах 10.0.2.3–10.0.2.6. Якщо тунель у той момент був опущений, знімок містить той публічний резолвер, яким користувався ноутбук, і гость продовжує питати його все своє життя. Публічні імена розв'язуються, внутрішні — ні, і всі симптоми вказують на VPN, тоді як справжнє застаріле значення — це список резолверів, знятий за кілька хвилин до підняття тунелю.
Тому виправлення порядку — не фольклор. Спершу підключіть тунель, потім перезапустіть емулятор і віддайте перевагу холодному завантаженню перед відновленням знімка, бо образ швидкого завантаження може повернутися з раніше збереженим станом резолверів і маршрутів. Якщо треба побачити, що гость використовує зараз, питайте пристрій, а не хост:
adb shell dumpsys connectivity | grep -i -A2 dns
adb shell ping -c 1 build.internal.exampleЕмулятор також приймає явний резолвер під час запуску, що корисно, коли ви точно знаєте, який сервер має використовувати гость, і небезпечно, коли цей сервер публічний:
emulator -avd Pixel_API_34 -dns-server 203.0.113.53Публічний резолвер не має копії внутрішньої зони, тому прив'язка одного перетворює проблему порядку на постійну відмову. Якщо профіль просуває приватний DNS, дозвольте тунелю його постачати і холодно завантажте гость замість того, щоб жорстко прописувати адресу.
Маршрутизація йде за хостом у момент з'єднання
Оскільки з'єднання гость стають сокетами хоста, рішення про маршрутизацію ухвалюється під час створення сокета. Піднятий до запиту тунель означає, що запит виходить через тунель з урахуванням маршрутів профілю. Профіль split-tunnel, що несе лише вибрані префікси, охоче залишить вашу приватну підмережу ззовні, тому доступність хоста — це гіпотеза про гость, а не результат. Наявні з'єднання гость зберігають шлях, з яким створені, тому клієнт, що перепідключається, не завжди виправляє завантаження, що застрягло в емуляторі.
Перевірка належить інтерфейсу хоста, а не статистиці гость:
sudo tcpdump -ni tun0 'host 203.0.113.10'Якщо запит гость з'являється на інтерфейсі тунелю, маршрутизація працює, і проблема вище. Якщо він з'являється на фізичному інтерфейсі, профіль не покриває цей префікс, і жодне переналаштування на боці гость цього не змінить.
Коли клієнт пропонує лише локальний проксі
Деякі комерційні клієнти взагалі не створюють системного тунелю. Вони відкривають HTTP- або SOCKS-слухач на 127.0.0.1 і очікують, що застосунки ним користуватимуться. Гость не бачить цей сокет напряму, але емулятору можна сказати його використовувати — або через розширені елементи керування (Settings, далі Proxy, ручний режим, хост 127.0.0.1 і порт, який друкує клієнт), або під час запуску:
emulator -avd Pixel_API_34 -http-proxy http://127.0.0.1:8080Скопіюйте порт із вікна клієнта; вгаданий порт тихо відмовляє і виглядає як зламаний тунель. Пам'ятайте, що це покриває: налаштування HTTP-проксі поважають застосунки, які знають про проксі, а сирі сокети повністю його ігнорують. Якщо навантаження — це нативний бінарник, що відкриває власні з'єднання, шлях через проксі не еквівалентний тунелю, і порівняння треба робити явно.
Доведіть результат зсередини гость
Розділіть розв'язання імен і маршрутизацію двома тестами в одній сесії. Ім'я, що не розв'язується, поки числова адреса відповідає, — це проблема знімка DNS, і рішення — порядок або явний резолвер. Якщо не працює обидва, це вказує на маршрутизацію або політику, і наступна перевірка — чи застосунок працює в робочому профілі з власними мережевими обмеженнями.
Насамкінець, знайте, на якому гость ви тестуєте. Дуже старі образи емулятора постачалися без підтримки tun, потрібної клієнту VPN на боці гость, тому жоден профіль там не міг працювати; поточні образи її мають. Клієнт, що не працює на поточному образі, — це проблема клієнта або профілю, і перебудова тунелю хоста результату не змінить.