Ping до партнёра по туннелю IPv6 не проходит? Проверьте адрес ::
Идентификатор интерфейса из одних нулей — это anycast маршрутизатора подсети, а не хост. Назначьте ::1 и ::2, маршрутизируйте префикс и проверьте multicast, прежде чем винить маршруты.
Один конец вашего туннеля IPv6 пингует другой, и всегда отвечает только одно направление. Интерфейс поднят, маршрут выглядит правильно, и ничто в журнале это не объясняет. Назначенный вами адрес — это anycast-адрес маршрутизатора подсети, который вовсе не является адресом хоста, и на канале с двумя конечными точками у него ровно одна цель доставки: отправитель. Никакое значение тайм-аута это не исправит, потому что адрес делает не то, что вы думаете.
Симптом, который указывает на адрес
Каждый хост на канале отвечает, кроме того, чей идентификатор интерфейса состоит из одних нулей. Пакет, адресованный такой форме, по определению доставляется маршрутизатору в подсети, поэтому на туннеле точка-точка он возвращается к машине, которая его отправила. С дальнего конца это читается как недоступный партнёр; с ближнего — как тишина. Замените идентификатор на другой из того же префикса, и симптом исчезнет без каких-либо других изменений, и это то подтверждение, которое нужно получить до того, как трогать маршруты.
Идентификатор из одних нулей зарезервирован как anycast
RFC 4291 сохраняет идентификатор интерфейса из одних нулей как anycast-адрес маршрутизатора подсети, поэтому /64 вроде 2001:db8:4a::/64 не содержит ни одного пригодного хоста по адресу 2001:db8:4a::. Резервирование оправдано: объявления маршрутизатора и обнаружение соседей адресуют именно эту форму, а маршрутизатор отвечает за обслуживаемый префикс. Назначение этого значения конечной точке туннеля даёт листу роль маршрутизатора, и поэтому ничего не возвращается. Любой другой идентификатор в префиксе работает как хост, так что исправление обычно — одна цифра.
Относитесь к резервированию как к роли, которую вы не вправе занимать с конечной точки туннеля, а не как к странности, которую обходят маршрутом.
Назначьте адреса хостов и маршрутизируйте префикс
Выберите ::1 и ::2 для двух концов, добавьте один командой ip -6 addr add 2001:db8:4a::2/64 dev tun0, а затем маршрутизируйте удалённый префикс вместо попытки его адресовать. Маршрут для 2001:db8:4a::/64 через туннель делает дальнюю сторону достижимой; сам адрес только настраивает локальный интерфейс.
Для полного туннеля есть третий шаг — маршрут по умолчанию для глобального unicast через устройство, что является эквивалентом IPv6 отправки всего в туннель. Пропустите его, и IPv6 продолжит использовать физический канал, пока IPv4 идёт внутри туннеля, так что хост утекает именно тот трафик, который вы считали покрытым. Подтвердите командой ip -6 route get 2001:4860:4860::8888 и прочитайте, какое устройство она называет, вместо того чтобы предполагать ответ.
Multicast отклоняется до маршрутизации
Android проверяет адреса и маршруты для VpnService.Builder через LinkAddress, и этот конструктор отклоняет multicast сразу. Дайте ему multicast-префикс как маршрут, и результатом будет ошибка плохих параметров LinkAddress, а не маршрут, что является ответом проверки, а не сети. Отказ соответствует среде: устройство tun точка-точка не имеет multicast на канальном уровне, поэтому групповой маршрут на нём не имеет модели доставки, которую можно установить. Групповые адреса создаёт и потребляет сам стек, а не настраивают вручную.
Адреса IPv6 all-nodes и solicited-node подпадают под то же правило. Интерфейс несёт их потому, что стек положил их туда, а не потому, что так задумала политика.
Что туннель может нести вместо этого
Перенос обнаружения multicast через туннель требует уровня, понимающего членство в группах: моста TAP, представляющего сегмент Ethernet, ретранслятора на уровне приложения или протокола маршрутизации, которому явно сказано, каким партнёрам реплицировать. Ничего этого нет в модели VpnService, где приложение читает и пишет пакеты и не имеет вызова, который присоединяется к группе для туннеля. Либо добавьте компонент, понимающий группы, либо уберите требование из проекта.
Unicast, напротив, не требует ничего сверх адресов и маршрутов выше, поэтому обычно ожидается, что туннели его понесут, а затем их винят, когда протокол обнаружения сбоит.
Три проверки, прежде чем что-либо назначать
Убедитесь, что адрес не является anycast-формой, что он не multicast и что префикс маршрутизирован, а не просто назначен устройству. Затем отправьте тест на адрес назначения, который является настоящим хостом, потому что ping по anycast-адресу измеряет отправителя и ничего не говорит о пути. Держите эти три проверки в записи об изменениях, чтобы следующее развёртывание не открывало их заново.
Маршрут, который платформа никогда не устанавливала, нельзя отладить более долгим ожиданием, а адрес, который никогда не был хостом, нельзя исправить лучшим ping.