IPv6 only síť již používáme na všechny naše produkty a musíme říct, že aktualizovaný software je na IPv6 only nasazení celkem dobře připraven a nenastává velmi často, že bychom řešili nějakou zapeklitou situaci.
Tentokrát jsme se ale setkali se situací, kde jsme se nakonec museli podívat do zdrojových kódů jedné knihovny, abychom našli zdroj našich starostí.
Přestože většinu serverů nasazujeme jako IPv6 only, tak na serverech je stále dostupný IPv4 loopback a vypnutí IPv4 nelze udělat tak jednoduše jako vypnutí IPv6. Síťová konfigurace takového serveru pak vypadá následovně:
root@test:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
48: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:16:3e:62:e8:9f brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 2001:db8:0:0:216:3eff:fe62:e89f/64 scope global mngtmpaddr dynamic
valid_lft 86103sec preferred_lft 14103sec
inet6 fe80::216:3eff:fe62:e89f/64 scope link
valid_lft forever preferred_lft forever
Server tedy má jednu globální IPv6 adresu na rozhraní ens3 a na loopbacku jak IPv4, tak IPv6 adresu.
Na server jsme nainstalovali memcached server a protože se jednalo o testovací server, tak jsme jej nechali v defaultní konfigurací.
Naslouchal tedy jen na IPv4 loopacku - čili na adrese 127.0.0.1
.
root@test:~# ss -at 'sport = 11211'
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:11211 *:*
Testovaná aplikace měla v konfiguraci nastaveno, aby se připojovala k adrese 127.0.0.1:11211
po TCP. Jenže připojení k memcached se nezdařilo.
Dokonce ani strace neukazoval žádné známky toho, že by se vůbec o nějaký connect()
syscall pokoušel.
Po několika pokusech najít problém pomocí telnet
, strace
, ss
a dalších nástrojů, jsme zkusili vše překonfigurovat na IPv6 loopback -
čili adresu [::1]:11211
, kde se připojení bez problému podařilo.
Řekněme, že v tento moment je problém vyřešen. Pro nás je ale důležité nejen najít řešení, ale i vědět proč k té situaci vůbec došlo. A tak jsme se pustili do dalšího studia vzniklé situace.
Vytáhli jsme si tedy z aplikace kus kódu, který se připojuje k memcached a vytvořili jsme si jednoduchý test case, na kterém jsme problém dále simulovali. Aplikace je napsaná v perlu a testovací kód tedy vypadá následovně:
#!/usr/bin/perl
use Cache::Memcached::Fast;
my $memcached = Cache::Memcached::Fast->new({ 'servers' => [ '127.0.0.1:11211' ] });
my $ismemcached = $memcached->set('ismemcached','1');
unless ($ismemcached) {
warn "\nMemcached is not responding\n";
}
Tento krátký prototyp nás dovedl k tomu, že bude problém v knihovně Cache::Memcached::Fast,
kterou aplikace používá. Rychle jsme si také vyzkoušeli, že velmi podobná knihovna Cache::Memcached
tímto problémem netrpí.
Autor knihovny se snažil dostát názvu knihovny všemi možnými prostředky a tak nastavil u funkce getaddrinfo
, která se stará o překlad adres,
flag AI_ADDRCONFIG.
Popis AI_ADDRCONFIG flagu:
If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4 addresses are returned in the list pointed to by res only if the local system has at least one IPv4 address configured, and IPv6 addresses are returned only if the local system has at least one IPv6 address configured. The loopback address is not considered for this case as valid as a configured address. This flag is useful on, for example, IPv4-only systems, to ensure that getaddrinfo() does not return IPv6 socket addresses that would always fail in connect(2) or bind(2).
Zjednodušeně řečeno tento flag zajistí, že getaddrinfo
vrátí adresy z rodiny IP protokolů jen takové, které jsou na daném systému
nakonfigurované. V našem případě tedy fungoval pouze v IPv6 světě a IPv4 loopback pro něj vůbec neexistoval, protože na serveru nebyla
vyjma loopbacku žádná IPv4 adresa.
Použití IPv4 loopbacku v IPv6 only síti je zcela legitimní a věřím, že IPv4 svět s námi bude ještě několik generací. Popravdě nás tato situace docela překvapila, protože nebyla podobná žádnému jinému běžnému problému, se kterými se setkáváme. Celé řešení však netrvalo dlouho a to hlavně díky otevřenému zdrojovému kódu, ve kterém jsme byli schopni velmi rychle najít příčinu naší situace.
Pevně věříme, že autor knihovny měl s daným flagem dobrý záměr a vyřešil mu nějakou jinou problémovou situaci. I tak jsme ale alespoň vytvořili issue, ve kterém celou situaci můžeme prodiskutovat a případně zaslat úpravu kódu. Z naší zkušenosti ale víme, že u běžných změn trvá velmi dlouho než se případné změny dostanou do upstreamu a pak do distribucí. V tomto případě jsme tedy upravili náš config management, aby se aplikace k memcached připojovala pomocí IPv6 loopbacku.