F5’e Basmaktan Ciğerim Soldu: Fedora’da “İlk İstekte Hata” Sorununu Nasıl Debug Ettim?

2–3 minutes

Linux kullanmanın en keyifli yanı, sistemin kaputunun altında her şeyin şeffaf olmasıdır. Ancak Fedora’nın kararlı bir sürümünü kullanıyor olsanız bile, bazen ağ yığınının (networking stack) derinliklerinde, standart kullanıcıların asla fark etmeyeceği ama teknik detaya hakim olanları çileden çıkaran “edge case” durumlarla karşılaşabiliyorsunuz. Geçtiğimiz günlerde tam da böyle bir sorunla, bir “ilk bağlantı zaman aşımı” problemiyle boğuştum. Hangi siteye gitsem tarayıcım ilk GET isteğinde ERR_ADDRESS_UNREACHABLE hatası fırlatıyor, sayfayı yenilediğimde ise sorunsuz şekilde çalışıyordu.

İşte bu “bir kere hata, sonra devam” döngüsünü nasıl analiz ettiğim ve (biraz kaba kuvvetle de olsa) nasıl çözdüğümün hikayesi.

Şüpheliler ve İlk Müdahaleler

İlk bakışta sorun klasik bir DNS timeout gibi duruyordu. Hemen ilk aklıma gelen çözümleri denemeye koyuldum. İlk olarak DNS Değişikliği yapmayı denedim. Hemen systemd-resolved servisini aradan çıkarıp NetworkManager üzerinden statik DNS (1.1.1.1 Cloudflare Çiçeğim 🙂 ) verdim fakat uzun bir süre bütün DNS sistemini bızıklasam da sonuç değişmedi. Sonrasında Tarayıcı Ayarları ile oynamaya başladım Chrome ve Firefox’un Secure DNS özelliklerini kapattım ama sinir bozucu hata devam ediyordu. Paylaşımlı bir ağdayım diye MAC adresi sabitleme (Sabit MAC adresini kullanacak değiliz değil mi?), MTU ayarları, Wi-Fi güç tasarrufu kapatma… Hepsini denedim. Sistem inatla ilk seferde “Ağa ulaşamıyorum” diyor, ikinci seferde yolu buluyordu. Bu bir “bağlantı” sorunu değil, bir “karar verme” sorunuydu.

Dedektiflik Zamanı: strace ile Suçüstü

Tahmin yürütmek mühendisliğe yakışmaz diyerek terminali açtım ve sorunu daha derinden incelemeye karar verdim. Tarayıcının hata verdiği o milisaniyede arka planda ne dönüyordu?

Chrome’u strace ile başlatıp sadece bağlantı (connect) çağrılarını izledim:

strace -e trace=connect -f google-chrome 2>&1 | grep "ENETUNREACH"

Ve işte suçlu karşımdaydı

connect(18, {sa_family=AF_INET6, ...}) = -1 ENETUNREACH

Çıktı çok netti

Sistemim inatla IPv6 (AF_INET6) üzerinden bağlantı kurmaya çalışıyordu. Ancak ağımda geçerli bir IPv6 çıkışı olmadığı için Kernel Ağ erişilebilir değil” (ENETUNREACH) hatası dönüyordu. İşin garibi ben IPv6yı Kapatmıştım?! NetworkManager ayarlarından IPv6’yı “Disabled” yapmıştım. ip addr komutunu çalıştırdığımda ise acı gerçeği gördüm:

inet6 fe80::bc24:661f... scope link

Ben ne kadar kapatsam da, NetworkManager veya Kernel, arayüze bir Link-Local (fe80::) adresi atıyordu. Sistem bu adresi görünce “Hey, benim IPv6’m var, hadi Google’a IPv6 ile gidelim!” sanrısına kapılıyor, ama o adresten dışarı çıkamayıp duvara tosluyordu. gai.conf ile IPv4’ü önceliklendirmek bile bu inatçı davranışı çözmedi.

Nükleer Çözüm: Kernel Parametresi

Yazılımsal ricalar (sysctl, nmcli) işe yaramayınca, sorunu en tepeden kernel seviyesinden çözmeye karar verdim. İşletim sistemine “Sen IPv6 diye bir protokolü hiç öğrenmedin, bilmiyorsun” diyecektim.

GRUB ayar dosyasını (/etc/default/grub) açtım ve şu parametreyi ekledim:

ipv6.disable=1

Bu parametre, Linux çekirdeği yüklenirken IPv6 modülünü tamamen devre dışı bırakıyor.

Tetiği çekip bilgisayarı yeniden başlattım. Bilgisayar açıldığında ip addr komutunda tek bir inet6 satırı bile yoktu. Tarayıcıyı açtım, bir siteye girdim ve… Anında açıldı. Çünkü Kernel artık IPv6 çağrısına “Ulaşılamıyor” (ENETUNREACH) hatası değil, “Böyle bir protokol yok” (EAFNOSUPPORT) hatası dönüyordu. Tarayıcı bu cevabı aldığı nanosaniye içinde vakit kaybetmeden IPv4’ü kullanıyordu.

Linux kullanıyorsanız bazen arayüzdeki “Kapat” butonu gerçekten kapatmak anlamına gelmeyebiliyor. Ve bir sorunu çözemiyorsanız, loglara (strace, journalctl) bakmak, karanlıkta el yordamıyla yürümekten her zaman iyidir, doğru log okumak körü körüne çözüm aramaktan çok daha değerli.