Θέλουμε να πιστεύουμε ότι τα τρία προηγούμενα άρθρα περί DNS έχουν βάλει στο νόημα ακόμη κι εκείνους που είχαν μόνο μιαν αμυδρά ιδέα περί name servers και Domain Name System γενικότερα. Πράγματι, καλύψαμε σημαντικό έδαφος και πλέον έχουμε κατανοήσει επαρκώς τη λογική του όλου συστήματος. Τόσο πολύ που έχει έρθει η ώρα να φτιάξουμε τον δικό μας name server, για τις ανάγκες του δικού μας τοπικού δικτύου.

Σε πολύ λίγο, σε ένα σύστημα με Ubuntu Server θα εγκαταστήσουμε το δημοφιλές BIND (Berkeley Internet Name Domain) και θα το ρυθμίσουμε ώστε να λειτουργεί ως caching name server για τα μηχανήματα του τοπικού δικτύου. Το BIND θα συμπεριφέρεται είτε ως recursive είτε ως forwarding name server. Πρόκειται για απόφαση που θα πάρουμε σταθμίζοντας τις ικανότητες του (εικονικού ή φυσικού) μηχανήματος με το BIND, το διαθέσιμο bandwidth για τις εξερχόμενες συνδέσεις προς το Internet, όπως επίσης και τη στάση μας ως προς την εξάρτηση από άλλους name servers.

Ας συζητήσουμε τα προηγούμενα λίγο πιο αναλυτικά. Κατ’ αρχάς η επιλογή του BIND δεν είναι μονόδρομος. Θα μπορούσαμε να επιλέξουμε άλλο λογισμικό, όπως, π.χ., είναι το Dnsmasq (caching και forwarding) ή το Unbound (caching και recursion ή forwarding). Όμως το BIND είναι εξαιρετικά ευέλικτο, κατάλληλο για απλά αλλά και για σύνθετα σενάρια, ενώ συναντάται συχνά στο Internet καθώς και σε τοπικά δίκτυα όλων των μεγεθών. Σκεφτήκαμε λοιπόν ότι, αν μη τι άλλο για εκπαιδευτικούς λόγους, δεν θα ήταν καθόλου κακή ιδέα να εξοικειωθούμε με το BIND ξεκινώντας από τα ρηχά.

Σε ένα τυπικό οικιακό δίκτυο θεωρούμε ότι δεν υπάρχει θέμα με την ισχύ του μηχανήματος που θ’ αναλάβει χρέη name server. Πράγματι, το ρόλο αυτό θα μπορούσε να έχει ακόμη κι ένα Raspberry Pi. Στην απόφασή μας, λοιπόν, για το αν ο name server θα είναι recursive ή forwarding, θα βαρύνουν άλλοι παράγοντες. Σημειώστε πάντως ότι για τους clients δεν έχει καμία σημασία τι από τα δύο θα είναι: Το μόνο που μετράει γι’ αυτούς είναι η ικανότητα για caching – κι αυτή θα την έχουμε και στις δύο περιπτώσεις. Πώς πρέπει να συμπεριφέρεται ο name server μας, λοιπόν;

Recursive. Σ’ αυτή την περίπτωση o server δεν έχει ανάγκη άλλους resolvers. Όταν δεν βρίσκει στην τοπική του cache την απάντηση σε κάποιο ερώτημα, ξεκινά την αναζήτηση από τους root name servers, μετά από τον κατάλληλο TLD server, ύστερα από τον domain-level server που θα του υποδειχθεί κ.ο.κ. Τις απαντήσεις που παίρνει δεν τις επιστρέφει απλά στους ενδιαφερόμενους πελάτες, αλλά ταυτόχρονα τις αποθηκεύει και στην cache του για μελλοντική αναφορά (και για όσο χρόνο επιτρέπουν τα αντίστοιχα TTL). Αν δεν θέλετε τα ερωτήματα των πελατών σας να φτάνουν σε δημόσιους caching name servers ή σε εκείνους του ISP σας, προτείνεται τότε να ρυθμίσετε το BIND ώστε να λειτουργεί ως recursive name server.

Forwarding. Όταν ένας name server της κατηγορίας δεν βρίσκει στην cache του την απάντηση σε ερώτημα πελάτη, τότε αμέσως προωθεί το ίδιο ερώτημα σε άλλους name servers που του έχουμε υποδείξει και είναι ικανοί για recursion. Με το που μαθαίνει ένας forwarding name server μιαν απάντηση, τη γνωστοποιεί στον ενδιαφερόμενο πελάτη αλλά την αποθηκεύει και στην cache του για μελλοντική χρήση. Είναι προφανές ότι ένας forwarding name server είναι σχεδιασμένος ώστε να αποφεύγει τη βαριά δουλειά. Υπό αυτή την έννοια, όταν το bandwidth που διαθέτουμε προς τον έξω κόσμο είναι περιορισμένο ή/και όταν η ποιότητα της σύνδεσης είναι χαμηλή, τότε η επιλογή ενός name server του είδους αποτελεί άριστη ιδέα. Θα εξαρτόμαστε βέβαια από άλλους recursive name servers, όπως, π.χ., είναι εκείνοι της Google, της OpenDNS ή του ISP μας (δεν τους προτείνουμε), ωστόσο ένας τέτοιος συμβιβασμός δεν είναι απαραίτητα τραγικός.

Τι ακολουθεί

Θα εγκαταστήσουμε το BIND σε ένα μηχάνημα με Ubuntu Server LTS 14.04, το οποίο θα ρυθμίσουμε ώστε να λειτουργεί ως caching name server με ικανότητες για recursion. Βασιζόμενοι σ’ αυτή τη διαμόρφωση θα δούμε πώς τροποποιείται, ώστε εναλλακτικά το BIND να λειτουργεί ως forwarding name server. Δεν θα παραλείψουμε να κάνουμε και μερικές δοκιμές, ώστε τέλος πάντων να δούμε πόσο πιο γρήγορος είναι –αν είναι– ο δικός μας name server, σε σύγκριση με έναν μεγάλο και σπουδαίο όπως, π.χ., είναι εκείνοι της Google ή της OpenDNS. Στο επόμενο και τελευταίο άρθρο της σειράς θα παρουσιάσουμε μερικές στρατηγικές εκμετάλλευσης του νέου name server. Θα συζητήσουμε, μ’ άλλα λόγια, για τρόπους ώστε κάποιες ή και όλες οι συσκευές του LAN να εξυπηρετούνται από τον καινούργιο name server.

Εγκατάσταση BIND

Από την κονσόλα του Ubuntu Server ή απομακρυσμένα, μέσω SSH, ενημερώνουμε πρώτα την τοπική λίστα με τα πακέτα από τα διαθέσιμα αποθετήρια:

sudo apt-get update

Αμέσως μετά εγκαθιστούμε το BIND (bind9), ένα πακέτο με χρήσιμα εργαλεία (bind9utils), καθώς και τη συνοδευτική τεκμηρίωση (bind9-doc, προαιρετικό πακέτο):

sudo apt-get install bind9 bind9utils bind9-doc

Αυτό ήταν. Όλα τα αρχεία ρυθμίσεων του BIND είναι συγκεντρωμένα κάτω από τον κατάλογο /etc/bind, οπότε ας μεταβούμε σ’ αυτόν:

cd /etc/bind

Το βασικό αρχείο ρυθμίσεων είναι το named.conf (named είναι το εναλλακτικό όνομα του BIND). Όπως είναι μετά την εγκατάσταση, το εν λόγω αρχείο δεν κάνει τίποτε άλλο από το να διαβάζει τα περιεχόμενα των αρχείων named.conf.default-zones, named.conf.local και named.conf.options. Στο παρόν άρθρο –και για τα είδη των name servers που μας ενδιαφέρουν– θα μας απασχολήσει μόνο το named.conf.options.

Recursive name server

Όπως προαναφέραμε το BIND είναι εξαιρετικά ευέλικτο, κι αμέσως τώρα θα του πούμε να συμπεριφέρεται ως caching name server με δυνατότητες recursion. Χωρίς άλλες περιστροφές ανοίγουμε το αρχείο named.conf.options με έναν text editor, όπως, π.χ., είναι το nano:

sudo nano named.conf.options

Ιδού πώς δείχνει το αρχείο χωρίς τα σχόλια:

options {
    directory "/var/cache/bind";

    dnssec-validation auto;

    auth-nxdomain no;
    listen-on-v6 { any; };
};

Πρώτη μας δουλειά είναι να ορίσουμε ένα ACL (Access Control List), δηλαδή μια λίστα, με τους πελάτες που επιτρέπεται να μιλούν με τον name server. Ο ορισμός αυτής της λίστας γίνεται στην αρχή του αρχείου named.conf.options κι έξω από το μπλοκ ονόματι options. Τη λίστα την ονομάζουμε όπως θέλουμε:

acl goodfellas {
    10.0.0.0/24;
    localhost;  
};

Επηρεασμένοι από την ταινία GoodFellas που θυμηθήκαμε προσφάτως, ονομάσαμε τη λίστα μας goodfellas (όλα πεζά) και φροντίσαμε ώστε να περιλαμβάνει:

  • όλα τα μηχανήματα με IP της μορφής 10.0.0.*, αφού αυτές είναι οι διευθύνσεις IP που παίρνουν οι clients του τοπικού μας δικτύου

  • το τοπικό μηχάνημα (localhost), ώστε οι εφαρμογές του συστήματος να είναι σε θέση να χρησιμοποιούν κι αυτές τον name server

Σημειώστε ότι στη θέση των 10.0.0.0/24 και 127.0.0.1 κάλλιστα μπορούμε να βάλουμε το localnets, το οποίο πάντα σημαίνει “το τοπικό μηχάνημα μαζί με τα δίκτυα κάθε network interface”. Πιο συγκεκριμένα: Το μηχάνημά μας με το BIND διαθέτει μία μόνο κάρτα δικτύου Ethernet (ένα network interface), έχει διεύθυνση IP την 10.0.0.5 και μάσκα δικτύου την 255.255.255.0, επομένως για την περίπτωση του παραδείγματός μας το localnet σημαίνει “127.0.0.1 και 10.0.0.0/24”. Το goodfellas, λοιπόν, μπορεί να οριστεί συντομότερα κι έτσι:

acl goodfellas {
    localnets;  
};

Να πώς μοιάζει το named.conf.options ως αυτή τη στιγμή:

acl goodfellas {
    localnets;  
};

options {
    directory "/var/cache/bind";

    dnssec-validation auto;

    auth-nxdomain no;
    listen-on-v6 { any; };
};

Ο ορισμός του ACL δεν είναι αρκετός, ώστε τα queries από τα μηχανήματα που περιγράφει να γίνονται αποδεκτά. Απαιτείται επιπρόσθετα η οδηγία allow-query { goodfellas; };, εντός του μπλοκ options. Χρειάζεται εξάλλου να ζητήσουμε την ενεργοποίηση του recursion με την οδηγία recursion yes; – πάντα μέσα στο μπλοκ options. Δείτε ξανά το named.conf.options, το οποίο πλέον περιλαμβάνει και τις δύο προαναφερθείσες οδηγίες:

acl goodfellas {
    localnets;  
};

options {
    directory "/var/cache/bind";

    recursion yes;
    allow-query { goodfellas; };

    dnssec-validation auto;

    auth-nxdomain no;
    listen-on-v6 { any; };
};

Δεν χρειάζεται καμία άλλη ρύθμιση ώστε το BIND να λειτουργεί ως caching name server με ικανότητες recursion. Αν δεν θέλετε να συμπεριφέρεται ως forwarding name server, τότε προσπεράστε την επόμενη ενότητα και συνεχίστε με τη μεθεπόμενη. Διαφορετικά συνεχίστε το διάβασμα κανονικά.

Forwarding name server

Ξεκινάμε από το τροποποιημένο named.conf.options, ακριβώς όπως το αφήσαμε στην προηγούμενη ενότητα. Προσοχή: Επειδή φτιάχνουμε έναν forwarding name server, δεν σημαίνει ότι τώρα θ’ αλλάξουμε την οδηγία recursion yes; σε recursion no;. Αντιθέτως θα την αφήσουμε ως έχει, αφού ο name server συνεχίζει ν’ απαντά για domains που δεν είναι στην ευθύνη του κι επομένως για τους πελάτες συνεχίζει να παρέχει recursive υπηρεσίες. Σίγουρα φορτώνει το μεγαλύτερο μέρος της δουλειάς σε άλλους name servers, αλλά αυτό δεν έχει σημασία και υπό μία έννοια είναι recursive. Και μιας κι αναφερθήκαμε σ’ αυτούς τους άλλους servers, ας ορίσουμε μια λίστα με caching name servers στους οποίους θα προωθούνται τα αιτήματα των πελατών. Ο ορισμός λαμβάνει χώρα εντός του μπλοκ options:

forwarders {
    8.8.8.8;
    8.8.4.4;
};

Η λίστα υλοποιήθηκε με το μπλοκ forwarders και περιλαμβάνει τους δύο δημόσιους name servers που απλόχερα παρέχει η Google. Θα μπορούσαμε να χρησιμοποιήσουμε άλλους, όπως, π.χ., εκείνους της OpenDNS (208.67.222.222 και 208.67.220.220) ή ακόμη και συνδυασμούς. Χρωστάμε και την οδηγία forward only;, ώστε ο name server μας να προωθεί πάντα τα αιτήματα των πελατών και να μην επιχειρεί να τα εξυπηρετεί ο ίδιος (εκτός κι αν έχει τις απαντήσεις στην cache του, δηλαδή). Δείτε παρακάτω όλα τα περιεχόμενα του αρχείου named.conf.options για τον forwarding name server μας:

acl goodfellas {
    localnets;
};

options {
    directory "/var/cache/bind";

    recursion yes;
    allow-query { goodfellas; };

    forwarders {
        8.8.8.8;
        8.8.4.4;
    };

    forward only;

    dnssec-enable yes;
    dnssec-validation yes;

    auth-nxdomain no;
    listen-on-v6 { any; };
};

Οι παρατηρητικοί θα διαπιστώσατε ότι:

  • το dnssec-validation auto; έχει γίνει dnssec-validation yes;
  • από πάνω του έχει προστεθεί η οδηγία dnssec-enable yes;

Χωρίς αυτές τις δύο αλλαγές, οι ρυθμίσεις DNSSEC των name servers στους οποίους προωθούμε τα αιτήματα θα μολύνουν τα log files του server μας με μηνύματα λάθους.

Έλεγχος ορθής λειτουργίας κι ενεργοποίηση

Αποθηκεύουμε τις αλλαγές στο αρχείο named.conf.options (στο nano, π.χ., δίνουμε [CTRL+O], [Enter]) κι αμέσως εγκαταλείπουμε τον editor (π.χ., με [CTRL+X] στο nano). Έχοντας δικαιώματα root ανοίγουμε στα γρήγορα το αρχείο ρυθμίσεων του BIND daemon, το /etc/default/bind9:

sudo nano /etc/default/bind9

Φροντίζουμε ώστε η γραμμή

OPTIONS="-u bind"

να γίνει

OPTIONS="-u bind -4"

Αποθηκεύουμε την αλλαγή κι εγκαταλείπουμε τον editor. Μόλις προσθέσαμε αυτό το -4 και, ως αποτέλεσμα, το BIND σε λίγο θα δέχεται μόνο αιτήματα για resolving διευθύνσεων IPv4. Στο Ubuntu, εξάλλου, η υπηρεσία ενεργοποιείται αμέσως μετά την εγκατάσταση του αντίστοιχου πακέτου (bind9). Αυτή τη στιγμή βέβαια δεν έχουν ληφθεί υπόψη οι τροποποιήσεις στο /etc/bind/named.conf.options και, πριν επανεκκινήσουμε το BIND ώστε να τις διαβάσει, είναι καλή ιδέα να ελέγξουμε το named.conf.options για συντακτικά λάθη. Προς τούτο θα καταφύγουμε στο εργαλείο named-checkconf, το οποίο βρισκόταν στο πακέτο bind9utils που εγκαταστήσαμε νωρίτερα:

sudo named-checkconf

Αν δεν υπάρχει λάθος, τότε το παραπάνω δεν θα επιστρέψει κάτι. Ας επανεκκινήσουμε λοιπόν το BIND:

sudo service bind9 restart

Έξοδος:

* Stopping domain name service...   bind9
waiting for pid 1341 to die         [ OK ]
* Starting domain name service...   bind9 [ OK ] 

Πολύ ωραία. Ένας τρόπος για να βεβαιωθούμε ότι το BIND αφουγκράζεται για αιτήματα πελατών, είναι με τη βοήθεια του netstat:

sudo netstat -antp

Έξοδος:

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 10.0.0.5:53             0.0.0.0:*               LISTEN      1622/named      
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      1622/named      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1312/sshd       
tcp        0      0 127.0.0.1:953           0.0.0.0:*               LISTEN      1622/named      
tcp        0     36 10.0.0.5:22             10.0.0.104:60922        ESTABLISHED 1483/sshd: admin [p
tcp6       0      0 :::22                   :::*                    LISTEN      1312/sshd       

Παρατηρούμε ότι το BIND δέχεται αιτήματα από το port 53/TCP και, όπως βλέπετε, στο σύστημά μας τα αναμένει από το network interface με IP το 10.0.0.5, αλλά κι από το loopback interface με IP το 127.0.0.1.

Δοκιμές και σύγκριση επιδόσεων

Τις πρώτες μας δοκιμές μπορούμε να τις κάνουμε από μια κονσόλα του ίδιου του Ubuntu Server με τη βοήθεια του εργαλείου dig, το οποίο παρέχεται από το πακέτο dnsutils που είναι ήδη εγκατεστημένο. Ας ζητήσουμε από τον τοπικό name server το IP του colder.xyz:

dig @127.0.0.1 colder.xyz

Έξοδος:

; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> colder.xyz
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12027
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;colder.xyz.            IN  A

;; ANSWER SECTION:
colder.xyz.     1799    IN  A   46.101.173.140

;; Query time: 290 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Sep 27 09:34:07 EEST 2015
;; MSG SIZE  rcvd: 55

Προκειμένου να μην ερωτηθεί ο name server που ήδη γνωρίζει το μηχάνημα αλλά ο τοπικός, στο dig δώσαμε την οδηγία @127.0.0.1. Το BIND δεν είχε το IP του colder.xyz στην cache του, το αναζήτησε, το βρήκε (είναι το 46.101.173.140), το αποθήκευσε στην cache του και το επέστρεψε στον πελάτη (που σ’ αυτή την περίπτωση είναι το dig). Η διαδικασία της αναζήτησης διήρκεσε 290 χιλιοστά του δευτερολέπτου (290 msec, βλ. γραμμή με το Query time). Ας ρωτήσουμε ξανά το BIND, πάλι για το colder.xyz:

dig @127.0.0.1 colder.xyz

Έξοδος:

; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> @127.0.0.1 colder.xyz
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21003
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;colder.xyz.            IN  A

;; ANSWER SECTION:
colder.xyz.     1246    IN  A   46.101.173.140

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Sep 27 09:43:20 EEST 2015
;; MSG SIZE  rcvd: 55 

Αυτή τη φορά το BIND είχε τη ζητούμενη πληροφορία στην cache του, οπότε το ερώτημα εξυπηρετήθηκε σε μηδενικό, πρακτικά, χρόνο! (Query time: 0 msec) Τώρα, για να εκτιμήσουμε πόσο μεγάλη βελτίωση στις επιδόσεις προσφέρει ένας τοπικός name server, ας απευθύνουμε το ίδιο ερώτημα διαδοχικά σε έναν εξωτερικό, όπως, π.χ., είναι ο 8.8.8.8 της Google. Θα καταφύγουμε και πάλι στο dig αλλά για οικονομία χώρου θα φιλτράρουμε την έξοδό του με το grep, ώστε να βλέπουμε μόνο τη γραμμή με το “Query time”:

dig @8.8.8.8 colder.xyz | grep "Query time"
;; Query time: 301 msec
dig @8.8.8.8 colder.xyz | grep "Query time"
;; Query time: 85 msec
dig @8.8.8.8 colder.xyz | grep "Query time"
;; Query time: 124 msec
dig @8.8.8.8 colder.xyz | grep "Query time"
;; Query time: 116 msec
dig @8.8.8.8 colder.xyz | grep "Query time"
;; Query time: 73 msec

Αμέσως μετά το πρώτο ερώτημα, το οποίο απαντήθηκε σε 301 msec, ο name server της Google αποθηκεύει στην cache του το IP του colder.xyz και στα επόμενα ερωτήματα απαντά γρηγορότερα (85 msec, 124 msec, 116 msec, 73 msec κ.ο.κ.) Παρά το γεγονός ότι πρόκειται για πανίσχυρο μηχάνημα, λόγω της απόστασής του από το δίκτυό μας είναι αδύνατον να συναγωνιστεί τον τοπικό μας name server.

Τον νέο μας name server καλό είναι να μην τον δοκιμάζουμε μόνο τοπικά, αλλά κι από κάποιο άλλο μηχάνημα του τοπικού δικτύου.Τον νέο μας name server καλό είναι να μην τον δοκιμάζουμε μόνο τοπικά, αλλά κι από κάποιο άλλο μηχάνημα του τοπικού δικτύου. Στο screenshot φαίνεται μέρος των ελέγχων που κάναμε στο πλαίσιο της προετοιμασίας του παρόντος άρθρου. Ο name server βρισκόταν στη διεύθυνση 192.168.201.133, ενώ ο υπολογιστής από τον οποίο εργαζόμασταν είχε ήδη ενημερωθεί για την παρουσία του. Παρατηρήστε τη διαφορά στους χρόνους απόκρισης μεταξύ δύο διαδοχικών ερωτημάτων για το ίδιο domain: Την πρώτη φορά η απάντηση ήλθε σε 150 msec, ενώ τη δεύτερη 150 φορές γρηγορότερα.

Άρθρα της σειράς

Εισαγωγή στο Domain Name System

Οι name servers στο μικροσκόπιο

Zone files και resource records

Ο δικός μας caching name server

Στρατηγικές εκμετάλλευσης του name server μας