Report: Added implementation, and experiments 1 and 2
This commit is contained in:
Binary file not shown.
+853
-2
@@ -1,4 +1,5 @@
|
||||
% !TEX TS-program = xelatex
|
||||
% !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
|
||||
%
|
||||
@@ -75,6 +76,44 @@
|
||||
\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}
|
||||
@@ -104,6 +143,16 @@
|
||||
|
||||
\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
|
||||
@@ -144,7 +193,10 @@ Language -- DSL}, και δημιουργεί δυναμικά τους αντί
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\section{Υλοποίηση του Builder}
|
||||
\section{Υλοποίηση}
|
||||
|
||||
|
||||
% ========================= DSL =========================
|
||||
|
||||
\subsection{Δηλωτική γλώσσα περιγραφής τοπολογίας}
|
||||
|
||||
@@ -312,6 +364,805 @@ Layer-3 διευθυνσιοδότηση και ενεργοποιημένη π
|
||||
ο σημασιολογικός έλεγχος πραγματοποιούνται σε \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{Συμπεράσματα}
|
||||
|
||||
Reference in New Issue
Block a user