% !TeX document-id = {d31ec456-0f13-4d95-9fc2-bd99b70397a1} % !TeX TXS-program:compile = txs:///xelatex/[-shell-escape] % !TEX encoding = UTF-8 Unicode % !TEX spellcheck = el-GR % % Compiter Networks II report % % Requires compilation with pdfLaTeX or XeLaTeX % % authors: % Χρήστος Χουτουρίδης ΑΕΜ 8997 % cchoutou@ece.auth.gr % % Options: % % 1) mainlang= % Default: english % Set the default language of the document which affects hyphenations, % localization (section, dates, etc...) % % example: \documentclass[mainlang=greek]{AUThReport} % % 2) % Add hyphenation and typesetting support for other languages % Currently supports: english, greek, german, frenc % % example: \documentclass[english, greek]{AUThReport} % % 3) short: Requests a shorter title for the document % Default: no short % % example: \documentclass[short]{AUThReport} % \documentclass[a4paper, 11pt, mainlang=greek, english]{AUThReport/AUThReport} \CurrentDate{\today} % Document setup %--------------------------------- % \WorkGroup{Ομάδα Χ} \AuthorName{Χρήστος Χουτουρίδης} \AuthorMail{cchoutou@ece.auth.gr} \AuthorAEM{8997} %\CoAuthorName{Όνομα Επίθετο} %\CoAuthorAEM{AEM} %\CoAuthorMail{xxx@ece.auth.gr} \DocTitle{Αυτοματοποιημένη Ανάπτυξη Τοπολογίας και Ανάλυση Πρωτοκόλλων στο Mininet} %\DocSubTitle{Ανάλυση και υλοποίηση του αλγόριθμου bitonic sort για υποσύστημα γραφικών με χρήση CUDA} \Department{Τμήμα ΗΜΜΥ. Τομέας Ηλεκτρονικής} \ClassName{Δίκτυα Υπολογιστών ΙΙ} % \InstructorName{Αναστάσιος Ντελόπουλος} \InstructorMail{antelopo@ece.auth.gr} \CoInstructorName{Εμανουήλ Τσαρδουλιάς} \CoInstructorMail{etsardou@ece.auth.gr} % Local package requirements %--------------------------------- \usepackage{enumitem} \usepackage{tabularx} \usepackage{array} \usepackage{multirow} \usepackage{float} \usepackage{xcolor} \usepackage{soul} \usepackage{amsmath} \usepackage{footnote} \usepackage{footmisc} \usepackage{minted} \usepackage{xcolor} % \setminted[python]{ fontsize=\small, breaklines, autogobble, baselinestretch=1.1, obeytabs=true tabsize=2, numbersep=8pt, startinline, gobble=0 } \setminted[json]{ fontsize=\small, breaklines, autogobble, baselinestretch=1.1, obeytabs=true tabsize=2, numbersep=8pt, startinline, gobble=0 } \setminted[bash]{ fontsize=\small, breaklines, autogobble, baselinestretch=1.1, obeytabs=true tabsize=2, numbersep=8pt, startinline, gobble=0 } %\definecolor{red-highlight}{rgb}{1.0, 0.11, 0.0} \definecolor{red-highlight}{rgb}{1.0, 0.31, 0.0} \definecolor{green-highlight}{rgb}{0.0, 0.62, 0.42} \newcommand{\bxrd}[1]{\colorbox{red-highlight}{#1}} \newcommand{\bxgr}[1]{\colorbox{green-highlight}{#1}} \newcommand{\trd}[1]{\textcolor{red-highlight}{\textbf{#1}}} \newcommand{\tgr}[1]{\textcolor{green-highlight}{\textbf{#1}}} % “virtual” cites % ---------------------------------------- %\newcommand{\citeKnuthACM}{% % Donald E. Knuth, \emph{Structured Programming with go to Statements}, ACM Computing Surveys, vol. 6, no. 4, 1974 %} % Links % Repository links % ---------------------------------------- \newcommand{\repoGithub}{https://github.com/hoo2/Computer-Networks-II} \newcommand{\repoGitea}{https://git.hoo2.net/hoo2/Computer-Networks-II} \newcommand{\topologyJsonUrl}{\repoGithub/blob/HEAD/exercise/topology.json} \newcommand{\buildNetworkUrl}{\repoGithub/blob/HEAD/source/build_network.py} \newcommand{\resultsUrl}{\repoGithub/tree/HEAD/exercise/results} \newcommand{\dslDesignUrl}{\repoGithub/blob/HEAD/Mininet_DSL_Design.md} % Experiment 1 \newcommand{\dhcpExecutionUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/execution.txt} \newcommand{\dhcpDecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/dhcp-decoded.txt} \newcommand{\dhcpPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp1-dhcp/dhcp.pcap} % Experiment 2 \newcommand{\arpExecutionUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/execution.txt} \newcommand{\arpDecodedUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/arp-decoded.txt} \newcommand{\arpPcapUrl}{\repoGithub/blob/HEAD/exercise/results/exp2-arp/arp.pcap} \begin{document} \InsertTitle %\tableofcontents \section{Εισαγωγή} Η παρούσα εργασία έχει ως αντικείμενο την \textbf{αυτοματοποιημένη ανάπτυξη δικτυακών τοπολογιών στο περιβάλλον Mininet}, με βάση μια δηλωτική περιγραφή σε αρχείο JSON. Στο πλαίσιο αυτό υλοποιείται εφαρμογή σε Python, η οποία διαβάζει περιγραφές της τοπολογίας σε μια πρότυπη \textbf{Domain-Specific Language -- DSL}, και δημιουργεί δυναμικά τους αντίστοιχους hosts, μεταγωγείς, συνδέσμους και δρομολογητές και εφαρμόζει τις απαιτούμενες ρυθμίσεις δικτύου. Το Mininet χρησιμοποιείται ως περιβάλλον εξομοίωσης, ώστε η τοπολογία να μπορεί να κατασκευάζεται και να εξετάζεται με χρήση των ίδιων εργαλείων και πρωτοκόλλων που χρησιμοποιούνται σε ένα πραγματικό σύστημα Linux. Μετά την ανάπτυξη της τοπολογίας πραγματοποιούνται τρία πειράματα χαμηλού επιπέδου για τη μελέτη των πρωτοκόλλων \textbf{DHCP} και \textbf{ARP}, καθώς και της \textbf{δρομολόγησης μεταξύ διαφορετικών υποδικτύων}. Μέσω καταγραφών με το \texttt{tcpdump} εξετάζεται η διαδικασία D.O.R.A. του DHCP, η αντιστοίχιση διευθύνσεων IP σε διευθύνσεις MAC μέσω του ARP και η μεταβολή των Ethernet διευθύνσεων και του TTL κατά τη διέλευση ενός IP πακέτου από τον δρομολογητή. Στόχος των πειραμάτων είναι η σύνδεση της θεωρητικής λειτουργίας των πρωτοκόλλων με την πραγματική μορφή των πακέτων που ανταλλάσσονται στα διαφορετικά επίπεδα του δικτύου. \subsection{Παραδοτέα} Τα παραδοτέα της εργασίας αποτελούνται από: \begin{itemize} \item Την παρούσα τεχνική αναφορά. \item Το αρχείο \href{\topologyJsonUrl}{\texttt{exercise/topology.json}}, το οποίο περιγράφει δηλωτικά την τοπολογία δικτύου που χρησιμοποιείται στην εργασία. \item Τον κατάλογο \texttt{source/}, ο οποίος περιέχει το αρχείο \href{\buildNetworkUrl}{\texttt{build\_network.py}}, καθώς και τα υπόλοιπα αρχεία Python που υλοποιούν την εφαρμογή. \item Τον κατάλογο \href{\resultsUrl}{\texttt{exercise/results/}}, ο οποίος περιέχει τις μετρήσεις και τα παραγόμενα αρχεία των πειραμάτων της εργασίας. \item Τους συνδέσμους προς τα αποθετήρια στο \href{\repoGithub}{GitHub} και στον \href{\repoGitea}{προσωπικό μου server}, τα οποία περιέχουν τον πηγαίο κώδικα, τον κώδικα παραγωγής της αναφοράς και τα αποτελέσματα των πειραμάτων. \end{itemize} \section{Υλοποίηση} % ========================= DSL ========================= \subsection{Δηλωτική γλώσσα περιγραφής τοπολογίας} Για την περιγραφή των δικτυακών τοπολογιών σχεδιάστηκε μία μικρή \textbf{δηλωτική γλώσσα ειδικού σκοπού} (Domain-Specific Language -- DSL), η οποία χρησιμοποιεί το JSON ως μορφή αναπαράστασης. Στόχος της γλώσσας είναι να περιγράφει την \emph{επιθυμητή κατάσταση του δικτύου} και όχι τη σειρά των εντολών που απαιτούνται για την κατασκευή του στο Mininet. Με αυτόν τον τρόπο η περιγραφή της τοπολογίας παραμένει ανεξάρτητη από λεπτομέρειες της υλοποίησης, όπως τα ονόματα των εικονικών διεπαφών ή η ακριβής ακολουθία κλήσεων προς το Mininet API. Η αναλυτική σχεδίαση και η γραμματική της γλώσσας τεκμηριώνονται επίσης στο αρχείο \href{\dslDesignUrl}{\texttt{Mininet\_DSL\_Design.md}} του αποθετηρίου. \subsubsection{Σχεδιαστική προσέγγιση} Ο σχεδιασμός της γλώσσας πραγματοποιήθηκε \textbf{από πάνω προς τα κάτω}, ξεκινώντας από τις έννοιες που είναι φυσικό να χρησιμοποιούνται για την περιγραφή ενός δικτύου, όπως οι \emph{κόμβοι}, οι \emph{διεπαφές}, οι \emph{σύνδεσμοι} και οι \emph{υπηρεσίες}. Παράλληλα, κάθε αφηρημένη έννοια επιλέχθηκε έχοντας υπόψη τις διαθέσιμες πρωτογενείς λειτουργίες του Mininet και του δικτυακού υποσυστήματος του Linux. Η προσέγγιση αυτή επιτρέπει στη γλώσσα να παραμένει υψηλού επιπέδου, χωρίς να εισάγει κατασκευές που δεν μπορούν να μεταφραστούν με σαφή και συστηματικό τρόπο στο υποκείμενο περιβάλλον εκτέλεσης. Οι βασικές λειτουργίες που απαιτούνται από την εργασία μπορούν να αναχθούν σε ένα σχετικά μικρό σύνολο \emph{πρωτογενών κατασκευών} του Mininet και του Linux. Η δημιουργία hosts και switches, η σύνδεσή τους μέσω links και η εκτέλεση εντολών μέσα στους αντίστοιχους network namespaces επαρκούν για την κατασκευή της απαιτούμενης τοπολογίας. Ένας δρομολογητής μπορεί αντίστοιχα να μοντελοποιηθεί ως host με περισσότερες από μία διεπαφές, κατάλληλη Layer-3 διευθυνσιοδότηση και ενεργοποιημένη προώθηση IP. Ο DHCP server μπορεί να θεωρηθεί ως υπηρεσία που εκτελείται σε έναν κόμβο και συνδέεται με συγκεκριμένη διεπαφή. Πριν οριστικοποιηθούν οι οντότητες της DSL, εξετάστηκαν οι βασικές λειτουργίες που παρέχει το Mininet και το δικτυακό υποσύστημα του Linux για την κατασκευή και παραμετροποίηση μιας τοπολογίας. Οι κύριες λειτουργίες που χρησιμοποιήθηκαν ως βάση είναι οι \texttt{addHost()}, \texttt{addSwitch()} και \texttt{addLink()}, καθώς και η δυνατότητα εκτέλεσης εντολών μέσα σε κάθε network namespace μέσω του \texttt{node.cmd()}. Στις λειτουργίες αυτές προστίθενται η παραμετροποίηση διεπαφών και δρομολόγησης μέσω εργαλείων του Linux και η εκκίνηση διεργασιών, όπως ο \texttt{dnsmasq}, μέσα στον αντίστοιχο κόμβο. Η ανάλυση αυτή χρησιμοποιήθηκε για να \textbf{σταθεροποιηθεί το σύνολο των αφαιρέσεων της DSL}, έτσι ώστε κάθε υψηλού επιπέδου κατασκευή να έχει σαφή δρόμο μετάφρασης προς τις διαθέσιμες λειτουργίες του backend. Με βάση τις παρατηρήσεις αυτές επιλέχθηκε ένα σύνολο οντοτήτων ώστε η DSL να \textbf{καλύπτει τον χώρο των κατασκευών που απαιτούνται από την εργασία}. Αντίστοιχα, το σύνολο των primitives του Mininet και του Linux που χρησιμοποιείται είναι επαρκές ώστε κάθε κατασκευή της DSL να μπορεί να μεταφραστεί σε συγκεκριμένες λειτουργίες του backend. Με αυτή την έννοια, τόσο η γλώσσα ως προς τον χώρο του προβλήματος όσο και τα χρησιμοποιούμενα primitives ως προς τον χώρο της υλοποίησης λειτουργούν \emph{«επί»}. Δηλαδή, δεν παραμένει απαίτηση της εργασίας χωρίς αναπαράσταση στη DSL ούτε κατασκευή της DSL χωρίς αντίστοιχη υλοποίηση στο Mininet και στο Linux. Οι βασικές οντότητες της γλώσσας είναι οι \emph{κόμβοι}, οι \emph{διεπαφές}, οι \emph{σύνδεσμοι}, οι \emph{ρυθμίσεις κόμβων} και οι \emph{υπηρεσίες}. \subsubsection{Βασική γραμματική} Η τοπολογία περιγράφεται από τρεις κύριες κατηγορίες αντικειμένων: \texttt{nodes}, \texttt{links} και \texttt{services}. Η βασική δομή της γλώσσας μπορεί να συνοψιστεί ως εξής: \begin{verbatim} Network |-- Nodes | |-- name | |-- type | |-- interfaces | `-- settings | |-- Links | |-- name | |-- endpoints | | |-- node | | `-- interface | `-- settings | `-- Services |-- type |-- node |-- interface `-- settings \end{verbatim} Κάθε κατηγορία έχει \textbf{διαφορετική σημασιολογική ευθύνη}. Ένας κόμβος(node) αναπαριστά έναν συμμετέχοντα του δικτύου, μία διεπαφή(interface) ένα σημείο σύνδεσης που ανήκει σε έναν κόμβο και ένας σύνδεσμος(link) συνδέει δύο τέτοια σημεία. Οι ρυθμίσεις(settings) κόμβου περιγράφουν ιδιότητες του ίδιου του δικτυακού namespace, ενώ οι υπηρεσίες(services) αναπαριστούν ανεξάρτητες διεργασίες που εκτελούνται μέσα σε αυτό. \subsubsection{Κόμβοι και διεπαφές} Οι κόμβοι δηλώνονται με ένα μοναδικό λογικό όνομα και έναν τύπο. Οι τύποι που υποστηρίζονται στην παρούσα υλοποίηση είναι \texttt{host}, \texttt{switch} και \texttt{router}. Ο τύπος εκφράζει τη \emph{σημασιολογία του κόμβου} και όχι απαραίτητα το συγκεκριμένο αντικείμενο του Mininet που θα χρησιμοποιηθεί για την υλοποίησή του. Οι διεπαφές \textbf{ανήκουν στους κόμβους} και προσδιορίζονται από λογικά ονόματα, τα οποία δεν απαιτείται να ταυτίζονται με τα ονόματα που θα δημιουργηθούν τελικά στο Linux. Για παράδειγμα, μία διεπαφή με λογικό όνομα \texttt{lan} μπορεί κατά την υλοποίηση να αντιστοιχιστεί στη φυσική διεπαφή \texttt{r0-eth0}. Η επιλογή αυτή επιτρέπει στο αρχείο JSON να χρησιμοποιεί ονόματα που εκφράζουν τον ρόλο μιας διεπαφής και όχι λεπτομέρειες της διαδικασίας δημιουργίας της. Μία διεπαφή μπορεί να χρησιμοποιεί στατική διευθυνσιοδότηση, DHCP ή να μην διαθέτει καθόλου Layer-3 παραμετροποίηση. Στην περίπτωση στατικής διευθυνσιοδότησης δηλώνεται η διεύθυνση μαζί με το prefix και, προαιρετικά, μία προεπιλεγμένη πύλη. Επιπλέον μπορούν να δηλωθούν ιδιότητες όπως η διεύθυνση MAC και το MTU. Ιδιαίτερη σημασία έχει η διάκριση μεταξύ της \textbf{απουσίας} του πεδίου \texttt{interfaces} και της δήλωσης ενός κενού αντικειμένου \texttt{interfaces}. Όταν το πεδίο παραλείπεται, ο κόμβος θεωρείται ότι διαθέτει \emph{δυναμικό σύνολο διεπαφών} και νέες διεπαφές μπορούν να δημιουργηθούν κατά την επίλυση των συνδέσμων. Αντίθετα, όταν το πεδίο υπάρχει, ακόμη και αν είναι κενό, το σύνολο των διαθέσιμων διεπαφών θεωρείται \emph{σταθερό}. \subsubsection{Σύνδεσμοι και αυτόματη επιλογή διεπαφών} Κάθε σύνδεσμος αποτελεί αυτοτελή οντότητα και συνδέει ακριβώς δύο endpoints. Κάθε endpoint προσδιορίζει τον κόμβο στον οποίο ανήκει και τη λογική διεπαφή μέσω της οποίας πραγματοποιείται η σύνδεση. Η διεπαφή μπορεί να δηλωθεί ρητά ή να χρησιμοποιηθεί ο ειδικός επιλογέας \texttt{auto}. Όταν χρησιμοποιείται το \texttt{auto} σε κόμβο με σταθερό σύνολο διεπαφών, επιλέγεται μία από τις δηλωμένες διεπαφές που δεν έχει ήδη δεσμευτεί από άλλη σύνδεση. Αν δεν υπάρχει ελεύθερη διεπαφή, η τοπολογία θεωρείται μη έγκυρη και \textbf{δεν δημιουργείται επιπλέον θύρα σιωπηρά}. Όταν αντίθετα το σύνολο διεπαφών έχει παραλειφθεί, το \texttt{auto} επιτρέπει τη δυναμική δημιουργία νέας λογικής διεπαφής για τις ανάγκες του συνδέσμου. Οι σύνδεσμοι μπορούν επίσης να περιλαμβάνουν παραμέτρους προσομοίωσης χαρακτηριστικών του φυσικού μέσου. Η τρέχουσα γλώσσα υποστηρίζει περιορισμό εύρους ζώνης, καθυστέρηση, απώλεια πακέτων και jitter μέσω των πεδίων \texttt{bandwidth\_mbps}, \texttt{delay\_ms}, \texttt{loss\_percent} και \texttt{jitter\_ms}. \subsubsection{Ρυθμίσεις κόμβων και υπηρεσίες} Οι ρυθμίσεις που αφορούν τη λειτουργία του ίδιου του κόμβου τοποθετούνται στο αντικείμενο \texttt{settings} του αντίστοιχου node. Για τον τύπο \texttt{router}, για παράδειγμα, υποστηρίζονται η ενεργοποίηση του IP forwarding και η απενεργοποίηση του reverse path filtering. Οι ιδιότητες αυτές αντιμετωπίζονται ως \emph{χαρακτηριστικά του network namespace} και όχι ως ανεξάρτητες υπηρεσίες. Οι υπηρεσίες μοντελοποιούνται ξεχωριστά επειδή αντιστοιχούν σε \textbf{διεργασίες που εκτελούνται πάνω σε έναν κόμβο}. Στην παρούσα εργασία υποστηρίζεται η υπηρεσία \texttt{dhcp-server}, η οποία συνδέεται με έναν κόμβο και μία από τις διεπαφές του. Οι παράμετροι της υπηρεσίας περιλαμβάνουν το εύρος διευθύνσεων που μπορούν να εκχωρηθούν και την προεπιλεγμένη πύλη που διαφημίζεται στους DHCP clients. Η θέση εκτέλεσης μιας υπηρεσίας και η διεπαφή στην οποία συνδέεται αποτελούν μέρος της ίδιας της ταυτότητάς της και για τον λόγο αυτό δηλώνονται έξω από το αντικείμενο \texttt{settings}. Με αυτόν τον διαχωρισμό, το \texttt{settings} περιγράφει αποκλειστικά τη συμπεριφορά της υπηρεσίας και όχι το σημείο στο οποίο αυτή τοποθετείται μέσα στην τοπολογία. \subsubsection{Αυστηρότητα της γραμματικής} Η γραμματική σχεδιάστηκε ώστε να είναι \textbf{αυστηρή} και να μην αγνοεί άγνωστα πεδία ή μη υποστηριζόμενες τιμές. Ένα τυπογραφικό λάθος σε ένα όνομα ιδιότητας δεν αντιμετωπίζεται επομένως ως απουσία της ιδιότητας, αλλά ως σφάλμα της περιγραφής. Η επιλογή αυτή περιορίζει την πιθανότητα μία συντακτικά αποδεκτή αλλά διαφορετική από την επιθυμητή τοπολογία να δημιουργηθεί χωρίς εμφανή προειδοποίηση. Η γλώσσα διαχωρίζει επίσης τη \emph{δομική εγκυρότητα} μιας περιγραφής από τη \emph{σημασιολογική συνέπειά} της. Ένα αντικείμενο μπορεί να ακολουθεί σωστά τη γραμματική αλλά να περιγράφει, για παράδειγμα, έναν σύνδεσμο προς ανύπαρκτο κόμβο ή μία στατική πύλη εκτός του αντίστοιχου υποδικτύου. Η διάκριση αυτή αξιοποιείται στη συνέχεια από την αρχιτεκτονική του builder, όπου η ανάλυση της γραμματικής και ο σημασιολογικός έλεγχος πραγματοποιούνται σε \textbf{διαφορετικά στάδια}. % ========================= Builder ========================= \subsection{Υλοποίηση του Builder} Η υλοποίηση του builder ακολουθεί τον διαχωρισμό που εισάγει η DSL και οργανώνεται ως μία ακολουθία ανεξάρτητων σταδίων, καθένα από τα οποία μετασχηματίζει την πληροφορία σε μία περισσότερο συγκεκριμένη αναπαράσταση. Η δομή αυτή επιτρέπει τον σαφή διαχωρισμό ανάμεσα στην περιγραφή της τοπολογίας, στον έλεγχο της εγκυρότητάς της και στην τελική δημιουργία και εκτέλεση του δικτύου στο Mininet. \subsubsection{Δομή των αρχείων} Ο πηγαίος κώδικας του builder βρίσκεται στον κατάλογο \texttt{source/}, ενώ η περιγραφή και τα αποτελέσματα της συγκεκριμένης εργαστηριακής άσκησης διατηρούνται χωριστά στον κατάλογο \texttt{exercise/}. Η βασική δομή του αποθετηρίου είναι η ακόλουθη: \begin{verbatim} . |-- source/ | |-- build_network.py | |-- topology_loader.py | |-- topology_parser.py | |-- topology_validator.py | |-- topology_plan.py | `-- topology_renderer.py | |-- exercise/ | |-- topology.json | |-- topology.generated.py | `-- results/ | |-- Mininet_DSL_Design.md `-- README.md \end{verbatim} \begin{itemize} \item Το \texttt{topology\_loader.py} είναι υπεύθυνο αποκλειστικά για τη φόρτωση του αρχείου JSON από το σύστημα αρχείων και την παραγωγή της αντίστοιχης ακατέργαστης Python δομής. \item Το \texttt{topology\_parser.py} περιέχει τη γραμματική, τα \texttt{Enum} και τα \texttt{dataclass} αντικείμενα που αποτελούν το τυποποιημένο σημασιολογικό μοντέλο της DSL. \item Το \texttt{topology\_validator.py} ελέγχει τη σημασιολογική συνέπεια της τοπολογίας, χωρίς να πραγματοποιεί οποιαδήποτε μεταβολή στο δίκτυο. \item Το \texttt{topology\_plan.py} επιλύει τις αφηρημένες επιλογές της DSL και παράγει ένα πλήρως συγκεκριμένο \texttt{ExecutionPlan}. \item Το \texttt{topology\_renderer.py} μετατρέπει το σχέδιο αυτό σε εκτελέσιμο Python κώδικα για το Mininet, οποίος εξάγεται σε ξεχωριστό αρχείο και αποτελεί ένα ιδιότυπο \emph{python-listing} του renderer. \item Τέλος, το \texttt{build\_network.py} αποτελεί τον \textbf{coordinator} και το μοναδικό user-facing entry point, συνδέοντας τα επιμέρους στάδια και αναλαμβάνοντας την τελική εκτέλεση του παραγόμενου προγράμματος. \end{itemize} \subsubsection{Χρήση} Η κανονική χρήση του builder απαιτεί μόνο το αρχείο JSON που περιγράφει την επιθυμητή τοπολογία. Για την τοπολογία της παρούσας εργασίας η πλήρης κατασκευή και εκτέλεση πραγματοποιείται με την εντολή: \begin{minted}{bash} sudo python3 source/build_network.py exercise/topology.json \end{minted} Η εκτέλεση αυτή μεταγλωττίζει πρώτα την τοπολογία, δημιουργεί το αρχείο \texttt{exercise/topology.generated.py} και στη συνέχεια εκτελεί \textbf{το ίδιο ακριβώς παραγόμενο αρχείο}. Μετά την κατασκευή και παραμετροποίηση του δικτύου ανοίγει το Mininet CLI, από το οποίο εκτελούνται τα πειράματα. Κατά την ανάπτυξη είναι επίσης δυνατό να παραχθεί μόνο το ενδιάμεσο Python πρόγραμμα, χωρίς να δημιουργηθεί κανένα network namespace ή άλλη κατάσταση στο σύστημα. Για παράδειγμα: \begin{minted}{bash} python3 source/build_network.py exercise/topology.json --emit [Optional file name] \end{minted} Η μορφή αυτή δεν απαιτεί δικαιώματα root και είναι χρήσιμη για την επιθεώρηση του αποτελέσματος της μεταγλώττισης ή για τον εντοπισμό σφαλμάτων πριν από την πραγματική εκτέλεση. Το \texttt{--emit} μπορεί επιπλέον να δεχθεί συγκεκριμένο path για το παραγόμενο αρχείο. Πριν από την εκτέλεση μπορεί επίσης να πραγματοποιηθεί έλεγχος του περιβάλλοντος με: \begin{minted}{bash} python3 source/build_network.py --env-check \end{minted} Ο έλεγχος επιβεβαιώνει την παρουσία του Mininet, του Open vSwitch και των εργαλείων Linux που απαιτούνται από τον builder και τα πειράματα, όπως τα \texttt{ip}, \texttt{tc}, \texttt{sysctl}, \texttt{dnsmasq}, \texttt{dhclient}, \texttt{tcpdump} και \texttt{ping}. Ο ίδιος έλεγχος πραγματοποιείται αυτόματα πριν από την πραγματική εκτέλεση μιας παραγόμενης τοπολογίας. \subsubsection{Διαχωρισμός περιγραφής τοπολογίας και runtime κατάστασης} Βασική σχεδιαστική επιλογή είναι ο \textbf{διαχωρισμός της δηλωμένης τοπολογίας από την κατάσταση που δημιουργείται κατά την εκτέλεσή της}. Το αρχείο JSON περιγράφει την επιθυμητή διαμόρφωση και τις πηγές από τις οποίες θα προκύψει η παραμετροποίηση, χωρίς να επιχειρεί να αποθηκεύσει την παροδική κατάσταση ενός εκτελούμενου δικτύου. Για παράδειγμα, η δήλωση: \begin{minted}{json} "net0": { "addressing": "dhcp" } \end{minted} δεν καθορίζει ποια διεύθυνση IP θα έχει τελικά ο host. Δηλώνει ότι η διεύθυνση πρέπει να αποκτηθεί δυναμικά από μία υπηρεσία DHCP κατά την εκτέλεση της τοπολογίας. Αντίστοιχα, ένας στατικός σύνδεσμος στο JSON οδηγεί στη δημιουργία πραγματικών virtual Ethernet interfaces, χωρίς τα τελικά ονόματα αυτών των interfaces να χρειάζεται να εμφανίζονται στην αρχική περιγραφή. Η ίδια διάκριση ισχύει για τις DHCP leases, τον ARP neighbor table, τους μετρητές πακέτων και τα αρχεία \texttt{pcap}, τα οποία αποτελούν \emph{runtime state} και δεν ανήκουν στη δηλωτική γλώσσα. Για τον ίδιο λόγο ο builder δεν εκκινεί αυτόματα το \texttt{dhclient} στους hosts που έχουν δηλωθεί ως DHCP clients, καθώς η απόκτηση της διεύθυνσης αποτελεί μέρος της πειραματικής διαδικασίας της εργασίας. Η αρχή αυτή αποτυπώνεται συνοπτικά ως: \begin{verbatim} Declarative topology Runtime state static address -------> configured IP address static gateway -------> routing-table entry DHCP addressing -------> dynamically acquired lease link declaration -------> veth / Mininet interfaces service declaration -------> running process ARP entries packet captures counters \end{verbatim} \subsubsection{Compiler-like αρχιτεκτονική} Η εσωτερική αρχιτεκτονική του builder σχεδιάστηκε με λογική παρόμοια με αυτή ενός \textbf{μεταγλωττιστή}. Αντί η εφαρμογή να διαβάζει ένα JSON και να καλεί άμεσα συναρτήσεις του Mininet, η περιγραφή περνά από διαδοχικά στάδια, καθένα από τα οποία έχει σαφώς περιορισμένη ευθύνη. Η συνολική ροή είναι: \begin{verbatim} topology.json ↓ [load] ↓ raw JSON dictionary ↓ [parse] ↓ typed Topology model ↓ [validate] ↓ validated Topology ↓ [plan] ↓ ExecutionPlan ↓ [render] ↓ topology.generated.py ↓ [execute] ↓ Mininet CLI ↓ [cleanup] \end{verbatim} Ο διαχωρισμός αυτός επιτρέπει σε κάθε στάδιο να εξετάζεται ανεξάρτητα και μεταφέρει σταδιακά την περιγραφή από μία υψηλού επιπέδου δήλωση πρόθεσης σε μία πλήρως συγκεκριμένη ακολουθία ενεργειών Mininet και Linux. Παράλληλα, κάθε κατηγορία σφάλματος ανήκει στο στάδιο που διαθέτει την απαραίτητη πληροφορία για να την εντοπίσει. \paragraph{Φόρτωση -- \texttt{topology\_loader.py}.} Το πρώτο στάδιο αφορά αποκλειστικά την πρόσβαση στο αρχείο και την ανάλυση της σύνταξης JSON. Η δημόσια συνάρτηση \texttt{load\_topology()} διαβάζει το αρχείο και επιστρέφει ένα \texttt{Dict[str, Any]}, χωρίς να γνωρίζει οτιδήποτε για τη σημασιολογία της DSL. \begin{verbatim} raw = load_topology("exercise/topology.json") JSON file | `--> Dict[str, Any] \end{verbatim} Σφάλματα όπως ανύπαρκτο αρχείο, μη έγκυρο JSON ή root αντικείμενο διαφορετικό από JSON object αναφέρονται ως \texttt{TopologyLoadError}. Στο σημείο αυτό δεν εξετάζεται ακόμη αν ένα \texttt{type} είναι έγκυρο ή αν ένας σύνδεσμος αναφέρεται σε υπαρκτό κόμβο. \paragraph{Parsing -- \texttt{topology\_parser.py}.} Το δεύτερο στάδιο μετατρέπει την ακατέργαστη δομή JSON στο \textbf{τυποποιημένο σημασιολογικό μοντέλο} της DSL. Η δημόσια συνάρτηση \texttt{parse\_topology()} κατασκευάζει αντικείμενα όπως \texttt{Topology}, \texttt{Node}, \texttt{Interface}, \texttt{Link} και \texttt{Service}, χρησιμοποιώντας \texttt{Enum} για τα κλειστά σύνολα τιμών. Για παράδειγμα, ένα τμήμα JSON όπως: \begin{minted}{json} { "node": "s1", "interface": "auto" } \end{minted} δεν παραμένει ένα γενικό dictionary, αλλά μετατρέπεται εννοιολογικά σε: \begin{minted}{python} LinkEndpoint( node="s1", interface=LinkInterfaceSelector.AUTO ) \end{minted} Το στάδιο αυτό εφαρμόζει επίσης την \emph{αυστηρή γραμματική} της γλώσσας. Άγνωστα πεδία ή μη υποστηριζόμενες τιμές προκαλούν \texttt{TopologyParseError}, αντί να αγνοούνται σιωπηρά. \paragraph{Validation -- \texttt{topology\_validator.py}.} Μετά το parsing η δομή είναι γραμματικά έγκυρη, αυτό όμως δεν συνεπάγεται ότι περιγράφει και συνεπές δίκτυο. Η δημόσια συνάρτηση \texttt{validate()} πραγματοποιεί τους ελέγχους που απαιτούν γνώση περισσότερων από ενός αντικειμένων της τοπολογίας. Για παράδειγμα, το ακόλουθο JSON μπορεί να αναλυθεί συντακτικά, αλλά δεν περιγράφει έγκυρη στατική διεπαφή: \begin{minted}{json} "net0": { "addressing": "static" } \end{minted} Το validation θα απορρίψει τη συγκεκριμένη περιγραφή επειδή απουσιάζει η στατική διεύθυνση. Αντίστοιχα ελέγχονται αναφορές σε ανύπαρκτους κόμβους, επαναχρησιμοποίηση interfaces, διευθύνσεις και gateways, διαθεσιμότητα ports για \texttt{auto}, καθώς και η συνέπεια των ρυθμίσεων της υπηρεσίας DHCP. Σε αντίθεση με ένα απλό fail-fast μοντέλο, ο validator συλλέγει τα προβλήματα σε αντικείμενα \texttt{ValidationIssue} και τα επιστρέφει συγκεντρωτικά μέσω ενός \texttt{TopologyValidationError}. Με αυτόν τον τρόπο ο χρήστης μπορεί να διορθώσει περισσότερα από ένα προβλήματα σε έναν κύκλο εκτέλεσης. \paragraph{Planning -- \texttt{topology\_plan.py}.} Το planning είναι το σημείο στο οποίο η έγκυρη πλέον περιγραφή μετατρέπεται σε μία \textbf{πλήρως επιλυμένη ενδιάμεση αναπαράσταση}. Η δημόσια συνάρτηση \texttt{plan()} παράγει ένα \texttt{ExecutionPlan}, στο οποίο δεν παραμένουν αφηρημένοι selectors όπως \texttt{auto} ή άλλες αποφάσεις που πρέπει να ληφθούν από τον backend. Για παράδειγμα, έστω ένας switch(node) με δύο ρητά δηλωμένες λογικές διεπαφές: \begin{minted}{json} { "name": "s1", "type": "switch", "interfaces": { "client": {}, "uplink": {} } } \end{minted} και δύο σύνδεσμοι, από τους οποίους ο πρώτος χρησιμοποιεί \texttt{auto}, ενώ ο δεύτερος ζητά ρητά τη διεπαφή \texttt{uplink}: \begin{minted}{json} { "endpoints": [ {"node": "h1", "interface": "net0"}, {"node": "s1", "interface": "auto"} ] }, { "endpoints": [ {"node": "r0", "interface": "lan"}, {"node": "s1", "interface": "uplink"} ] } \end{minted} Πριν από την επίλυση των \texttt{auto}, ο planner εντοπίζει όλες τις ρητές αναφορές σε interfaces και δεσμεύει τη \texttt{uplink}. Το διαθέσιμο σύνολο διεπαφών του \texttt{s1} για αυτόματη επιλογή περιέχει επομένως μόνο τη \texttt{client}. \begin{minted}{python} reserved["s1"] = {"uplink"} free_interfaces["s1"] = ["client"] \end{minted} Κατά το planning, το \texttt{auto} του πρώτου συνδέσμου επιλύεται συνεπώς στη λογική διεπαφή \texttt{client}. Στο συγκεκριμένο παράδειγμα οι λογικές διεπαφές αντιστοιχίζονται στη συνέχεια και στα συγκεκριμένα ονόματα διεπαφών που θα χρησιμοποιήσει το Mininet: \begin{verbatim} h1:net0 -> h1-eth0 s1:client -> s1-eth0 r0:lan -> r0-eth0 s1:uplink -> s1-eth1 \end{verbatim} Με αυτόν τον τρόπο μία προηγούμενη αυτόματη επιλογή δεν μπορεί να καταλάβει interface που έχει ζητηθεί ρητά από μεταγενέστερο link. Το \texttt{auto} λειτουργεί επομένως ως \emph{επιλογέας διαθέσιμης λογικής διεπαφής} και όχι ως όνομα διεπαφής. Η συμπεριφορά είναι διαφορετική όταν το πεδίο \texttt{interfaces} έχει παραλειφθεί πλήρως από έναν κόμβο. Σε αυτή την περίπτωση ο planner δημιουργεί συνθετικά λογικά ονόματα, όπως \texttt{auto0} και \texttt{auto1}, τα οποία αντιστοιχίζονται στη συνέχεια σε φυσικά ονόματα όπως \texttt{s1-eth0} και \texttt{s1-eth1}. Στο ίδιο στάδιο αποφασίζονται και backend-specific λεπτομέρειες που δεν πρέπει να εμφανίζονται στη DSL. Έτσι, η σημασιολογία ενός απλού Layer-2 switch μετατρέπεται από τον planner στην επιλογή \texttt{switch\_fail\_mode = "standalone"} για το Open vSwitch. Ένα απλοποιημένο τμήμα του \texttt{ExecutionPlan} για το προηγούμενο παράδειγμα μπορεί επομένως να θεωρηθεί ότι έχει τη μορφή: \begin{minted}{python} PlannedLinkEndpoint( node="s1", logical_interface="client", interface_name="s1-eth0" ) PlannedLinkEndpoint( node="s1", logical_interface="uplink", interface_name="s1-eth1" ) PlannedNode( name="s1", type=NodeType.SWITCH, switch_fail_mode="standalone" ) \end{minted} Ο planner δεν δημιουργεί interfaces και δεν τα εισάγει στο Mininet. Η ευθύνη του τελειώνει όταν όλες οι αποφάσεις που απαιτούνται για την εκτέλεση έχουν αποτυπωθεί στο \texttt{ExecutionPlan}. \paragraph{Rendering -- \texttt{topology\_renderer.py}.} Το renderer δέχεται το πλήρως επιλυμένο \texttt{ExecutionPlan} και το μετατρέπει σε ένα ολοκληρωμένο Python πρόγραμμα μέσω της δημόσιας συνάρτησης \texttt{render\_python()}. Σε αυτό το στάδιο \textbf{δεν πραγματοποιείται νέα σημασιολογική απόφαση}: ο renderer αποτυπώνει σε κώδικα τις επιλογές που έχουν ήδη γίνει από τον planner. Για το προηγούμενο παράδειγμα μπορούν να παραχθούν εντολές της μορφής: \begin{minted}{python} nodes['h1'] = net.addHost('h1', ip=None) nodes['r0'] = net.addHost('r0', ip=None) nodes['s1'] = net.addSwitch('s1', failMode='standalone') net.addLink( nodes['h1'], nodes['s1'], intfName1='h1-eth0', intfName2='s1-eth0', ) net.addLink( nodes['r0'], nodes['s1'], intfName1='r0-eth0', intfName2='s1-eth1', ) \end{minted} Παρατηρείται ότι στο παραγόμενο πρόγραμμα δεν υπάρχει πλέον ο selector \texttt{auto}. Η επιλογή \texttt{s1:client} έχει ήδη πραγματοποιηθεί από τον planner και ο renderer γνωρίζει μόνο το πλήρως επιλυμένο ζεύγος \texttt{s1:client} και \texttt{s1-eth0}. Η χρήση του \texttt{ip=None} εμποδίζει το Mininet να εκχωρήσει τις δικές του προεπιλεγμένες διευθύνσεις στους hosts, ώστε η διευθυνσιοδότηση να παραμένει αποκλειστικά υπό τον έλεγχο της DSL. Ανάλογα με το σχέδιο, ο renderer παράγει επίσης εντολές για IP addresses, routes, sysctls, \texttt{TCLink} και εκκίνηση του \texttt{dnsmasq}. Το παραγόμενο πρόγραμμα περιλαμβάνει ακόμη το πλήρες lifecycle του δικτύου: \begin{minted}{python} net.build() net.start() # interface configuration # routes # sysctls # services CLI(net) # finally: # stop started services # net.stop() \end{minted} \paragraph{Το παραγόμενο Python ως ενδιάμεση ``assembly''.} Το αρχείο \texttt{topology.generated.py} έχει σκόπιμα κεντρικό ρόλο στην αρχιτεκτονική και δεν αποτελεί απλώς ένα προσωρινό implementation detail. Μπορεί να θεωρηθεί ως η \emph{``assembly'' της DSL}: είναι χαμηλότερου επιπέδου από το JSON, πλήρως συγκεκριμένο, άμεσα εκτελέσιμο και ταυτόχρονα αρκετά αναγνώσιμο ώστε να μπορεί να επιθεωρηθεί από τον χρήστη. Η αντιστοίχιση μπορεί να συνοψιστεί ως: \begin{verbatim} topology.json: declarative source Topology: typed semantic representation ExecutionPlan: resolved intermediate representation topology.generated.py: executable "assembly" Mininet / Linux: runtime \end{verbatim} Ο coordinator αποθηκεύει πάντοτε το παραγόμενο Python πριν από την εκτέλεση και στη συνέχεια εκτελεί ακριβώς αυτό το αρχείο. Δεν υπάρχει δεύτερος, ανεξάρτητος executor που να μεταφράζει απευθείας το \texttt{ExecutionPlan} σε Mininet operations, αποφεύγοντας έτσι τον κίνδυνο διαφορετικής συμπεριφοράς μεταξύ του inspectable artifact και του πραγματικού runtime. \paragraph{Εκτέλεση και συντονισμός -- \texttt{build\_network.py}.} Το \texttt{build\_network.py} συνθέτει τα προηγούμενα στάδια μέσω της συνάρτησης \texttt{compile\_topology()}: \begin{minted}{python} topology = parse_topology(load_topology(path)) validate(topology) execution_plan = plan(topology) source = render_python(execution_plan) \end{minted} Το παραγόμενο source γράφεται στο \texttt{topology.generated.py} και, στην κανονική λειτουργία, εκτελείται ως ξεχωριστό Python process με τα ίδια δικαιώματα με τον coordinator. Η πραγματική εκτέλεση απαιτεί root privileges, ενώ η φόρτωση, το parsing, το validation, το planning και το rendering μπορούν να πραγματοποιηθούν χωρίς αυτά. Το generated πρόγραμμα δημιουργεί τους κόμβους και τα links, εφαρμόζει τη δικτυακή παραμετροποίηση, εκκινεί τις προβλεπόμενες υπηρεσίες και παραδίδει τον έλεγχο στον χρήστη μέσω του Mininet CLI. Η έξοδος από το CLI οδηγεί σε δομημένο cleanup μέσω \texttt{finally}, όπου τερματίζονται οι service processes που ξεκίνησε το ίδιο το πρόγραμμα και στη συνέχεια καλείται το \texttt{net.stop()}. \subsubsection{Έλεγχος των επιμέρους σταδίων} Η ανεξαρτησία των σταδίων αξιοποιείται και κατά την ανάπτυξη και τον εντοπισμό σφαλμάτων. Κάθε βασικό module του pipeline διαθέτει ένα μικρό \textbf{self-test του δημόσιου interface του}, το οποίο μπορεί να εκτελεστεί χωρίς να δημιουργηθεί πραγματικό Mininet δίκτυο. Για παράδειγμα: \begin{minted}{bash} python3 source/topology_loader.py python3 source/topology_parser.py python3 source/topology_validator.py python3 source/topology_plan.py python3 source/topology_renderer.py \end{minted} Μία επιτυχής εκτέλεση καταλήγει σε μήνυμα της μορφής: \begin{verbatim} topology_parser: self-test passed \end{verbatim} Τα tests δεν περιορίζονται στην απλή εισαγωγή των modules, αλλά ελέγχουν την κύρια συμπεριφορά του αντίστοιχου δημόσιου API. Ο parser, για παράδειγμα, ελέγχει τόσο σωστή μετατροπή σε typed objects όσο και απόρριψη άγνωστων πεδίων, ενώ ο validator εξετάζει τόσο έγκυρες όσο και πολλαπλά λανθασμένες τοπολογίες. Αντίστοιχα, ο planner ελέγχει την επίλυση του \texttt{auto}, την παραγωγή των physical interface names, την επιλογή \texttt{standalone} για τους switches και την παραγωγή των απαιτούμενων sysctls. Ο renderer ελέγχει ότι το παραγόμενο source είναι συντακτικά έγκυρο Python και ότι περιλαμβάνει τις αναμενόμενες κλήσεις Mininet, τις υπηρεσίες και το cleanup. Ο διαχωρισμός αυτός αποδείχθηκε ιδιαίτερα χρήσιμος κατά την ανάπτυξη, καθώς ένα σφάλμα μπορεί να απομονωθεί στο στάδιο στο οποίο εμφανίζεται, χωρίς να απαιτείται κάθε φορά εκκίνηση του Mininet με δικαιώματα root. Το \texttt{--emit} συμπληρώνει αυτή τη διαδικασία, επιτρέποντας την επιθεώρηση της τελικής \emph{``assembly''} πριν από οποιαδήποτε μεταβολή της πραγματικής δικτυακής κατάστασης του συστήματος. % ========================= Πείραμα 1 ========================= \section{Πείραμα 1 -- DHCP και διαδικασία D.O.R.A.} \subsection{Σκοπός και πειραματική διαδικασία} Σκοπός του πρώτου πειράματος είναι η παρατήρηση της διαδικασίας μέσω της οποίας ένας host χωρίς στατική διευθυνσιοδότηση αποκτά τις απαραίτητες ρυθμίσεις δικτύου από έναν DHCP server. Ειδικότερα, εξετάζεται η ακολουθία \textbf{Discover--Offer--Request--ACK (D.O.R.A.)} και τα αντίστοιχα πεδία των Ethernet, IP και UDP headers. Η τοπολογία εκκινήθηκε από τον κατάλογο \texttt{exercise/} με την εντολή: \begin{minted}{bash} sudo python3 ../source/build_network.py topology.json \end{minted} Πριν από την καταγραφή αφαιρέθηκε το αποθηκευμένο lease του \texttt{dhclient}, ώστε ο \texttt{h1} να ξεκινήσει τη διαδικασία χωρίς να επιχειρήσει να επαναχρησιμοποιήσει διεύθυνση από προηγούμενη εκτέλεση. Αφαιρέθηκε επίσης τυχόν προηγούμενο αρχείο καταγραφής και στη συνέχεια ξεκίνησε το \texttt{tcpdump} στη διεπαφή \texttt{h1-eth0}. Οι εντολές που εκτελέστηκαν στο Mininet CLI ήταν: \begin{minted}{bash} minted> h1 rm -f /var/lib/dhcp/dhclient.leases minted> h1 rm -f /tmp/dhcp.pcap minted> h1 tcpdump -i h1-eth0 -n -w /tmp/dhcp.pcap & minted> h1 ps aux | grep tcpdump minted> h1 dhclient h1-eth0 minted> h1 pkill -INT tcpdump minted> h1 tcpdump -n -e -vv -r /tmp/dhcp.pcap \end{minted} Η επιλογή \texttt{-e} κατά την ανάγνωση της καταγραφής επιτρέπει την εμφάνιση των Ethernet headers και επομένως των MAC διευθύνσεων που απαιτούνται για την ανάλυση. Η καταγραφή ολοκληρώθηκε χωρίς απώλειες από το \texttt{tcpdump}, με 12 πακέτα να έχουν καταγραφεί συνολικά. Η πλήρης συνεδρία της εκτέλεσης βρίσκεται στο \href{\dhcpExecutionUrl}{\texttt{execution.txt}}. Το αρχικό αρχείο καταγραφής διατίθεται στο \href{\dhcpPcapUrl}{\texttt{dhcp.pcap}}, ενώ η αναλυτικά αποκωδικοποιημένη μορφή του βρίσκεται στο \href{\dhcpDecodedUrl}{\texttt{dhcp-decoded.txt}}. \subsection{Αποτελέσματα καταγραφής -- Ζητούμενο 1.1} Η καταγραφή περιλαμβάνει την αναμενόμενη ακολουθία \textbf{Discover $\rightarrow$ Offer $\rightarrow$ Request $\rightarrow$ ACK}, η οποία ολοκληρώθηκε επιτυχώς. Στην πραγματική εκτέλεση καταγράφηκαν δύο DHCP Discover με το ίδιο transaction ID πριν από το πρώτο Offer. Η χρονική ακολουθία των σχετικών DHCP μηνυμάτων ήταν: \begin{verbatim} 10:58:29.655251 DHCP Discover 10:58:32.214530 DHCP Discover 10:58:32.670897 DHCP Offer 10:58:32.671193 DHCP Request 10:58:32.673025 DHCP ACK 10:58:32.678132 DHCP Offer \end{verbatim} Μεταξύ του πρώτου Discover και του πρώτου Offer παρατηρήθηκαν τρία ARP probes από τον DHCP server για τη διεύθυνση \texttt{192.168.1.131} και στη συνέχεια ένα ICMP Echo Request προς την ίδια διεύθυνση. Ο έλεγχος αυτός εισήγαγε καθυστέρηση στην πρώτη απάντηση του server, με αποτέλεσμα ο \texttt{dhclient} να επαναμεταδώσει το Discover περίπου τρία δευτερόλεπτα μετά το πρώτο. Και τα δύο Discover χρησιμοποιούν το ίδιο transaction ID, \texttt{0x0ecb5a2e}, επομένως αποτελούν μέρος της ίδιας προσπάθειας απόκτησης διεύθυνσης και όχι δύο ανεξάρτητες διαδικασίες DHCP. Παρά την επαναμετάδοση, η διαδικασία ολοκληρώθηκε κανονικά με Offer, Request και ACK και ο \texttt{h1} έλαβε τη διεύθυνση \texttt{192.168.1.131}. Μετά το ACK καταγράφηκε ακόμη ένα Offer, χωρίς αυτό να επηρεάζει την ήδη ολοκληρωμένη παραχώρηση της διεύθυνσης. Η βασική τετράδα D.O.R.A. δίνει τα ακόλουθα στοιχεία: \begin{table}[H] \centering \small \begin{tabularx}{\textwidth}{ >{\raggedright\arraybackslash}p{1.3cm} >{\raggedright\arraybackslash}p{5.2cm} >{\raggedright\arraybackslash}p{2.0cm} >{\raggedright\arraybackslash}X } \textbf{Μήνυμα} & \textbf{IP} & \textbf{UDP port} & \textbf{MAC} \\ \hline % \textbf{Μήνυμα} & % \textbf{από $\rightarrow$ προς} & % \textbf{UDP port από $\rightarrow$ προς} & % \textbf{MAC από $\rightarrow$ προς} \\ \hline Discover & \texttt{0.0.0.0 $\rightarrow$ 255.255.255.255} & \texttt{68 $\rightarrow$ 67} & \texttt{12:07:f8:bf:6e:ff $\rightarrow$ ff:ff:ff:ff:ff:ff} \\ Offer & \texttt{192.168.1.1 $\rightarrow$ 192.168.1.131} & \texttt{67 $\rightarrow$ 68} & \texttt{82:3b:16:e9:bb:17 $\rightarrow$ 12:07:f8:bf:6e:ff} \\ Request & \texttt{0.0.0.0 $\rightarrow$ 255.255.255.255} & \texttt{68 $\rightarrow$ 67} & \texttt{12:07:f8:bf:6e:ff $\rightarrow$ ff:ff:ff:ff:ff:ff} \\ ACK & \texttt{192.168.1.1 $\rightarrow$ 192.168.1.131} & \texttt{67 $\rightarrow$ 68} & \texttt{82:3b:16:e9:bb:17 $\rightarrow$ 12:07:f8:bf:6e:ff} \\ \end{tabularx} \caption{Διευθύνσεις και UDP θύρες των μηνυμάτων της διαδικασίας D.O.R.A.} \end{table} \subsection{Ανάλυση της διαδικασίας D.O.R.A.} Στο \textbf{Discover} ο \texttt{h1} δεν διαθέτει ακόμη διεύθυνση IPv4 και αναζητά διαθέσιμο DHCP server στο τοπικό δίκτυο. Για τον λόγο αυτό χρησιμοποιεί ως source IP την \texttt{0.0.0.0} και μεταδίδει το μήνυμα προς την περιορισμένη broadcast διεύθυνση \texttt{255.255.255.255}, με Ethernet destination \texttt{ff:ff:ff:ff:ff:ff}. Στο \textbf{Offer} ο DHCP server του \texttt{r0}, με διεύθυνση \texttt{192.168.1.1}, προσφέρει στον client τη διεύθυνση \texttt{192.168.1.131}. Στο ίδιο μήνυμα περιλαμβάνονται επίσης η μάσκα \texttt{255.255.255.0}, η broadcast διεύθυνση \texttt{192.168.1.255} και η προεπιλεγμένη πύλη \texttt{192.168.1.1}. Ο \texttt{h1} απαντά με \textbf{Request}, στο οποίο δηλώνει τόσο τον server που επέλεξε όσο και τη διεύθυνση που ζητά να του εκχωρηθεί. Τα αντίστοιχα options που καταγράφηκαν είναι: \begin{minted}{text} Server-ID Option: 192.168.1.1 Requested-IP Option: 192.168.1.131 \end{minted} Τέλος, με το \textbf{ACK} ο server επιβεβαιώνει την παραχώρηση της \texttt{192.168.1.131} και αποστέλλει τις τελικές παραμέτρους του lease. Στην καταγραφή το lease time είναι \texttt{43200} δευτερόλεπτα και η προεπιλεγμένη πύλη που παρέχεται στον client είναι η \texttt{192.168.1.1}. \subsection{Broadcast μετάδοση του DHCP Request -- Ζητούμενο 1.2} Το DHCP Request της αρχικής διαδικασίας απόκτησης διεύθυνσης μεταδόθηκε ως \textbf{broadcast} τόσο στο επίπεδο Ethernet όσο και στο επίπεδο IP. Στην καταγραφή παρατηρούνται συγκεκριμένα: \begin{minted}{text} Ethernet destination: ff:ff:ff:ff:ff:ff IP destination: 255.255.255.255 UDP ports: 68 -> 67 \end{minted} Κατά τη στιγμή αποστολής του Request η παραχώρηση της διεύθυνσης δεν έχει ακόμη ολοκληρωθεί και ο client συνεχίζει να χρησιμοποιεί την \texttt{0.0.0.0} ως source IP. Η broadcast μετάδοση επιτρέπει επιπλέον σε όλους τους DHCP servers του τοπικού δικτύου να παρατηρήσουν ποια προσφορά επέλεξε ο client. Ο επιλεγμένος server αναγνωρίζεται από το \texttt{Server-ID} του Request, ενώ τυχόν άλλοι servers μπορούν να διαπιστώσουν ότι οι δικές τους προσφορές δεν επιλέχθηκαν. Το ACK του \texttt{192.168.1.1} ολοκληρώνει τελικά τη διαδικασία και επιβεβαιώνει ότι η \texttt{192.168.1.131} μπορεί πλέον να χρησιμοποιηθεί από τον \texttt{h1}. % ========================= Πείραμα 2 ========================= \section{Πείραμα 2 -- Πρωτόκολλο ARP} \subsection{Σκοπός και πειραματική διαδικασία} Σκοπός του δεύτερου πειράματος είναι η παρατήρηση της διαδικασίας αντιστοίχισης μιας γνωστής διεύθυνσης IPv4 στην αντίστοιχη διεύθυνση MAC μέσω του πρωτοκόλλου \textbf{ARP}. Ειδικότερα, εξετάζεται η αρχική επίλυση της διεύθυνσης του \texttt{h2} από τον \texttt{h1} και η διαφορετική μορφή μετάδοσης του ARP Request και του ARP Reply. Η τοπολογία εκκινήθηκε εκ νέου και οι δύο hosts του Subnet A απέκτησαν διευθύνσεις μέσω DHCP. Οι διευθύνσεις που εκχωρήθηκαν κατά τη συγκεκριμένη εκτέλεση ήταν: \begin{itemize} \item \texttt{\textbf{192.168.1.131/24}} για τον \texttt{\textbf{h1}} και \item \texttt{\textbf{192.168.1.164/24}} για τον \texttt{\textbf{h2}}. \end{itemize} Οι αρχικές εντολές της εκτέλεσης ήταν: \begin{minted}{bash} sudo python3 ../source/build_network.py topology.json minted> h1 ip -4 -br addr minted> h2 ip -4 -br addr minted> h1 dhclient h1-eth0 minted> h2 dhclient h2-eth0 minted> h1 ip -4 -br addr minted> h2 ip -4 -br addr \end{minted} Πριν από το ping διαγράφηκε ο neighbor table του \texttt{h1}, ώστε να μην υπάρχει ήδη γνωστή αντιστοίχιση μεταξύ της IP και της MAC διεύθυνσης του \texttt{h2}. Η κενή κατάσταση του πίνακα επιβεβαιώθηκε με την εντολή \texttt{ip neigh show}. \begin{minted}{bash} minted> h1 ip neigh flush all minted> h1 ip neigh show minted> h1 rm -f /tmp/arp.pcap minted> h1 tcpdump -i h1-eth0 -n arp -w /tmp/arp.pcap & minted> h1 ping -c 1 192.168.1.164 minted> h1 ip neigh show minted> h1 pkill -INT tcpdump minted> h1 tcpdump -n -e -vv -r /tmp/arp.pcap \end{minted} Το φίλτρο \texttt{arp} του \texttt{tcpdump} περιορίζει την καταγραφή στα ARP frames, ενώ η επιλογή \texttt{-e} κατά την ανάγνωση εμφανίζει τα Ethernet headers και επομένως τις MAC διευθύνσεις πηγής και προορισμού. Η καταγραφή ολοκληρώθηκε χωρίς απώλειες, με τέσσερα ARP frames να έχουν καταγραφεί συνολικά. Η πλήρης συνεδρία της εκτέλεσης βρίσκεται στο \href{\arpExecutionUrl}{\texttt{execution.txt}}. Το αρχικό αρχείο καταγραφής διατίθεται στο \href{\arpPcapUrl}{\texttt{arp.pcap}}, ενώ η αποκωδικοποιημένη μορφή του βρίσκεται στο \href{\arpDecodedUrl}{\texttt{arp-decoded.txt}}. \subsection{Αποτελέσματα καταγραφής} Μετά την εκκαθάριση του neighbor table, το πρώτο ping από τον \texttt{h1} προς τον \texttt{h2} απαίτησε την επίλυση της MAC διεύθυνσης που αντιστοιχεί στην \texttt{192.168.1.164}. Το πρώτο ζεύγος πακέτων της καταγραφής ήταν: \begin{minted}{text} 4a:6f:2a:18:f4:80 > ff:ff:ff:ff:ff:ff Request who-has 192.168.1.164 tell 192.168.1.131 82:c0:6d:ae:3f:56 > 4a:6f:2a:18:f4:80 Reply 192.168.1.164 is-at 82:c0:6d:ae:3f:56 \end{minted} Από την καταγραφή προκύπτει επομένως ότι στη συγκεκριμένη εκτέλεση οι δύο hosts είχαν τα ακόλουθα στοιχεία: \begin{table}[H] \centering \begin{tabular}{lll} \textbf{Host} & \textbf{IPv4} & \textbf{MAC} \\ \hline \texttt{h1} & \texttt{192.168.1.131} & \texttt{4a:6f:2a:18:f4:80} \\ \texttt{h2} & \texttt{192.168.1.164} & \texttt{82:c0:6d:ae:3f:56} \\ \end{tabular} \caption{Διευθύνσεις των hosts που συμμετέχουν στο πείραμα ARP.} \end{table} Το ping ολοκληρώθηκε επιτυχώς και, μετά την ανταλλαγή ARP, ο neighbor table του \texttt{h1} περιείχε (λογικά) την αντιστοίχιση: \begin{minted}{text} 192.168.1.164 dev h1-eth0 lladdr 82:c0:6d:ae:3f:56 REACHABLE \end{minted} Το αποτέλεσμα αυτό επιβεβαιώνει ότι ο \texttt{h1} έμαθε τη MAC διεύθυνση του \texttt{h2} μέσω της προηγούμενης ανταλλαγής ARP και μπορεί πλέον να δημιουργεί απευθείας Ethernet frames προς αυτόν. \subsection{Ανάλυση του ARP Request και Reply -- Ζητούμενο 2.1} Κατά την αποστολή του αρχικού ARP Request ο \texttt{h1} γνωρίζει τη διεύθυνση IP του προορισμού, αλλά \textbf{δεν γνωρίζει ακόμη τη MAC διεύθυνσή του}. Δεν μπορεί επομένως να δημιουργήσει ένα unicast Ethernet frame προς τον \texttt{h2}. Για τον λόγο αυτό το ARP Request μεταδίδεται προς την Ethernet broadcast διεύθυνση: \begin{minted}{text} Source MAC: 4a:6f:2a:18:f4:80 Destination MAC: ff:ff:ff:ff:ff:ff Who has 192.168.1.164? Tell 192.168.1.131 \end{minted} Όλοι οι κόμβοι του ίδιου Layer-2 broadcast domain μπορούν να λάβουν το Request, αλλά μόνο ο host στον οποίο ανήκει η \texttt{192.168.1.164} πρέπει να απαντήσει. Στην συγκεκριμένη περίπτωση ο host αυτός είναι ο \texttt{h2}. Το ARP Reply, αντίθετα, μεταδίδεται ως \textbf{unicast}: \begin{minted}{text} Source MAC: 82:c0:6d:ae:3f:56 Destination MAC: 4a:6f:2a:18:f4:80 192.168.1.164 is-at 82:c0:6d:ae:3f:56 \end{minted} Ο \texttt{h2} μπορεί να στείλει την απάντηση απευθείας στον \texttt{h1}, επειδή το ARP Request περιλαμβάνει τα στοιχεία του αποστολέα και επομένως παρέχει στον \texttt{h2} τη MAC διεύθυνση στην οποία πρέπει να απαντήσει. Δεν υπάρχει συνεπώς ανάγκη το Reply να μεταδοθεί σε όλους τους κόμβους του broadcast domain. \textbf{Η MAC προορισμού του αρχικού ARP Request είναι επομένως \texttt{ff:ff:ff:ff:ff:ff}, ενώ το ARP Reply επιστρέφει ως unicast στη MAC \texttt{4a:6f:2a:18:f4:80} του \texttt{h1}.} \subsection{Πρόσθετη παρατήρηση} Στην καταγραφή εμφανίστηκε περίπου πέντε δευτερόλεπτα αργότερα και ένα δεύτερο ζεύγος ARP Request/Reply προς την αντίθετη κατεύθυνση: \begin{minted}{text} 82:c0:6d:ae:3f:56 > 4a:6f:2a:18:f4:80 Request who-has 192.168.1.131 tell 192.168.1.164 4a:6f:2a:18:f4:80 > 82:c0:6d:ae:3f:56 Reply 192.168.1.131 is-at 4a:6f:2a:18:f4:80 \end{minted} Σε αντίθεση με το αρχικό Request, το δεύτερο Request έχει ήδη ως Ethernet destination τη MAC του \texttt{h1} και επομένως είναι unicast. Η ανταλλαγή αυτή σχετίζεται με τη διαχείριση και επιβεβαίωση της κατάστασης του neighbor cache από το Linux και δεν αποτελεί την αρχική επίλυση που προκαλεί το ping. Για το ζητούμενο του πειράματος εξετάζεται συνεπώς το \textbf{πρώτο ζεύγος Request/Reply}, στο οποίο φαίνεται καθαρά η μετάβαση από broadcast αναζήτηση σε unicast απάντηση. Παρόλα αυτά το γεγονός ότι υπήρχε δεύτερο ζεύγος μας προβλημάτισε ιδιαίτερα μέχρι να ανακαλύψουμε τον λόγο ύπαρξής του! \subsection{Συμπεράσματα} ... \section{Σύνοψη} Τέλος, ... \end{document}