Appearance
Versuch IP, BASH, Python auf Layer 2
Ziel dieses Versuches ist selber Frames auf Layer 2 zu senden und zu empfangen. Dabei verwenden wir zum einen das Raspberry Pi unter der Verwendung von Ethernet und der Python socket
API, sowie Wireshark auf Hostseite um Frames empfangen und untersuchen zu können.
Lektüre
Fakultativ (zum Nachschlagen) finden Sie Informationen zum Thema Physical Layer im Buch auf dem Active Directory unter Physical Layer.pdf
.
- 2.2.2 Twisted-Pair Kabel
- 2.2.5 Glasfaserleiter
- 2.6.1 Aufbau des Telefonsystems
- 2.6.5 Vermittlung
- 2.8 Kabelfernsehen (2.8.4: optional)
BASH Scripts
Ein Vorteil von konsolenbasierten Programme gegenüber GUI ist deren Fähigkeit automatisiert aufgerufen zu werden. Unter Linux kommen BASH Scripts
zum Einsatz. Hier handelt es sich um Files, welche in Sequenz Unterprogramme aufrufen. Zum Beispiel zur konfiguration einer IP Adresse:
bash
#!/bin/bash
echo "Configuring interface eth0"
sudo ifconfig eth0 192.168.50.10 netmask 255.255.255.0
echo "current configuration:"
ifconfig eth0
Erstellen Sie dieses Script unter dem Namen config.sh
via Samba im Homeverzeichnis Ihres Targets. Rufen Sie das Script auf dem Target auf via:
bash
cd
bash ./config.sh
Putty stürzt ab
Wenn Sie die IP ändern und über Putty via SSH verbunden sind, dann wird die Session "gekappt" und Sie müssen sich neu verbinden (ggf. über die neue IP).
Files ausführbar machen
Idealerweise könnten wir config.sh
einfach so, ohne ein bash
im Vorfeld aufrufen. Hierzu muss allerdings config.sh
ausführbar gemacht werden.
bash
chmod a+x config.sh
ls -al config.sh
Im Terminal wird config.sh
nun grün angezeit, dies deutet darauf hin, dass das File ausführbar ist.
bash
./config.sh
bash config.sh
Lokaler Pfad als Prefix
Der Pfad: ./
Bezeichnet immer das lokale Directory.
Ethernet
Auf Layer 2 ist Ethernet neben WLAN heute weit verbreitet und hat speziell im LAN selten Konkurrenz. In diesem Versuch wird gezeigt wie ein Frame auf Layer 2 zusammengebaut und via Ethernet übertragen werden kann.
Setup
- Raspbery Pi via eth0
192.168.50.1/24
- Host System via eth0
192.168.50.2/24
- Direkte Verbindung via Host und Target mit Ethernetkabel
Setup für den Versuch
Ethernet Frames
Die Einheit über welche Ethernet Daten austauscht heisst ein "Frame". Ein Ethnernet II
Frame setzt sich folgendermassen zusammen.
Bezeichnung | Länge (Byte) | Default |
---|---|---|
Präambel | 7 | |
Start of Frame | 1 | |
Destination MAC | 6 | |
Source MAC | 6 | |
Ether Type | 2 | 0x0800 |
Payload | 46 - 1500 | |
CRC | 4 |
Während Ethernet als Träger für Protokolle wie ARP, ICMP, IPv4, IPv6 verwendet wird, könne auch "handgeschmiedete" Frames erstellt werden. Hierzu eignen sich vor allem Hardwarenahe APIs. Unter Linux findet man die socket
API, diese wird für den Zugriff aufs Netzwerk von Kernel und Userspace Applikationen verwendet.
Lektüre
Lesen Sie an dieser Stelle entweder mit man 2 socket
auf dem Target oder http://man7.org/linux/man-pages/man2/socket.2.html wie man socket
verwendet.
Lesen Sie auch man packet
oder http://man7.org/linux/man-pages/man7/packet.7.html.
Die häufigste Anwendung für Sockets sind die types SOCK_STREAM
und SOCK_DGRAM
welche TCP
und UDP
entsprechen. Während wir in späteren Übungen mit beiden Protokollen arbeiten werden, ist für diesen Versuch im Speziellen SOCK_RAW
interessant.
Aus dem MAN Eintrag von packet
entnehmen Sie folgendes:
Packets auf Devicelevel: SOCK_RAW
SOCK_RAW packets are passed to and from the device driver without any changes in the packet data. When receiving a packet, the address is still parsed and passed in a standard sockaddr_ll address structure. When transmitting a packet, the user-supplied buffer should contain the physical-layer header. That packet is then queued unmodified to the network driver of the interface defined by the destination address. Some device drivers always add other headers. SOCK_RAW is similar to but not compatible with the obsolete AF_INET/SOCK_PACKET of Linux 2.0.
Frage
Für welche Programmiersprache sind die MAN Einträge? Finden Sie ein Beispiel für Socket?
Packets oder Frames?
Zwar wird im MAN Eintrag von Packets geredet, in Tat und Wahrheit handelt es sich hier aber aus einer Perspektive des Netzwerks um Frames
Netzwerk für Host und Target
Wie im letzten mal beschrieben setzen wir auf der Hostmaschine die IP Adresse vom Ethernetinterface von Hand in den Windows Versuch: Tools .
Auf dem Target, welches über z.B. UART (alternativ SSH) angeschlossen ist, konfigurieren wir das Ethernetinterface eth0 via Commandline
bash
ifconfig eth0 192.168.50.1/24
Beide Maschinen sind somit im gleichen Netz (192.168.50.0) (natürlich ist eine physikalische Verbindung mit Ethernetkabel an dieser Stelle vorausgesetzt).
Verifizieren Sie, dass die Maschinen erreichbar sind, vom Target aus:
bash
ping 192.168.50.2
Ping antwortet nicht
Es ist gut möglich, dass das Hostsystem nicht auf den Ping antwortet. Das hat mit der Firewall von Windows zu tun. Stellen Sie in dem Fall sicher, dass Sie umgekehrt von Windows das Target anpingen können, dies sollte in jedem Fall funktionieren.
Code Editor
Im Versuch: Tools haben Sie bereits einen Texteditor und das Target via Netzlaufwerk eingebunden. Dies vereinfacht vorallem das bearbeiten von Text oder Sourcecode.
Erstellen Sie im Home Verzeichnis vom Target einen neuen Order link-layer
. Erstellen Sie ein file hello.py
und editieren Sie es anschliessen mit dem Texteditor.
Fügen Sie folgendes Pythonscript ein:
py
def main():
print("hello world!")
if __name__ == '__main__':
main()
Hello World auf dem Target
Auf dem Target wechseln sie in das soeben erstellte Directory.
cd ~/link-layer/
Jetzt führen Sie den Code aus
python hello.py
hello world!
Auf dem Target können Sie so selber Python Programme ausführen.
Python
Python ist eine sehr schlanke Programmiersprache und hat eine vielseitige Standardlibray. Gerade für Proof of Concept eignet sich die Umgebung ausgezeichnet. Während Python zwar bis zu einem gewissen Grad objektorientierte Programmierung unterstütz ist die Sprache nicht wirklich dafür geschaffen und hinkt bei komplexen Anforderungen Sprachen wie Java, Go oder C# / C++ etwas nach.
Gerade aber bei den native interfaces, den Schnittstellen zu Sprachen wie C/C++ mach Python niemand so schnell etwas vor. Im Gegensatz zu C vefügt die Sprache allerdings über eine flachere Lernkurve, da gerade Memorymanagement eine untergeordnete Rolle spielt.
Python ist eine Interpretersprache, während C Programme kompiliert und für die entsprechende Architektur übersetzt werden muss können Sie Pyhton ähnlich wie Java plattformunabhänging ausführen. D.h. gerade bei ARM erspart dies den Umweg über einen Crosscompiler um Code aus x86 in armv7 zu übersetzen.
Layer 2 Frames auf dem Target
Erstellen Sie eine neue Datei rawsocket.py
mit folgendem Inhalt.
py
#!/usr/bin/python3
from socket import socket, SOCK_RAW, AF_PACKET
sock = None
message = b"""
Dear Receiver of this message
I am happy to announce the successful departure
of a layer 2 frame.
While none of the required headers are set
and thus this packet may never pass either
a single- nor a multiport bridge, you on the other
hand will receive this message regardless of
convetions and contracts.
Thank you for the interest you are taking
in reading this string of information and
farewell.
Yours truly
Sender
"""
def main():
print("welcome to the second layer")
sock = socket(AF_PACKET, SOCK_RAW)
# ethernet interface hier waehlen
# entweder eth0 / eth1
sock.bind(("eth0", 0))
sock.send(message)
if __name__ == '__main__':
main()
Führen Sie das Programm auf dem Target aus.
sudo python rawsocket.py
Aufzeichnen der Frames
Auf Hostseite könne nun die Layer 2 Frames inspiziert werden. Dazu verwenden wir den bereits installierten Wireshark
.
Aufgaben
- Öffnen Sie
Wireshark
auf ihrem Hostsystem und höhren Sie das Ethernetinterface ab, während Sie das Skript Ausführen - Was können Sie aus dem Frame schliessen, wenn sie es mit anderen Frames in Wireshark vergleichen
- Erstellen Sie in Wireshark einen Filter für das von Ihnen gesendete RAW packet.
Blinky Ping
Ping ist ein Tool, welches auf Layer 3 ein ICMP
Packet sendet. Mit einer minimalen Python Applikation hören wir auf ICMP Requests und lassen ein LED kurz blinken, sobald ein solches Paket eintrifft.
Hardware Setup
Verwenden Sie die beim Raspi-Kit mitgegebne LED und schliessen Sie diese wiefolgt an:
PIN | LED Modul |
---|---|
4 (5V PWR) | VCC |
14 (GND) | GND |
12 (GPIO 18) | IN |
ACHTUNG Pins nicht verwechseln!
Bitte überprüfen Sie vor dem Anschliessen, ob die Pins richtig verbunden sind, da es sonst zu einem Kurzschluss kommen kann.
Erstellen Sie folgendes Python Script:
python
#!/usr/bin/python3
from gpiozero import LED
from time import sleep
import socket
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
sock.bind(("0.0.0.0", 0))
print("ping receiver")
led = LED(18)
while True:
(data, addr) = sock.recvfrom(1024)
print(f"data {data}")
print(f"from: {addr}")
led.on()
sleep(0.1)
led.off()
if __name__ == "__main__":
main()
Speichern Sie das Script im gleichen Verzeichnis wie vorhin unter dem namen ping.py
. Um das File ausführbar zu machen, navigieren Sie mit der BASH / Console ins entsprechende Verzeichnis und führen aus chmod a+x ping.py
.
Starten Sie das Script nun mit sudo ./ping.py
.
Testen
Von Ihrem Hostsystem pingen Sie nun das Target und beobachten ob die LED kurz aufblinkt.
ICMP
ICMP
steht für Internet Control Message Protocol und wird für das Austauschen von Information auf Layer 3 verwendet. Ein Feature von ICMP
ist der ECHO
request, welcher dazu dient ein eingehendes Echo Paket mit einem ausgehenden zu beantworten.
gpiozero
gpiozero
(https://gpiozero.readthedocs.io/en/stable/index.html) ist eine Python Library fürs Raspberry Pi, welche Zugriff auf die Peripherie vom Userspace her ermöglicht. Neben LED und Buttons, können so auch devices via I2C oder SPI verwendet werden.