Minulou středu oznámila společnost Cloudflare spuštění služby Warp. Jde o rozšíření funkce stávající mobilní aplikace 1.1.1.1 pro Android a iOS, která dosud řešila pouze šifrování DNS provozu, o plnohodnotnou VPN službu. Ta si zachovává jednoduchost obsluhy a je přátelská k mobilním zařízením. Aplikaci dominuje jediný přepínač sloužící k zapnutí či vypnutí funkce VPN, žádné další nastavení není k dispozici. Cloudflare také tvrdí, že se stará o ochranu soukromí: pravidelně čistí logy, neshromažďuje žádné údaje identifikující konkrétní uživatele a dokonce ani nepožaduje osobní údaje při instalaci aplikace.
Nás na technickém serveru zajímají zejména detaily technického řešení služby. O nich se podrobněji rozepsal Zack Bloom. Služba je postavena na moderním VPN protokolu Wireguard. Ten přenáší šifrované datagramy protokolu IP uvnitř UDP paketů. Je k dispozici ve formě velice efektivní implementace přímo v linuxovém jádře, samotný protokol je ale možné implementovat i jako jednoduchou aplikaci. Tento postup zvolili i v Cloudflare a vznikl tak projekt BoringTun, napsaný v moderním jazyce Rust.
Komplikace s anycastem
Každý šifrovaný tunel potřebuje dva konce, jeden místní, druhý vzdálený, kde se šifrovaná data rozšifrovávají a dále odbavují směrem do internetu. Zatímco v případě klasické VPN jde o jeden konkrétní koncentrátor, v případě služby Warp je vzdálená strana provozována na anycastu. To znamená, že IP adresy, ke kterým se připojují Warp klienti, jsou zároveň dostupné v přibližně dvou stovkách datacenter Cloudflare po celém světě.
Celá situace je ještě víc komplikovaná tím, že v každém datacentru není jen jeden server; je jich tam spousta. K rozdělování zátěže mezi jednotlivé servery se nepoužívají žádné load balancery, ale běžné směrovače s funkcí ECMP. Jednotlivé servery ohlašují směrovacím protokolem dostupnost cílové adresy, například 1.1.1.1.
Má-li směrovač k dispozici více cest k cílové adrese a všechny cesty mají stejnou cenu, rozkládá jednotlivé toky do jednotlivých linek. Nedělá to ale náhodně, jako klíč počítá u každého datagramu hash zdrojové a cílové adresy, transportního protokolu a případně zdrojového a cílového portu. Tímto způsobem je zajištěno, že všechny datagramy týkající se jedné relace, například TCP spojení, budou doručovány totožnému serveru.
Pro většinu situací tento způsob rozkládání zátěže funguje velmi dobře, zvláště jde-li o krátkodobé relace, což odpovídá charakteru HTTP a DNS provozu. I v takovém případě však existují mezní stavy, kdy podobný způsob zapojení způsobuje problémy. Jedním z nich byl problém s objevováním MTU cesty.
Použití Wireguardu v obdobné infrastruktuře je něco úplně jiného. Relace Wireguardu trvá velmi dlouho – celou dobu, kdy je funkce Warp zapnuta. Přitom pokud není třeba přenášet data, žádná se nepřenáší; to je výhodné i s ohledem na výdrž baterie mobilních zařízení. Jenže v tom je právě potíž. Pokud je klient za překladačem adres (NATem), což je případ drtivé většiny mobilních telefonů po celém světě, dojde po určité době, kdy se žádné UDP zprávy nepřenáší, k vyčištění záznamů v tabulce překladů překladače adres. Následující odchozí datagram pak může získat zcela jinou přeloženou zdrojovou IP adresu a číslo portu.
Dorazí-li takový datagram na směrovač s funkcí ECMP, je velmi pravděpodobné, že bude doručen na jiný server než ten, na kterém je původní tunel zakončen. Tomu se zprávu nepodaří rozšifrovat, takže ji zahodí. Podle původních předpokladů k takovým problémům nemělo docházet příliš často a klient je případně vyřeší automatickým restartem spojení po nečinnosti. Během vývoje aplikace se ale ukázalo, že naopak jde o velmi častý případ, který je třeba řešit lépe.
Aktuální řešení spočívá ve využití tří rezervovaných oktetů v záhlaví protokolu Wireguard k identifikaci serveru, kterému daná relace patří. Jde o jednoduché rozšíření, které zachovává omezenou interoperabilitu se stávajícími implementacemi Wireguardu. Na straně serverů Cloudflare se tyto tři oktety používají k dosměrování provozu na server, na kterém probíhá daná relace. Díky tomu je spojení udržováno i v případě, kdy klient mění zdrojové adresy a čísla portů.
Warp a Warp+
Kromě služby Warp je k dispozici i placená verze Warp+. Rozdíl mezi nimi spočívá v odbavování VPN provozu do internetu. Bezplatná verze odbavuje data přímo z datacentra, do kterého je klient připojen. Služba Warp+ proti tomu využívá páteřní síť Argo, prostřednictvím které je provoz přesměrován do datacentra které je nejblíže cílovému serveru a teprve odtamtud je odbaven do veřejného internetu. Díky tomu je údajně možné získat až o 30 procent vyšší rychlost, zejména v případech, kdy by cesta veřejným internetem narazila na přetížené spoje.
Protože se pro každé spojení samostatně rozhoduje, které datacentrum bude nejvhodnější pro odbavení provozu, není neobvyklé, že se mění i veřejná IP adresa, pod kterou klient vystupuje.
Zvláštní adresování
Po aktivaci aplikace 1.1.1.1 se v operačním systému Android objeví nové rozhraní tun0
. Na obou zařízeních, na kterých jsem službu testoval, měla lokální strana IPv4 adresu 172.16.0.2, vzdálená strana pak adresu 172.16.0.1. Zdá se tedy, že implementace Wireguardu na straně serveru nějakým způsobem přímo v sobě řeší tuto mnohonásobnou kolizi IP adres. Není to zřejmě velký problém, každý klient je unikátně identifikován především svým veřejným klíčem, použití unikátní IPv4 adresy pro každého klienta by navíc hrozilo vyčerpáním zásob privátních IPv4 adres.
V Cloudflare mají už několik let pravidlo, že každá služba musí podporovat IPv6. Služba Warp není výjimkou a umožní svým uživatelům získat IPv6 konektivitu i v případě, že hostitelská síť IPv6 nenabízí, jak dokládá tento snímek známého testu IPv6:
Zvláštní je ovšem varování zhruba uprostřed: „Váš prohlížeč má funkční IPv6 adresu, ale vyhýbá se jejímu použití. To je znepokojující.“ Na Twitteru se to pokoušel vysvětlovat John Graham-Cumming použitím algoritmu Happy Eyeballs, tedy automatickým přepnutím z IPv6 na IPv4, pokud se IPv6 ukáže jako pomalé. To by skutečně mohla být příčina, realita je ale mnohem zajímavější.
IPv6 nebude nikdy preferováno
Ve skutečnosti je na vině velmi kreativní přístup ke zpřístupnění IPv6 konektivity pro aplikaci Warp. Na rozdíl od IPv4 má každý klient přidělenu unikátní IPv6 adresu. Nejde ale o globální unikátní adresu, která je vidět ve snímku obrazovky výše, ale o unikátní lokální adresu z prefixu fd01:5ca1:ab1e::/48
. Podle RFC 4193 musí být globální ID použité v unikátním lokálním prefixu náhodně generované v souladu s BCP 106. Zajímalo by mě, kolik muselo být provedeno náhodných výběrů, než bylo vybráno náhodné číslo připomínající slovo scalable.
Mezi klientem a internetem je tedy i pro IPv6 vložen překladač adres, resp. transparentní proxy server, který lokální adresu přeloží na globální. Takové řešení je velmi neobvyklé a má jednu zásadní nevýhodu: IPv6 nebude nikdy preferováno. Mohou za to pravidla výběru cílové adresy podle RFC 6724. Hned druhé pravidlo v pořadí zní: „Preferuj adresy shodného dosahu.“ Vzhledem k tomu, že lokální adresa v roli zdrojové má jiný dosah než cílová globální adresa, bude před použitím IPv6 preferována jakákoli jiná adresa, včetně IPv4 adresy. IPv6 tak bude použito pouze v případě, že není žádná jiná možnost, například pro přístup na stránky www.nebezi.cz.
Takové řešení se mimo porušení end-to-end principu z důvodu překladu adres také negativně podepíše na statistikách používání IPv6, zejména u poskytovatelů obsahu. Dosud platilo, že je-li k dispozici IPv6 na obou stranách spojení, je spojení po IPv6 preferováno, protože se má za to, že spojení pomocí IPv6 je levnější (například proto, že nepotřebuje překladače adres). Při použití aplikace Warp se sice pravděpodobně použije IPv6 pro sestavení vlastního šifrovaného tunelu, provoz uvnitř tunelu ale půjde téměř výhradně po IPv4. Poskytovatelé obsahu tak budou mít zkreslené statistiky o tom, jaké procento uživatelů má IPv6 k dispozici.
Dalo se to řešit jinak?
Očekávané řešení zpřístupnění IPv6 by spočívalo v použití globálních unikátních adres, které by byly bez překladu přímo odbavovány na internetu. V takovém případě by základní služba Warp musela používat IPv6 rozsah směrovaný do daného datacentra na daný konkrétní server. Služba Warp+ by pak mohla používat jiný IPv6 rozsah, který by byl prostřednictvím anycastu obsluhován ve všech datacentrech. Kterékoli datacentrum by pak páteřní sítí dosměrovalo příchozí provoz do datacentra, ke kterému je připojen VPN klient. Nebylo by ale možné vyloučit asymetrii směrování, takže by často docházelo k situacím, kdy by každý směr procházel jiným datacentrem.
Zřejmě z toho důvodu je použití IPv6 NATu, potažmo proxy serverů, pro Cloudflare jednodušší. Problém s nepreferencí IPv6 by se dal vyřešit i úpravou nastavení klienta (na Linuxu v souboru /etc/gai.conf
), jenže takové nastavení s velkou pravděpodobností nebude možné na Androidu a iOS provést. Další velmi neelegantní, ale nepochybně funkční metodou by bylo místo unikátních lokálních adres použít libovolné globální adresy, ale přitom zachovat překlad adres. End-to-end princip by zůstal porušen, ale algoritmus výběru adresy by to nepoznal a nadále tak preferoval IPv6 před IPv4.