Μια ιστορία σχετικά με τα πακέτα DNS που λείπουν από την τεχνική υποστήριξη του Google Cloud

Από το Google Blog Editor: Έχετε αναρωτηθεί ποτέ πώς χειρίζονται οι μηχανικοί της Google Cloud Technical Solutions (TSE) τα αιτήματά σας υποστήριξης; Οι μηχανικοί τεχνικής υποστήριξης της TSE είναι υπεύθυνοι για τον εντοπισμό και τη διόρθωση των πηγών προβλημάτων που αναφέρουν οι χρήστες. Μερικά από αυτά τα προβλήματα είναι αρκετά απλά, αλλά μερικές φορές συναντάτε ένα εισιτήριο που απαιτεί την προσοχή πολλών μηχανικών ταυτόχρονα. Σε αυτό το άρθρο, ένας από τους υπαλλήλους του TSE θα μας πει για ένα πολύ δύσκολο πρόβλημα από την πρόσφατη πρακτική του - περίπτωση που λείπουν πακέτα DNS. Σε αυτήν την ιστορία, θα δούμε πώς οι μηχανικοί κατάφεραν να επιλύσουν την κατάσταση και ποια νέα πράγματα έμαθαν ενώ διόρθωσαν το σφάλμα. Ελπίζουμε αυτή η ιστορία όχι μόνο να σας εκπαιδεύσει σχετικά με ένα βαθύ σφάλμα, αλλά και να σας δώσει πληροφορίες για τις διαδικασίες που ακολουθούν την υποβολή ενός δελτίου υποστήριξης στο Google Cloud.

Μια ιστορία σχετικά με τα πακέτα DNS που λείπουν από την τεχνική υποστήριξη του Google Cloud

Η αντιμετώπιση προβλημάτων είναι και επιστήμη και τέχνη. Όλα ξεκινούν με τη δημιουργία μιας υπόθεσης σχετικά με τον λόγο της μη τυπικής συμπεριφοράς του συστήματος, μετά την οποία ελέγχεται για αντοχή. Ωστόσο, πριν διατυπώσουμε μια υπόθεση, πρέπει να ορίσουμε με σαφήνεια και να διατυπώσουμε με ακρίβεια το πρόβλημα. Εάν η ερώτηση ακούγεται πολύ ασαφής, τότε θα πρέπει να αναλύσετε τα πάντα προσεκτικά. Αυτή είναι η «τέχνη» της αντιμετώπισης προβλημάτων.

Υπό το Google Cloud, τέτοιες διαδικασίες γίνονται εκθετικά πιο περίπλοκες, καθώς το Google Cloud καταβάλλει κάθε δυνατή προσπάθεια για να εγγυηθεί το απόρρητο των χρηστών του. Εξαιτίας αυτού, οι μηχανικοί της TSE δεν έχουν πρόσβαση για να επεξεργαστούν τα συστήματά σας, ούτε τη δυνατότητα να προβάλουν τις διαμορφώσεις τόσο ευρέως όσο οι χρήστες. Επομένως, για να ελέγξουμε οποιαδήποτε από τις υποθέσεις μας, εμείς (οι μηχανικοί) δεν μπορούμε να τροποποιήσουμε γρήγορα το σύστημα.

Ορισμένοι χρήστες πιστεύουν ότι θα διορθώσουμε τα πάντα σαν μηχανικούς σε μια υπηρεσία αυτοκινήτου και απλώς θα μας στείλουμε το αναγνωριστικό μιας εικονικής μηχανής, ενώ στην πραγματικότητα η διαδικασία λαμβάνει χώρα σε μορφή συνομιλίας: συλλογή πληροφοριών, σχηματισμός και επιβεβαίωση (ή διάψευση) υποθέσεων, και, τελικά, τα προβλήματα απόφασης βασίζονται στην επικοινωνία με τον πελάτη.

Εν προκειμένω πρόβλημα

Σήμερα έχουμε μια ιστορία με καλό τέλος. Ένας από τους λόγους για την επιτυχή επίλυση της προτεινόμενης υπόθεσης είναι η πολύ λεπτομερής και ακριβής περιγραφή του προβλήματος. Παρακάτω μπορείτε να δείτε ένα αντίγραφο του πρώτου εισιτηρίου (επεξεργασμένο για απόκρυψη εμπιστευτικών πληροφοριών):
Μια ιστορία σχετικά με τα πακέτα DNS που λείπουν από την τεχνική υποστήριξη του Google Cloud
Αυτό το μήνυμα περιέχει πολλές χρήσιμες πληροφορίες για εμάς:

  • Καθορίστηκε συγκεκριμένο VM
  • Το ίδιο το πρόβλημα υποδεικνύεται - το DNS δεν λειτουργεί
  • Υποδεικνύεται όπου εμφανίζεται το πρόβλημα - VM και κοντέινερ
  • Υποδεικνύονται τα βήματα που έκανε ο χρήστης για να εντοπίσει το πρόβλημα.

Το αίτημα καταχωρήθηκε ως «P1: Critical Impact - Service Unusable in production», που σημαίνει συνεχή παρακολούθηση της κατάστασης 24/7 σύμφωνα με το πρόγραμμα «Follow the Sun» (μπορείτε να διαβάσετε περισσότερα για προτεραιότητες των αιτημάτων των χρηστών), με τη μεταφορά του από μια ομάδα τεχνικής υποστήριξης σε άλλη με κάθε αλλαγή ζώνης ώρας. Μάλιστα, μέχρι να φτάσει το πρόβλημα στην ομάδα μας στη Ζυρίχη, είχε ήδη κάνει τον γύρο της υδρογείου. Μέχρι εκείνη τη στιγμή, ο χρήστης είχε λάβει μέτρα μετριασμού, αλλά φοβόταν την επανάληψη της κατάστασης στην παραγωγή, καθώς η βασική αιτία δεν είχε ακόμη ανακαλυφθεί.

Μέχρι να φτάσει το εισιτήριο στη Ζυρίχη, είχαμε ήδη τις ακόλουθες πληροφορίες:

  • Περιεχόμενο /etc/hosts
  • Περιεχόμενο /etc/resolv.conf
  • Παραγωγή iptables-save
  • Συγκεντρώθηκε από την ομάδα ngrep αρχείο pcap

Με αυτά τα δεδομένα, ήμασταν έτοιμοι να ξεκινήσουμε τη φάση «διερεύνησης» και αντιμετώπισης προβλημάτων.

Τα πρώτα μας βήματα

Πρώτα απ 'όλα, ελέγξαμε τα αρχεία καταγραφής και την κατάσταση του διακομιστή μεταδεδομένων και βεβαιωθήκαμε ότι λειτουργούσε σωστά. Ο διακομιστής μεταδεδομένων ανταποκρίνεται στη διεύθυνση IP 169.254.169.254 και, μεταξύ άλλων, είναι υπεύθυνος για τον έλεγχο των ονομάτων τομέα. Ελέγξαμε επίσης ότι το τείχος προστασίας λειτουργεί σωστά με το VM και δεν μπλοκάρει πακέτα.

Ήταν κάποιο περίεργο πρόβλημα: ο έλεγχος nmap διέψευσε την κύρια υπόθεση μας σχετικά με την απώλεια πακέτων UDP, οπότε καταλήξαμε διανοητικά σε πολλές ακόμη επιλογές και τρόπους για να τα ελέγξουμε:

  • Τα πακέτα πέφτουν επιλεκτικά; => Ελέγξτε τους κανόνες iptables
  • Δεν είναι πολύ μικρό; MTU? => Ελέγξτε την έξοδο ip a show
  • Το πρόβλημα επηρεάζει μόνο τα πακέτα UDP ή το TCP; => Οδηγήστε μακριά dig +tcp
  • Επιστρέφονται τα πακέτα που δημιουργήθηκαν από το dig; => Οδηγήστε μακριά tcpdump
  • Το libdns λειτουργεί σωστά; => Οδηγήστε μακριά strace για να ελέγξετε τη μετάδοση των πακέτων και προς τις δύο κατευθύνσεις

Εδώ αποφασίζουμε να καλέσουμε τον χρήστη για την αντιμετώπιση προβλημάτων ζωντανά.

Κατά τη διάρκεια της κλήσης μπορούμε να ελέγξουμε πολλά πράγματα:

  • Μετά από αρκετούς ελέγχους, αποκλείουμε τους κανόνες iptables από τη λίστα των λόγων
  • Ελέγχουμε τις διεπαφές δικτύου και τους πίνακες δρομολόγησης και ελέγχουμε ξανά ότι το MTU είναι σωστό
  • Το ανακαλύπτουμε dig +tcp google.com (TCP) λειτουργεί όπως θα έπρεπε, αλλά dig google.com Το (UDP) δεν λειτουργεί
  • Έχοντας διώξει μακριά tcpdump δουλεύει ακόμα dig, διαπιστώνουμε ότι επιστρέφονται πακέτα UDP
  • Διώχνουμε μακριά strace dig google.com και βλέπουμε πώς καλεί σωστά το dig sendmsg() и recvms(), ωστόσο το δεύτερο διακόπτεται από τάιμ άουτ

Δυστυχώς φτάνει το τέλος της βάρδιας και αναγκαζόμαστε να κλιμακώσουμε το πρόβλημα στην επόμενη ζώνη ώρας. Το αίτημα, ωστόσο, προκάλεσε ενδιαφέρον στην ομάδα μας και ένας συνάδελφος προτείνει τη δημιουργία του αρχικού πακέτου DNS χρησιμοποιώντας τη λειτουργική μονάδα scrapy Python.

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())

Αυτό το τμήμα δημιουργεί ένα πακέτο DNS και στέλνει το αίτημα στον διακομιστή μεταδεδομένων.

Ο χρήστης εκτελεί τον κώδικα, επιστρέφεται η απόκριση DNS και τον λαμβάνει η εφαρμογή, επιβεβαιώνοντας ότι δεν υπάρχει πρόβλημα σε επίπεδο δικτύου.

Μετά από ένα άλλο "γύρο του κόσμου", το αίτημα επιστρέφει στην ομάδα μας και το μεταφέρω εντελώς στον εαυτό μου, σκεπτόμενος ότι θα είναι πιο βολικό για τον χρήστη εάν το αίτημα σταματήσει να κυκλώνει από μέρος σε μέρος.

Εν τω μεταξύ, ο χρήστης συμφωνεί ευγενικά να παρέχει ένα στιγμιότυπο της εικόνας του συστήματος. Αυτά είναι πολύ καλά νέα: η δυνατότητα δοκιμής του συστήματος μόνος μου κάνει την αντιμετώπιση προβλημάτων πολύ πιο γρήγορη, επειδή δεν χρειάζεται πλέον να ζητάω από τον χρήστη να εκτελέσει εντολές, να μου στείλει τα αποτελέσματα και να τα αναλύσει, μπορώ να κάνω τα πάντα μόνος μου!

Οι συνάδελφοί μου έχουν αρχίσει να με ζηλεύουν λίγο. Κατά τη διάρκεια του γεύματος συζητάμε τη μετατροπή, αλλά κανείς δεν έχει ιδέα τι συμβαίνει. Ευτυχώς, ο ίδιος ο χρήστης έχει ήδη λάβει μέτρα για τον μετριασμό των συνεπειών και δεν βιάζεται, οπότε έχουμε χρόνο να αναλύσουμε το πρόβλημα. Και αφού έχουμε εικόνα, μπορούμε να κάνουμε ό,τι τεστ μας ενδιαφέρει. Εξαιρετική!

Κάνοντας ένα βήμα πίσω

Μία από τις πιο δημοφιλείς ερωτήσεις συνέντευξης για θέσεις μηχανικού συστημάτων είναι: «Τι συμβαίνει όταν κάνεις ping www.google.com? Η ερώτηση είναι μεγάλη, αφού ο υποψήφιος πρέπει να περιγράψει τα πάντα, από το φλοιό μέχρι τον χώρο χρήστη, τον πυρήνα του συστήματος και μετά το δίκτυο. Χαμογελώ: μερικές φορές οι ερωτήσεις συνέντευξης αποδεικνύονται χρήσιμες στην πραγματική ζωή...

Αποφασίζω να εφαρμόσω αυτήν την ερώτηση ανθρώπινου δυναμικού σε ένα τρέχον πρόβλημα. Σε γενικές γραμμές, όταν προσπαθείτε να προσδιορίσετε ένα όνομα DNS, συμβαίνει το εξής:

  1. Η εφαρμογή καλεί μια βιβλιοθήκη συστήματος όπως το libdns
  2. Το libdns ελέγχει τη διαμόρφωση του συστήματος με τον διακομιστή DNS που πρέπει να επικοινωνήσει (στο διάγραμμα αυτό είναι 169.254.169.254, διακομιστής μεταδεδομένων)
  3. Το libdns χρησιμοποιεί κλήσεις συστήματος για να δημιουργήσει μια υποδοχή UDP (SOKET_DGRAM) και να στείλει πακέτα UDP με ένα ερώτημα DNS και προς τις δύο κατευθύνσεις
  4. Μέσω της διεπαφής sysctl μπορείτε να διαμορφώσετε τη στοίβα UDP σε επίπεδο πυρήνα
  5. Ο πυρήνας αλληλεπιδρά με το υλικό για τη μετάδοση πακέτων μέσω του δικτύου μέσω της διεπαφής δικτύου
  6. Ο hypervisor συλλαμβάνει και μεταδίδει το πακέτο στον διακομιστή μεταδεδομένων κατά την επαφή με αυτό
  7. Ο διακομιστής μεταδεδομένων, δια μαγείας του, καθορίζει το όνομα DNS και επιστρέφει μια απάντηση χρησιμοποιώντας την ίδια μέθοδο

Μια ιστορία σχετικά με τα πακέτα DNS που λείπουν από την τεχνική υποστήριξη του Google Cloud
Επιτρέψτε μου να σας υπενθυμίσω ποιες υποθέσεις έχουμε ήδη εξετάσει:

Υπόθεση: Σπασμένες βιβλιοθήκες

  • Δοκιμή 1: εκτελέστε strace στο σύστημα, ελέγξτε ότι το dig καλεί τις σωστές κλήσεις συστήματος
  • Αποτέλεσμα: Καλούνται οι σωστές κλήσεις συστήματος
  • Δοκιμή 2: χρήση srapy για να ελέγξουμε αν μπορούμε να προσδιορίσουμε ονόματα που παρακάμπτουν τις βιβλιοθήκες συστήματος
  • Αποτέλεσμα: μπορούμε
  • Δοκιμή 3: εκτελέστε rpm –V στο πακέτο libdns και τα αρχεία βιβλιοθήκης md5sum
  • Αποτέλεσμα: ο κώδικας της βιβλιοθήκης είναι εντελώς πανομοιότυπος με τον κώδικα στο λειτουργικό σύστημα
  • Δοκιμή 4: προσαρτήστε την εικόνα του ριζικού συστήματος του χρήστη σε ένα VM χωρίς αυτήν τη συμπεριφορά, εκτελέστε το chroot, δείτε αν λειτουργεί το DNS
  • Αποτέλεσμα: Το DNS λειτουργεί σωστά

Συμπέρασμα βάσει δοκιμών: το πρόβλημα δεν είναι στις βιβλιοθήκες

Υπόθεση: Υπάρχει σφάλμα στις ρυθμίσεις DNS

  • Δοκιμή 1: ελέγξτε το tcpdump και δείτε εάν τα πακέτα DNS αποστέλλονται και επιστρέφονται σωστά μετά την εκτέλεση του dig
  • Αποτέλεσμα: τα πακέτα μεταδίδονται σωστά
  • Δοκιμή 2: διπλός έλεγχος στον διακομιστή /etc/nsswitch.conf и /etc/resolv.conf
  • Αποτέλεσμα: όλα είναι σωστά

Συμπέρασμα βάσει δοκιμών: το πρόβλημα δεν είναι με τη διαμόρφωση DNS

Υπόθεση: ο πυρήνας έχει καταστραφεί

  • Δοκιμή: εγκατάσταση νέου πυρήνα, έλεγχος υπογραφής, επανεκκίνηση
  • Αποτέλεσμα: παρόμοια συμπεριφορά

Συμπέρασμα βάσει δοκιμών: ο πυρήνας δεν έχει καταστραφεί

Υπόθεση: εσφαλμένη συμπεριφορά του δικτύου χρήστη (ή της διεπαφής δικτύου υπερεπόπτη)

  • Δοκιμή 1: Ελέγξτε τις ρυθμίσεις του τείχους προστασίας σας
  • Αποτέλεσμα: το τείχος προστασίας μεταβιβάζει πακέτα DNS τόσο στον κεντρικό υπολογιστή όσο και στο GCP
  • Δοκιμή 2: υποκλοπή κίνησης και παρακολούθηση της ορθότητας της μετάδοσης και της επιστροφής αιτημάτων DNS
  • Αποτέλεσμα: Το tcpdump επιβεβαιώνει ότι ο κεντρικός υπολογιστής έχει λάβει πακέτα επιστροφής

Συμπέρασμα βάσει δοκιμών: το πρόβλημα δεν είναι στο δίκτυο

Υπόθεση: ο διακομιστής μεταδεδομένων δεν λειτουργεί

  • Δοκιμή 1: ελέγξτε τα αρχεία καταγραφής διακομιστή μεταδεδομένων για ανωμαλίες
  • Αποτέλεσμα: δεν υπάρχουν ανωμαλίες στα αρχεία καταγραφής
  • Δοκιμή 2: Παράκαμψη του διακομιστή μεταδεδομένων μέσω dig @8.8.8.8
  • Αποτέλεσμα: Η ανάλυση διακόπτεται ακόμη και χωρίς τη χρήση διακομιστή μεταδεδομένων

Συμπέρασμα βάσει δοκιμών: το πρόβλημα δεν είναι με τον διακομιστή μεταδεδομένων

Η κατώτατη γραμμή: δοκιμάσαμε όλα τα υποσυστήματα εκτός από ρυθμίσεις χρόνου εκτέλεσης!

Κατάδυση στις ρυθμίσεις χρόνου εκτέλεσης πυρήνα

Για να διαμορφώσετε το περιβάλλον εκτέλεσης του πυρήνα, μπορείτε να χρησιμοποιήσετε επιλογές γραμμής εντολών (grub) ή τη διεπαφή sysctl. κοίταξα μέσα /etc/sysctl.conf και σκεφτείτε, ανακάλυψα πολλές προσαρμοσμένες ρυθμίσεις. Έχοντας την αίσθηση ότι είχα πιάσει κάτι, απέρριψα όλες τις ρυθμίσεις που δεν ήταν δικτυακές ή μη tcp, παραμένοντας στις ρυθμίσεις βουνού net.core. Στη συνέχεια, πήγα εκεί που ήταν τα δικαιώματα του κεντρικού υπολογιστή στο VM και άρχισα να εφαρμόζω τις ρυθμίσεις μία προς μία, μία μετά την άλλη, με το σπασμένο VM, μέχρι που βρήκα τον ένοχο:

net.core.rmem_default = 2147483647

Εδώ είναι, μια διαμόρφωση που σπάει το DNS! Βρήκα το όπλο της δολοφονίας. Γιατί όμως συμβαίνει αυτό; Χρειαζόμουν ακόμα ένα κίνητρο.

Το βασικό μέγεθος προσωρινής αποθήκευσης πακέτων DNS διαμορφώνεται μέσω net.core.rmem_default. Μια τυπική τιμή είναι κάπου γύρω στα 200 KiB, αλλά εάν ο διακομιστής σας λαμβάνει πολλά πακέτα DNS, μπορεί να θέλετε να αυξήσετε το μέγεθος του buffer. Εάν το buffer είναι γεμάτο όταν φτάσει ένα νέο πακέτο, για παράδειγμα επειδή η εφαρμογή δεν το επεξεργάζεται αρκετά γρήγορα, τότε θα αρχίσετε να χάνετε πακέτα. Ο πελάτης μας αύξησε σωστά το μέγεθος του buffer επειδή φοβόταν την απώλεια δεδομένων, καθώς χρησιμοποιούσε μια εφαρμογή για τη συλλογή μετρήσεων μέσω πακέτων DNS. Η τιμή που όρισε ήταν η μέγιστη δυνατή: 231-1 (αν οριστεί σε 231, ο πυρήνας θα επιστρέψει "ΜΗ ΕΓΚΥΡΟ ΕΠΙΧΕΙΡΗΜΑ").

Ξαφνικά συνειδητοποίησα γιατί το nmap και το scapy λειτουργούσαν σωστά: χρησιμοποιούσαν ακατέργαστες πρίζες! Οι ακατέργαστες πρίζες διαφέρουν από τις κανονικές υποδοχές: παρακάμπτουν τα iptable και δεν αποθηκεύονται στην προσωρινή μνήμη!

Γιατί όμως το "buffer too big" προκαλεί προβλήματα; Προφανώς δεν λειτουργεί όπως έπρεπε.

Σε αυτό το σημείο θα μπορούσα να αναπαράγω το πρόβλημα σε πολλούς πυρήνες και πολλαπλές διανομές. Το πρόβλημα εμφανίστηκε ήδη στον πυρήνα 3.x και τώρα εμφανίστηκε και στον πυρήνα 5.x.

Πράγματι, κατά την εκκίνηση

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

Το DNS σταμάτησε να λειτουργεί.

Άρχισα να ψάχνω για τιμές εργασίας μέσω ενός απλού δυαδικού αλγόριθμου αναζήτησης και διαπίστωσα ότι το σύστημα λειτουργούσε με το 2147481343, αλλά αυτός ο αριθμός ήταν ένα σύνολο αριθμών χωρίς νόημα για μένα. Πρότεινα στον πελάτη να δοκιμάσει αυτόν τον αριθμό και απάντησε ότι το σύστημα λειτουργούσε με το google.com, αλλά παρόλα αυτά έδωσε ένα σφάλμα με άλλους τομείς, επομένως συνέχισα την έρευνά μου.

έχω εγκαταστήσει dropwatch, ένα εργαλείο που θα έπρεπε να είχε χρησιμοποιηθεί νωρίτερα: δείχνει ακριβώς πού στον πυρήνα καταλήγει ένα πακέτο. Ο ένοχος ήταν η λειτουργία udp_queue_rcv_skb. Κατέβασα τις πηγές του πυρήνα και πρόσθεσα μερικές λειτουργίες printk για να παρακολουθείτε πού ακριβώς καταλήγει το πακέτο. Βρήκα γρήγορα τη σωστή κατάσταση if, και απλά το κοίταξα επίμονα για αρκετή ώρα, γιατί ήταν τότε που όλα τελικά συνδυάστηκαν σε μια ολόκληρη εικόνα: 231-1, ένας αριθμός χωρίς νόημα, ένας τομέας που δεν λειτουργούσε... Ήταν ένα κομμάτι κώδικα στο __udp_enqueue_schedule_skb:

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

Παρακαλώ σημειώστε:

  • rmem είναι τύπου int
  • size είναι του τύπου u16 (ανυπόγραφο δεκαέξι-bit int) και αποθηκεύει το μέγεθος του πακέτου
  • sk->sk_rcybuf είναι τύπου int και αποθηκεύει το μέγεθος buffer το οποίο, εξ ορισμού, είναι ίσο με την τιμή in net.core.rmem_default

Όταν sk_rcvbuf πλησιάζει το 231, η άθροιση του μεγέθους του πακέτου μπορεί να έχει ως αποτέλεσμα υπερχείλιση ακέραιου αριθμού. Και επειδή είναι int, η τιμή του γίνεται αρνητική, οπότε η συνθήκη γίνεται αληθής όταν θα έπρεπε να είναι ψευδής (μπορείτε να διαβάσετε περισσότερα για αυτό στο σύνδεσμος).

Το σφάλμα μπορεί να διορθωθεί με ασήμαντο τρόπο: με casting unsigned int. Εφάρμοσα την επιδιόρθωση και επανεκκίνησα το σύστημα και το DNS λειτούργησε ξανά.

Γεύση νίκης

Προώθησα τα ευρήματά μου στον πελάτη και έστειλα LKML ενημερωμένη έκδοση κώδικα πυρήνα. Είμαι ευχαριστημένος: κάθε κομμάτι του παζλ ταιριάζει, μπορώ να εξηγήσω ακριβώς γιατί παρατηρήσαμε αυτό που παρατηρήσαμε, και το πιο σημαντικό, μπορέσαμε να βρούμε μια λύση στο πρόβλημα χάρη στην ομαδική μας δουλειά!

Αξίζει να αναγνωρίσουμε ότι η περίπτωση αποδείχθηκε σπάνια και ευτυχώς σπάνια λαμβάνουμε τόσο περίπλοκα αιτήματα από χρήστες.

Μια ιστορία σχετικά με τα πακέτα DNS που λείπουν από την τεχνική υποστήριξη του Google Cloud


Πηγή: www.habr.com

Προσθέστε ένα σχόλιο