https://github.com/arkregiel/raw-socket-network-sniffer
Python network sniffer using raw socket
https://github.com/arkregiel/raw-socket-network-sniffer
network-programming networking packet-sniffer python python3 sniffer socket-programming
Last synced: 20 days ago
JSON representation
Python network sniffer using raw socket
- Host: GitHub
- URL: https://github.com/arkregiel/raw-socket-network-sniffer
- Owner: arkregiel
- License: mit
- Created: 2022-03-26T22:29:56.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-07-02T17:40:36.000Z (almost 3 years ago)
- Last Synced: 2025-03-10T08:59:28.887Z (over 1 year ago)
- Topics: network-programming, networking, packet-sniffer, python, python3, sniffer, socket-programming
- Language: Python
- Homepage:
- Size: 52.7 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Sniffer sieciowy z użyciem surowych gniazd (Linux)
Implementacja sniffera sieciowego bazującego na surowych gniazdach, który przechwytuje ramki i przedstawia część informacji (np. źródłowy i docelowy adres MAC, źródłowy i docelowy adres IPv4, źródłowy i docelowy port) w postaci czytelnej dla człowieka. Tego typu oprogramowanie pozwala zaobserwować zastosowanie teoretycznego modelu TCP/IP w praktyce
Z uwagi na wykorzystanie surowego gniazda, program należy uruchamiać z opcją `sudo`
```
$ sudo python main.py
```
```
sposób użycia:
$ sudo python main.py -i [options]
opcje:
-h --help wyświetla tę pomoc
-i --interface= interfejs, z którym powiązać gniazdo
-v --verbose wyświetlanie danych na ekran
-o --outputfile= plik, do którego zapisać dane
-d --dump czy zrzucać surowe przechwycone dane do pliku
przykład:
$ sudo python main.py -i wlan0 --verbose -o captured.txt
```
Na chwilę obecną program obsługuje tylko protokoły:
- IPv4
- ARP
- ICMP
- UDP
- TCP
- DNS
- DHCP
## PacketSniffer
### Dissector.py
W tym pliku znajdują się następujące klasy, próbujące odwzorować strukturę nagłówka danego protokołu:
- `EthernetHeader`
- `IPHeader`
- `ARPHeader`
- `ICMPHeader`
- `TCPHeader`
- `UDPHeader`
- `DNSHeader`
- `DHCPHeader`
Jako parametr konstruktora każda z tych klas przyjmuje bufor rozpoczynający się nagłówkiem danego protokołu i tworzy jego strukturę, podobnie jak w języku C dzięki modułowi `ctypes`
```c
/* struktura naglowka ARP w C */
struct arpheader {
u_int16_t htype;
u_int16_t ptype;
u_char hlen;
u_char plen;
u_int16_t oper;
u_char sha[6];
u_char spa[4];
u_char tha[6];
u_char tpa[4];
};
```
```py
from ctypes import *
class ARPHeader(Structure):
_fields_ = [
('htype', c_uint16),
('ptype', c_uint16),
('hlen', c_ubyte),
('plen', c_ubyte),
('oper', c_uint16),
('sha', c_ubyte * 6),
('spa', c_ubyte * 4),
('tha', c_ubyte * 6),
('tpa', c_ubyte * 4)
]
```
Przykładowo
```python
ip_header = Dissector.IPHeader(buf)
```
Struktura `ctypes` klasy `IPHeader` mapuje pierwsze 20 bajtów otrzymanego bufora na _przyjazny_ nagłówek IP (w pozostałych klasach jest analogicznie dla innych protokołów)
W tym samym pliku jest również funkcja `service_lookup`, która na podstawie podanych portów zgaduje, jaka usługa jest uruchomiona
```python
def service_lookup(src_port, dst_port=-1):
"""Zgaduje usługę za pomocą używanych numerów portów"""
port_to_service_map = {
20: 'FTP (data transfer)',
21: 'FTP (command)',
22: 'SSH',
23: 'Telnet',
25: 'SMTP',
43: 'WHOIS',
49: 'TACACS',
53: 'DNS',
80: 'HTTP',
88: 'Kerberos',
110: 'POP3',
143: 'IMAP',
161: 'SNMP',
162: 'SNMP (trap)',
443: 'HTTPS',
}
if src_port in port_to_service_map.keys():
return port_to_service_map[src_port]
elif dst_port in port_to_service_map.keys():
return port_to_service_map[dst_port]
else:
return 'Unknown'
```
Z tej funkcji korzystają klasy `TCPHeader` oraz `UDPHeader`
### Sniffer.py
W tym pliku znajduje się klasa `Sniffer` odpowiedzialna za funkcjonalność narzędzia. Wykorzystuje klasy z modułu `Dissector.py` do przedstawiania przechwyconych danych w czytelnej dla człowieka formie
```python
sniffer = Sniffer("eth0", verbose=True, output_file='captured.txt', dump=False)
```
Konstruktor przujmuje argumenty:
- `interface` - NIC, z którego będą przechwytywane ramki (argument obowiązkowy)
- `verbose` - czy wypisywać wyniki na stdout (opcjonalne, domyślnie `True`)
- `output_file` - plik, do którego zapisać wyniki (opcjonalne, domyślnie `None`)
- `dump` - czy zrzucać surowe przechwycone dane (opcjonalne, domyślnie `True`)
W metodzie `__init__` jest tworzone _surowe gniazdo_, które następnie zostaje powiązane z podanym interfejsem
funkcja `socket` z modułu `socket` przyjmuje argumenty:
- rodzina `socket.AF_PACKET`
- typ `socket.SOCK_RAW`
- stała `ETH_P_ALL` (wszystkie protokoły)
Klasa `Sniffer` zawiera metody:
- `hexdump(self, buffer)`
- Tworzy zrzut szesnastkowy z otrzymanej ramki
- `start_sniffing(self)`
- rozpoczyna przechwytywanie pakietów
- przełącza kartę sieciową w tryb mieszany (_promiscuous_)
- przechwytuje ramki i przekazuje je do dalszej analizy
- aby zatrzymać przechwytywanie należy nacisnąć _**Ctrl + C**_
- `promisc_mode(self, enable=True)`
- jeśli parametr `enable` jest prawdą, przełącza kartę w tryb mieszany
- jeśli `False`, wyłącza tryb mieszany
- `stop_sniffing(self)`
- wyłącza tryb mieszany na interfejsie
- `dissect_eth(self, frame)`
- z otrzymanej ramki tworzy obiekt `Dissector.EthernetHeader` i określa protokół warstwy wyższej
- `dissect_ip(self, ip_header, packet)`
- z otrzymanego pakietu IP tworzy obiekt `Dissector.IPHeader` i określa protokół warstwy wyżej
- w przypadku warstwy transportowej (TCP, UDP) określa usługę
- `dissect_app_layer(self, service, segment)`
- na podstawie argumentu `service` określa protokół warstwy aplikacji i przetwarza jego dane