Kisah tentang kehilangan paket DNS daripada sokongan teknikal Google Cloud

Daripada Editor Blog Google: Pernahkah anda terfikir bagaimana jurutera Google Cloud Technical Solutions (TSE) mengendalikan permintaan sokongan anda? Jurutera Sokongan Teknikal TSE bertanggungjawab untuk mengenal pasti dan membetulkan sumber masalah yang dilaporkan pengguna. Beberapa masalah ini agak mudah, tetapi kadangkala anda menjumpai tiket yang memerlukan perhatian beberapa jurutera sekaligus. Dalam artikel ini, salah seorang pekerja TSE akan memberitahu kami tentang satu masalah yang sangat rumit daripada amalannya baru-baru ini - kes kehilangan paket DNS. Dalam cerita ini, kita akan melihat bagaimana jurutera berjaya menyelesaikan keadaan, dan perkara baharu yang mereka pelajari semasa membetulkan ralat. Kami berharap cerita ini bukan sahaja mendidik anda tentang pepijat yang mendalam, tetapi juga memberi anda cerapan tentang proses yang digunakan untuk memfailkan tiket sokongan dengan Google Cloud.

Kisah tentang kehilangan paket DNS daripada sokongan teknikal Google Cloud

Penyelesaian masalah adalah sains dan seni. Semuanya bermula dengan membina hipotesis tentang sebab kelakuan tidak standard sistem, selepas itu ia diuji untuk kekuatan. Walau bagaimanapun, sebelum kita merumuskan hipotesis, kita mesti mentakrifkan dengan jelas dan merumuskan masalah dengan tepat. Jika soalan itu kedengaran terlalu kabur, maka anda perlu menganalisis semuanya dengan teliti; Ini adalah "seni" penyelesaian masalah.

Di bawah Google Cloud, proses sedemikian menjadi lebih kompleks secara eksponen, kerana Google Cloud cuba sedaya upaya untuk menjamin privasi penggunanya. Oleh sebab itu, jurutera TSE tidak mempunyai akses untuk mengedit sistem anda, mahupun keupayaan untuk melihat konfigurasi secara meluas seperti yang dilakukan oleh pengguna. Oleh itu, untuk menguji mana-mana hipotesis kami, kami (jurutera) tidak boleh mengubah suai sistem dengan cepat.

Sesetengah pengguna percaya bahawa kami akan membetulkan segala-galanya seperti mekanik dalam perkhidmatan kereta, dan hanya menghantar id mesin maya kepada kami, sedangkan pada hakikatnya proses itu berlaku dalam format perbualan: mengumpul maklumat, membentuk dan mengesahkan (atau menafikan) hipotesis, dan, pada akhirnya, masalah keputusan adalah berdasarkan komunikasi dengan pelanggan.

Masalah yang dipersoalkan

Hari ini kita mempunyai cerita dengan pengakhiran yang baik. Salah satu sebab kejayaan penyelesaian kes yang dicadangkan adalah penerangan yang sangat terperinci dan tepat tentang masalah tersebut. Di bawah anda boleh melihat salinan tiket pertama (diedit untuk menyembunyikan maklumat sulit):
Kisah tentang kehilangan paket DNS daripada sokongan teknikal Google Cloud
Mesej ini mengandungi banyak maklumat berguna untuk kami:

  • VM khusus ditentukan
  • Masalahnya sendiri ditunjukkan - DNS tidak berfungsi
  • Ia ditunjukkan di mana masalah itu nyata - VM dan bekas
  • Langkah-langkah yang diambil pengguna untuk mengenal pasti masalah ditunjukkan.

Permintaan itu didaftarkan sebagai "P1: Kesan Kritikal - Perkhidmatan Tidak Dapat Digunakan dalam pengeluaran", yang bermaksud pemantauan berterusan keadaan 24/7 mengikut skema "Ikuti Matahari" (anda boleh membaca lebih lanjut mengenai keutamaan permintaan pengguna), dengan pemindahannya daripada satu pasukan sokongan teknikal kepada yang lain dengan setiap peralihan zon waktu. Malah, pada masa masalah itu sampai kepada pasukan kami di Zurich, ia telah pun mengelilingi dunia. Pada masa ini, pengguna telah mengambil langkah mitigasi, tetapi takut situasi dalam pengeluaran berulang, kerana puncanya masih belum ditemui.

Apabila tiket tiba di Zurich, kami sudah mempunyai maklumat berikut di tangan:

  • Kandungan /etc/hosts
  • Kandungan /etc/resolv.conf
  • Output iptables-save
  • Dihimpun oleh pasukan ngrep fail pcap

Dengan data ini, kami bersedia untuk memulakan fasa "penyiasatan" dan penyelesaian masalah.

Langkah pertama kami

Pertama sekali, kami menyemak log dan status pelayan metadata dan memastikan ia berfungsi dengan betul. Pelayan metadata bertindak balas kepada alamat IP 169.254.169.254 dan, antara lain, bertanggungjawab untuk mengawal nama domain. Kami juga menyemak semula bahawa tembok api berfungsi dengan betul dengan VM dan tidak menyekat paket.

Ia adalah sejenis masalah pelik: semakan nmap menyangkal hipotesis utama kami tentang kehilangan paket UDP, jadi kami secara mental datang dengan beberapa lagi pilihan dan cara untuk menyemaknya:

  • Adakah paket digugurkan secara terpilih? => Semak peraturan iptables
  • Tidakkah ia terlalu kecil? MTU? => Semak output ip a show
  • Adakah masalah itu menjejaskan hanya paket UDP atau TCP juga? => Menghalau dig +tcp
  • Adakah paket yang dijana dig dikembalikan? => Mengusir tcpdump
  • Adakah libdns berfungsi dengan betul? => Mengusir strace untuk memeriksa penghantaran paket dalam kedua-dua arah

Di sini kami memutuskan untuk memanggil pengguna untuk menyelesaikan masalah secara langsung.

Semasa panggilan, kami dapat menyemak beberapa perkara:

  • Selepas beberapa semakan, kami mengecualikan peraturan iptables daripada senarai sebab
  • Kami menyemak antara muka rangkaian dan jadual penghalaan, dan semak semula bahawa MTU adalah betul
  • Kami mendapati itu dig +tcp google.com (TCP) berfungsi sebagaimana mestinya, tetapi dig google.com (UDP) tidak berfungsi
  • Setelah dihalau tcpdump ia masih berfungsi dig, kami mendapati bahawa paket UDP sedang dikembalikan
  • Kami memandu pergi strace dig google.com dan kita lihat cara dig membuat panggilan dengan betul sendmsg() ΠΈ recvms(), namun yang kedua terganggu oleh tamat masa

Malangnya, penghujung syif tiba dan kami terpaksa meningkatkan masalah ke zon waktu seterusnya. Permintaan itu, bagaimanapun, menimbulkan minat dalam pasukan kami, dan rakan sekerja mencadangkan untuk membuat pakej DNS awal menggunakan modul Python yang buruk.

from scapy.all import *

answer = sr1(IP(dst="169.254.169.254")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="google.com")),verbose=0)
print ("169.254.169.254", answer[DNS].summary())

Serpihan ini mencipta paket DNS dan menghantar permintaan kepada pelayan metadata.

Pengguna menjalankan kod, respons DNS dikembalikan, dan aplikasi menerimanya, mengesahkan bahawa tiada masalah di peringkat rangkaian.

Selepas "perjalanan keliling dunia" yang lain, permintaan itu kembali kepada pasukan kami, dan saya memindahkannya sepenuhnya kepada diri saya sendiri, memikirkan bahawa ia akan menjadi lebih mudah untuk pengguna jika permintaan berhenti beredar dari satu tempat ke satu tempat.

Sementara itu, pengguna dengan hormatnya bersetuju untuk memberikan syot kilat imej sistem. Ini adalah berita yang sangat baik: keupayaan untuk menguji sistem sendiri menjadikan penyelesaian masalah lebih cepat, kerana saya tidak perlu lagi meminta pengguna menjalankan arahan, menghantar keputusan kepada saya dan menganalisisnya, saya boleh melakukan semuanya sendiri!

Rakan sekerja saya mula iri hati dengan saya. Semasa makan tengah hari, kami membincangkan penukaran, tetapi tiada siapa yang tahu apa yang sedang berlaku. Nasib baik, pengguna itu sendiri telah mengambil langkah untuk mengurangkan akibatnya dan tidak tergesa-gesa, jadi kami mempunyai masa untuk membedah masalah itu. Dan kerana kami mempunyai imej, kami boleh menjalankan sebarang ujian yang menarik minat kami. Hebat!

Mengambil langkah ke belakang

Salah satu soalan temu duga paling popular untuk jawatan jurutera sistem ialah: β€œApa yang berlaku apabila anda ping www.google.com? Soalannya bagus, kerana calon perlu menerangkan segala-galanya dari shell ke ruang pengguna, ke kernel sistem dan kemudian ke rangkaian. Saya tersenyum: kadangkala soalan temuduga ternyata berguna dalam kehidupan sebenar...

Saya memutuskan untuk menggunakan soalan HR ini kepada masalah semasa. Secara kasarnya, apabila anda cuba menentukan nama DNS, perkara berikut berlaku:

  1. Aplikasi ini memanggil perpustakaan sistem seperti libdns
  2. libdns menyemak konfigurasi sistem yang mana pelayan DNS harus dihubungi (dalam rajah ini ialah 169.254.169.254, pelayan metadata)
  3. libdns menggunakan panggilan sistem untuk mencipta soket UDP (SOKET_DGRAM) dan menghantar paket UDP dengan pertanyaan DNS dalam kedua-dua arah
  4. Melalui antara muka sysctl anda boleh mengkonfigurasi timbunan UDP pada peringkat kernel
  5. Kernel berinteraksi dengan perkakasan untuk menghantar paket melalui rangkaian melalui antara muka rangkaian
  6. Hipervisor menangkap dan menghantar paket ke pelayan metadata apabila dihubungi dengannya
  7. Pelayan metadata, dengan keajaibannya, menentukan nama DNS dan mengembalikan respons menggunakan kaedah yang sama

Kisah tentang kehilangan paket DNS daripada sokongan teknikal Google Cloud
Izinkan saya mengingatkan anda apakah hipotesis yang telah kami pertimbangkan:

Hipotesis: Perpustakaan rosak

  • Ujian 1: jalankan strace dalam sistem, semak bahawa penggalian memanggil panggilan sistem yang betul
  • Keputusan: Panggilan sistem yang betul dipanggil
  • Ujian 2: menggunakan srapy untuk menyemak sama ada kita boleh menentukan nama yang memintas perpustakaan sistem
  • Keputusan: kita boleh
  • Ujian 3: jalankan rpm –V pada pakej libdns dan fail perpustakaan md5sum
  • Keputusan: kod perpustakaan adalah sama sepenuhnya dengan kod dalam sistem pengendalian yang berfungsi
  • Ujian 4: lekapkan imej sistem akar pengguna pada VM tanpa tingkah laku ini, jalankan chroot, lihat jika DNS berfungsi
  • Keputusan: DNS berfungsi dengan betul

Kesimpulan berdasarkan ujian: masalahnya bukan di perpustakaan

Hipotesis: Terdapat ralat dalam tetapan DNS

  • Ujian 1: semak tcpdump dan lihat jika paket DNS dihantar dan dikembalikan dengan betul selepas menjalankan dig
  • Keputusan: paket dihantar dengan betul
  • Ujian 2: semak semula pada pelayan /etc/nsswitch.conf ΠΈ /etc/resolv.conf
  • Keputusan: semuanya betul

Kesimpulan berdasarkan ujian: masalahnya bukan dengan konfigurasi DNS

Hipotesis: teras rosak

  • Ujian: pasang kernel baharu, semak tandatangan, mulakan semula
  • Keputusan: tingkah laku yang serupa

Kesimpulan berdasarkan ujian: kernel tidak rosak

Hipotesis: tingkah laku rangkaian pengguna yang tidak betul (atau antara muka rangkaian hipervisor)

  • Ujian 1: Semak tetapan tembok api anda
  • Keputusan: tembok api menghantar paket DNS pada hos dan GCP
  • Ujian 2: memintas trafik dan memantau ketepatan penghantaran dan pemulangan permintaan DNS
  • Keputusan: tcpdump mengesahkan bahawa hos telah menerima paket pemulangan

Kesimpulan berdasarkan ujian: masalahnya tiada dalam rangkaian

Hipotesis: pelayan metadata tidak berfungsi

  • Ujian 1: semak log pelayan metadata untuk mengesan anomali
  • Keputusan: tiada anomali dalam log
  • Ujian 2: Pintas pelayan metadata melalui dig @8.8.8.8
  • Keputusan: Resolusi rosak walaupun tanpa menggunakan pelayan metadata

Kesimpulan berdasarkan ujian: masalahnya bukan dengan pelayan metadata

Dasarnya: kami menguji semua subsistem kecuali tetapan masa jalanan!

Menyelam ke dalam Tetapan Masa Jalan Kernel

Untuk mengkonfigurasi persekitaran pelaksanaan kernel, anda boleh menggunakan pilihan baris arahan (grub) atau antara muka sysctl. Saya melihat ke dalam /etc/sysctl.conf dan fikirkan, saya menemui beberapa tetapan tersuai. Merasa seolah-olah saya telah meraih sesuatu, saya membuang semua tetapan bukan rangkaian atau bukan tcp, kekal dengan tetapan gunung net.core. Kemudian saya pergi ke tempat kebenaran hos berada dalam VM dan mula menggunakan tetapan satu demi satu, satu demi satu, dengan VM yang rosak, sehingga saya menemui puncanya:

net.core.rmem_default = 2147483647

Ini dia, konfigurasi pemecah DNS! Saya jumpa senjata pembunuh. Tetapi mengapa ini berlaku? Saya masih memerlukan motif.

Saiz penimbal paket DNS asas dikonfigurasikan melalui net.core.rmem_default. Nilai biasa adalah sekitar 200KiB, tetapi jika pelayan anda menerima banyak paket DNS, anda mungkin mahu meningkatkan saiz penimbal. Jika penimbal penuh apabila paket baru tiba, contohnya kerana aplikasi tidak memprosesnya dengan cukup pantas, maka anda akan mula kehilangan paket. Pelanggan kami meningkatkan saiz penimbal dengan betul kerana dia takut kehilangan data, kerana dia menggunakan aplikasi untuk mengumpul metrik melalui paket DNS. Nilai yang dia tetapkan adalah maksimum yang mungkin: 231-1 (jika ditetapkan kepada 231, kernel akan mengembalikan "HUJAH TIDAK SAH").

Tiba-tiba saya menyedari mengapa nmap dan scapy berfungsi dengan betul: mereka menggunakan soket mentah! Soket mentah adalah berbeza daripada soket biasa: ia memintas iptables, dan ia tidak ditimbal!

Tetapi mengapa "penampan terlalu besar" menyebabkan masalah? Ia jelas tidak berfungsi seperti yang dimaksudkan.

Pada ketika ini saya boleh mengeluarkan semula masalah pada berbilang kernel dan berbilang pengedaran. Masalahnya telah muncul pada kernel 3.x dan kini ia juga muncul pada kernel 5.x.

Sesungguhnya, apabila dimulakan

sysctl -w net.core.rmem_default=$((2**31-1))

DNS berhenti berfungsi.

Saya mula mencari nilai kerja melalui algoritma carian binari mudah dan mendapati bahawa sistem berfungsi dengan 2147481343, tetapi nombor ini adalah set nombor yang tidak bermakna kepada saya. Saya mencadangkan pelanggan mencuba nombor ini, dan dia menjawab bahawa sistem itu berfungsi dengan google.com, tetapi masih memberikan ralat dengan domain lain, jadi saya meneruskan siasatan saya.

Saya telah memasang titisan jam tangan, alat yang sepatutnya digunakan lebih awal: ia menunjukkan dengan tepat di mana dalam kernel suatu paket berakhir. Pelakunya adalah fungsinya udp_queue_rcv_skb. Saya memuat turun sumber kernel dan menambah beberapa fungsi printk untuk mengesan di mana betul-betul paket itu berakhir. Saya segera menemui keadaan yang sesuai if, dan hanya merenungnya untuk beberapa lama, kerana pada ketika itu segala-galanya akhirnya menjadi satu gambaran keseluruhan: 231-1, nombor tidak bermakna, domain tidak berfungsi... Ia adalah sekeping kod dalam __udp_enqueue_schedule_skb:

if (rmem > (size + sk->sk_rcvbuf))
		goto uncharge_drop;

Sila ambil perhatian:

  • rmem adalah jenis int
  • size adalah jenis u16 (int enam belas-bit tidak ditandatangani) dan menyimpan saiz paket
  • sk->sk_rcybuf adalah jenis int dan menyimpan saiz penimbal yang, mengikut definisi, adalah sama dengan nilai dalam net.core.rmem_default

Apabila sk_rcvbuf menghampiri 231, menjumlahkan saiz paket boleh mengakibatkan limpahan integer. Dan kerana ia adalah int, nilainya menjadi negatif, jadi syarat menjadi benar apabila ia sepatutnya palsu (anda boleh membaca lebih lanjut tentang ini di pautan).

Ralat boleh diperbetulkan dengan cara yang remeh: dengan menghantar unsigned int. Saya menggunakan pembetulan dan memulakan semula sistem dan DNS berfungsi semula.

Rasa kemenangan

Saya memajukan penemuan saya kepada pelanggan dan menghantar LKML tampalan kernel. Saya gembira: setiap bahagian teka-teki sesuai bersama, saya boleh menerangkan dengan tepat mengapa kami memerhati perkara yang kami perhatikan, dan yang paling penting, kami dapat mencari penyelesaian kepada masalah itu berkat kerja berpasukan kami!

Perlu diingat bahawa kes itu ternyata jarang berlaku, dan mujurlah kami jarang menerima permintaan yang rumit daripada pengguna.

Kisah tentang kehilangan paket DNS daripada sokongan teknikal Google Cloud


Sumber: www.habr.com

Tambah komen