10 - libpcap

LEZIONE 25
I router, come abbiamo visto, alla fine "sono dei computer".
Packet processing with libpcap/WinPcap
Fulvio Risso
http://fulvio.frisso.net
1
Libpcap/WinPcap
n
Libpcap is an open source C library that allows to
capture/send raw packets from a Network Interface Card
(NIC)
n
Libpcap gives you access to exactly the packets that are
being received/sent by your NIC
n
n
WinPcap is the Windows version
Be carefully that some packets may be filtered by your network
switch!
n
Main target are C programmers, but other languages (e.g.,
Java) may be supported through additional components
n
This presentation will focus on the capturing capabilities of
libpcap/WinPcap
Iniziamo da libpcap, librerie open source scritte in C che servono per
interagire direttamente con la NIC. Non è formalmente corretto, ma
possiamo immaginare che l'interazione del nostro programma con la
rete sia sostanzialmente diretta e non si passi dal SO. Dal punto di
vista funzionale noi possiamo generare e ricevere ESATTAMENTE
gli stessi pacchetti che verranno trasmessi sulla rete.
L'interfaccia nativa è appunto in C. Dopodichè esistono altre librerie
di adattamento (ad esempio per Java, Python e PHP). libpcap e
winpcap possono sia inviare che ricevere.
2
Libpcap/Wincap do and don’t
Does not
Does
n
Capture raw packets
n
Filter traffic
n
n
Parse packets
n
Capture a subset of traffic
n
Supports reading traffic from
physical interfaces and files
n
Saves (filtered) traffic on file
E.g., easy access to protocol
fields (e.g., ip.src)
n
Visualize packet content
n
Support for post-capture filters
n
Unless data is saved on a file,
which is then opened with a
filter
Cosa fanno?
- catturano pacchetti crudi
- filtrano il traffico ("cattura solo i pacchetti TCP")
- lettura di traffico sia da network interface che da un file
- salvare il traffico filtrato sul file
Cosa non fanno?
- parsificazione del pacchetto (viene restituita una stringa di caratteri,
winpcap non ha la più pallida idea del significato)
- non visualizza il contenuto del pacchetto (perchè comunque ci va
del parsing)
- se voglio specificare un filtro lo devo dire prima della cattura (non
posso cambiarlo se non fermando una cattura e farne partire un
altra. Quindi eventualmente catturate tutto su file e fare più filtri a
posteriori).
3
tcpdump/WinDump
n
Basic sniffer based on libpcap/WinDump
n
Command line interface
n
Often the only sniffer present when you install your Linux OS
C:\Users\Fulvio>windump -n -r sample.cap
reading from file sample.cap, link-type EN10MB (Ethernet)
13:55:56.141474 IP 130.192.3.76.138 > 130.192.3.255.138: UDP, length 201
13:55:56.141725 arp who-has 130.192.43.107 tell 130.192.4.34
13:55:56.239625 IP 130.192.25.132.138 > 130.192.25.255.138: UDP, length 232
13:55:56.338967 arp who-has 208.137.254.2 tell 130.192.3.24
13:55:56.439478 arp who-has 130.192.24.8 (ff:ff:ff:ff:ff:ff) tell 130.192.24.254
13:55:56.440093 arp who-has 130.192.24.16 (ff:ff:ff:ff:ff:ff) tell 130.192.24.254
13:55:56.440670 arp who-has 130.192.24.11 (ff:ff:ff:ff:ff:ff) tell 130.192.24.254
13:55:56.443275 router-hello l2rout vers 2 eco 0 ueco 0 src 60.29 blksize 1498 pri 64 hello 15
13:55:56.539253 IP 130.192.4.32.138 > 130.192.4.255.138: UDP, length 237
13:55:57.441384 IP 130.192.16.105.138 > 130.192.16.255.138: UDP, length 178
13:55:57.443861 IP 130.192.3.24.2301 > 255.255.255.255.2301: UDP, length 12
13:55:57.908574 IP 130.192.16.81.1210 > 130.192.3.21.53: 79+[|domain]
13:55:57.911728 IP 130.192.3.21.53 > 130.192.16.81.1210: 79*[|domain]
13:55:57.929764 IP 130.192.16.81 > 130.192.28.6: ICMP echo request, id 512, seq 432, length 40
13:55:57.931675 IP 130.192.28.6 > 130.192.16.81: ICMP echo reply, id 512, seq 432, length 40
4
tcpdump è un programmino che sfrutta libpcap per catturare il traffico. Aggiunge un minimo di parsing in cui ci fa vedere un timestamp
del pacchetto e aggiunge un sommario dello stesso.
In due parole è una versione scarnissima di Wireshark.
tcpdump/Windump basics
n
Some suggestions for the command line:
n
-D: prints the list of network interfaces available in the system
n
-i [interface]: captures from that network interface
n
-s [snaplen]: captures only the first [snaplen] bytes of each
packet
n
n
Often modern NICs implement TCP reassembly, returning to the
user very large packet (also 64KB)
n
-r [filename]: reads packets from [filename] instead of NIC
n
-w [filename]: saves the read packet to [filename]
n
n
Please set it to a large number to be sure that all the payload
gets captured
Qui ci sono alcune indicazioni:
-i [interface]: lancio da una specifica interfaccia (su Windows ho dei
nomi lunghissimi, si può usare il numero dell'interfaccia)
-D: numero e nome delle interfacce
-r [filename]: legge da file
-w [filename]: scrive su file
-s: per questioni di privacy/velocità tcpdump cattura solo i primi byte
del pacchetto (96 bytes o roba del genere), con -s [tot] posso specificare quanti byte leggo ("meglio" mettere un NUMERO INCREDIBILE
in modo da riuscire a prendere pacchetti messi su più parti di una
sessione TCP).
Can be used also to read from a first file, apply a filter, and save
the result on a second filter
Example
tcpdump –i eth0 –s 10000 – w sample.cap tcp port 80
5
Istruzioni per ottenere le librerie. Per sviluppare serve qualcosa in più.
Getting and installing the library
n
n
n
Linux/UNIX
n
Binaries (libpcap + tcpdump) usually included in your distribution
n
May require administrative privileges (e.g., sudo)
Windows
n
Need to download and install the binaries from
http://www.winpcap.org
n
Two separate downloads for the library binary (a couple of DLL
files) and tcpdump (a standalone executable)
For developers
n
Need to install the developer version, which includes headers
n
Linux: often called libpcap-dev
n
Windows: install the “Developer’s Pack”
6
6
CMake
n
Cross-platform generator for project files (e.g., makefiles,
Windows Studio projects, etc)
n
Not strictly needed, but definitely useful in order to write
cross-platform software
n
Download and install from:
n
Linux: use your package manager
n
Windows: http://www.cmake.org
CMake non è obbligatorio, ma siccome siamo in un mondo di N sistemi operativi posso fare dei file C portabili (se scritti bene). E' un tool
con un suo linguaggio: si scrive il Makefile con un certo linguaggio
semplice e crea il Makefile con il linguaggio opportuno.
7
Create your first libpcap program
n
Objective: open a capture file and print the hex dump of the
packets on screen
C:\Users\Fulvio\test-libpcap\debug>
1387179358:265840 (186)
00 0d 29 0b a4 3f 20 cf 30 14 c9 0d
00 ac 20 18 40 00 40 06 2e 00 82 c0
05 5d 00 16 c3 25 f2 8c 0b 21 f9 1a
00 50 ec c2 00 00 b2 76 79 0b 39 8f
d0 ae ec 6e b0 e7 a7 97 d1 66 da b5
e0 d0 d3 c6 37 e1 85 ea ca cf 2f da
25 1c 90 63 e4 68 cc ca d6 42 32 9b
59 41 55 74 e6 28 01 15 8d d8 c0 99
c3 ea c4 66 b6 b7 ed 79 2d a2 fc 7d
76 0f 37 50 93 fd 89 33 ba 31 39 2b
a1 d1 76 53 c5 a7 60 7f ca dd fd d5
9f 11 b7 b5 5e 15 11 12 df 3c
1387179358:267072
20 cf 30 14 c9 0d
00 28 7a f6 40 00
e1 46 c3 25 00 16
3f 79 c4 8c 00 00
8
(60)
00 0d
7e 06
f9 1a
00 00
29
95
05
b1
0b
b5
22
27
a4
82
f2
f5
readfile-ex sample.cap
08
e1
05
e8
b4
2d
df
58
20
f5
97
00
46
22
00
46
5e
e6
c2
0b
ba
fa
45
82
50
c2
ab
10
f1
95
a1
13
76
10
c0
18
c3
fd
7b
d6
45
72
35
4a
3f 08 00 45 00
c0 05 5d 82 c0
8c 0b a5 50 10
f1
Piccolo programma su libcap che legge un file e stampa il timestamp,
tra parentesi la lunghezza del pacchetto e l'esadecimale del pacchetto.
Sul sito c'è uno zip. Lo scomprimiamo.
Create your first libpcap program
n
Unpack the sample
n
Create the project files:
n
Compile the executable
n
C:\Users\Fulvio\test-libpcap> cmake .
n
Windows: open the Microsoft Studio Solution file (.sln) and
compile the solution
n
Linux:
fulvio@zerg:~/test-libpcap$ make
Launch the executable
n
Windows:
C:\Users\Fulvio\test-libpcap\debug> readfile-ex ..\sample.cap
n
Linux:
fulvio@zerg:~/test-libpcap$ ./readfile-ex sample.cap
9
Il sorgente è semplicissimo. Ci sono un paio di include, la seconda è
<pcap.h> ed è l'header di winpcap.
Prima funzione chiamata: apertura di una cattura offline. error buffer
viene riempito in caso di fallimento. La funzione ritorna un handler
a una struttura dati interna per lavorare successivamente su quella
cattura.
The source code (1)
// Standard C include file for I/O functions
#include <stdio.h>
// Include files for libpcap/WinPcap functions
#include <pcap.h>
#define LINE_LEN 16
int main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
struct pcap_pkthdr *header;
const u_char *pkt_data;
u_int i=0;
int res;
if (argc != 2)
{
printf("usage: %s filename\n\n", argv[0]);
return -1;
}
/* Open the capture file */
if ((fp = pcap_open_offline(argv[1],
// name of the device to open
errbuf
// error buffer
)) == NULL)
{
fprintf(stderr,"Unable to open the file %s.\n\n", argv[1]);
return -1;
}
10
The source code (2)
/* Retrieve the packets from the file */
while((res = pcap_next_ex(fp, &header, &pkt_data)) >= 0)
{
/* print pkt timestamp and pkt len */
printf("%ld:%ld (%d)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);
pcap_next_ex serve per leggere il prossimo pacchetto. Parametri:
puntatore, header passato per puntatore (quando la funzione ritorna
c'è l'header del pacchetto) e data passato per puntatore (idem come
sopra). L'header non è l'header del pacchetto, ma è un header con
alcune informazioni utili per analizzarlo (timestamp, lunghezza...)
Il for interno cicla sui bytes del pacchetto e stampa byte per byte.
/* Print the packet */
for (i=1; (i < header->caplen + 1 ) ; i++)
{
printf("%.2x ", pkt_data[i-1]);
if ( (i % LINE_LEN) == 0) printf("\n");
}
printf("\n\n");
}
if (res == -1)
{
printf("Error reading the packets: %s\n", pcap_geterr(fp));
}
pcap_close(fp);
return 0;
Devo essere "veloce abbastanza" a fare processing affinchè il buffer
circolare che sta sotto non finisca, saturato dai nuovi pacchetti in arrivo. La dimensione del buffer si può chiamare tramite opportune
chiamate che permettono di interagire col kernel.
Il traffico in uscita non ha padding, a differenza di quello in ingresso.
}
11
Qui c'è qualcosa al riguardo del file di configurazione per creare i
Makefile. Questa roba si può anche non toccare.
The project file
PROJECT(READFILE-SAMPLE)
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
# Set source files
SET(SOURCES
readfile_ex.c
)
# Default directories for include files
IF(WIN32)
INCLUDE_DIRECTORIES (
${READFILE-SAMPLE_SOURCE_DIR}
${READFILE-SAMPLE_SOURCE_DIR}/../WPdPack/Include
)
ELSE(WIN32)
INCLUDE_DIRECTORIES (
${READFILE-SAMPLE_SOURCE_DIR}
)
ENDIF(WIN32)
# Default directories for linking
#
(in Linux those are already in the system path)
IF(WIN32)
LINK_DIRECTORIES(${READFILE-SAMPLE_SOURCE_DIR}/../WPdPack/Lib)
ENDIF(WIN32)
Assume the “WPdPack” folder is at
the same level of our sample
12
# Platform-specific definitions
IF(WIN32)
ADD_DEFINITIONS(
-D_CRT_SECURE_NO_WARNINGS
-D_CRT_SECURE_NO_DEPRECATE
-DWIN32_LEAN_AND_MEAN
)
ENDIF(WIN32)
# Create executable
ADD_EXECUTABLE(
readfile-ex
${SOURCES}
)
# Link the executable to the
#
required libraries
IF(WIN32)
TARGET_LINK_LIBRARIES(
readfile-ex
wpcap
)
ELSE(WIN32)
TARGET_LINK_LIBRARIES(
readfile-ex
pcap
)
ENDIF(WIN32)
Libpcap programming basics: basic workflow
Start
Chosen
interface
Chosen
filter
Read available
adapters
pcap_findalldevs()
Open capture
interface
pcap_open()
pcap_open_live()
pcap_open_offline()
Compile packet
filter
pcap_compile()
Set packet filter
pcap_setfilter()
Vediamo alcune funzioni principali in modo da creare un programma
più elaborato:
- guardo quali sono le schede di rete (findalldevs)
- scelgo l'interfaccia da aprire (open apre file o adapter)
- compilare un filtro (passo una stringa a un minicompilatore)
- settare il filtro sull'interfaccia
- ricevere i pacchetti
pcap_next_ex()
Read packets
13
Relevant source code for the “callback” mode
/* Open the capture file */
if ((fp = pcap_open_offline(argv[1],
// name of the device
errbuf
// error buffer
)) == NULL)
{
fprintf(stderr,"Unable to open the file %s.\n\n", argv[1]);
return -1;
}
/* read and dispatch packets until EOF is reached */
pcap_loop(fp, 0, dispatcher_handler, NULL);
Vedi prima slide 16. Confrontando questo codice con quello visto in
precedenza, notiamo che non c'è un while ma una pcap_loop. Tra i
parametri c'è un dispatcher_handler, funzione che viene poi chiamata dal sistema operativo quando ho un pacchetto.
E' esattamente il codice che c'era in precedenza che una volta avevo
nella while.
Ho un parametro in più (temp1) per sapere da quale interfaccia è
stata chiamata la funzione se uso un solo dispatcher_handler.
pcap_close(fp);
return 0;
}
void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
u_int i=0;
/* print pkt timestamp and pkt len */
printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);
/* Print the packet */
for (i=1; (i < header->caplen + 1 ) ; i++)
{
printf("%.2x ", pkt_data[i-1]);
if ( (i % LINE_LEN) == 0) printf("\n");
}
printf("\n\n");
}
14
Libpcap programming basics: data structures
Most common function
for reading packets
(polling model)
pcap_next_ex(
Pcap handler
(identifies the source
currently in use)
fp,
Pcap
header
&header,
Raw packet dump
(may include
Ethernet padding)
&pkt_data
Le strutture principali le abbiamo già viste intuitivamente:
- fp: handler usato in tutte le funzioni per specificare dove devo operare
- header: composto da timestamp, lunghezza del pacchetto e lunghezza del pacchetto catturato. Il timestamp è a sua volta una
struct.
)
struct pcap_pkthdr {
struct timeval ts; // time stamp
bpf_u_int32 caplen; // captured packet length
bpf_u_int32 len;
// total packet length
}
struct timeval {
long
tv_sec;
long
tv_usec;
};
// seconds
// and microseconds
15
Polling vs. event-driven libpcap programming
Start
Start
Read available
adapters
Read available
adapters
Open capture
interface
Open capture
interface
Compile
packet filter
Compile
packet filter
Set packet
filter
Set packet
filter
Read packets
pcap_next_ex()
Polling
16
Stop in a
blocking call
Call from the
operating system
User-defined
callback function
Return to the
Operating system
pcap_loop()
Event-based
libpcap ha due modalità di lettura dei dati. Polling è il procedimento
che abbiamo visto prima.
La seconda modalità è event-driven: il programma si ferma su una
call di tipo bloccante. Il processamento dei pacchetti viene fatto con
un handler chiamato dal sistema operativo. Modalità originaria.
Polling è più facile da capire, il problema è che la read ogni tanto rimane "appesa" perchè non arriva niente (c'è un timeout, bisogna vedere per quale motivo lo raggiungo!)
Uno snapshot di codice "callback" è alla slide 14.
Parsing packets: protocols
struct ether_header {
u_int8_t ether_dhost[6];
u_int8_t ether_shost[6];
u_int16_t ether_type;
};
Define a structure that helps
parsing the Ethernet header; this
is possible only because the
Ethernet header has fixed length
/* 6 bytes destination address */
/* 6 bytes source address */
/* 2 bytes ethertype */
Cast the raw packet (starting at
offset zero) into an ether_header
structure
Una volta catturati i pacchetti bisogna parsificarli. Cerchiamo di migliorarlo un po': sarebbe bello interpretare i byte crudi come byte
Ethernet.
Definiamo dunque una struttura ether_header composta da tre campi (destination host, source host, ether type). Il fatto che uso uint è
buono se voglio fare roba cross-platform. Ho definito dunque una
struttura che "scimmiotta" quella dell'Ethernet.
int main(int argc, char **argv) { ... }
void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
/* Pointer to the ether_header structure */
struct ether_header *eptr;
/* Cast the raw packet to the ether_header structure, in order to facilitate the parsing */
eptr = (struct ether_header *) pkt_data;
/* Print on screen the MAC addresses of each packet */
printf("%02x:%02x:%02x:%02x:%02x:%02x --> %02x:%02x:%02x:%02x:%02x:%02x\n\n",
eptr->ether_shost[0], eptr->ether_shost[1], eptr->ether_shost[2],
eptr->ether_shost[3], eptr->ether_shost[4], eptr->ether_shost[5],
eptr->ether_dhost[0], eptr->ether_dhost[1], eptr->ether_dhost[2],
eptr->ether_dhost[3], eptr->ether_dhost[4], eptr->ether_dhost[5]);
Per usarla:
- alloco un puntatore a questa struttura
- casto pkt_data a quel puntatore
Tutto il parsing è delegato all'utente. Tra l'altro, tutto il parsing aiuta
nel caso in cui il protocollo ha dimensioni prefissate. Altrimenti si scava a manina.
}
Print the value in hex
using two digits and
prepend ‘0’ if needed
17
Parsing packets: accessing to protocol fields
#ifdef WIN32
#include <winsock2.h> /* Needed for ntohs() in Windows */
#endif
struct ether_header {
u_int8_t ether_dhost[6];
u_int8_t ether_shost[6];
u_int16_t ether_type;
};
/* 6 bytes destination address */
/* 6 bytes source address */
/* 2 bytes ethertype */
Warning!
In Windows, remember to add the
library “ws2_32” in CMakeLists.txt in
order to resolve the linking for function
ntohs()
Altro problema grosso sul parsing dei protocolli. Qui voglio stampare
il valore di ether_type. E' un casino. I 16 bit sulla rete sono in network byte order, Intel memorizza in senso opposto.
Vedi sotto.
int main(int argc, char **argv) { ... }
void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct ether_header *eptr; /* Pointer to the ether_header structure */
u_int16_t ethertype;
/* Variable that keeps the ethertype in host-based format */
/* Cast the raw packet to the ether_header structure, in order to facilitate the parsing */
eptr = (struct ether_header *) pkt_data;
/* Print on screen the MAC addresses of each packet */
printf("%02x:%02x:%02x:%02x:%02x:%02x --> %02x:%02x:%02x:%02x:%02x:%02x",
eptr->ether_shost[0], eptr->ether_shost[1], eptr->ether_shost[2],
eptr->ether_shost[3], eptr->ether_shost[4], eptr->ether_shost[5],
eptr->ether_dhost[0], eptr->ether_dhost[1], eptr->ether_dhost[2],
eptr->ether_dhost[3], eptr->ether_dhost[4], eptr->ether_dhost[5]);
ethertype= ntohs(eptr->ether_type); /* Converting ethertype from network to host byte order */
printf("(ethertype: 0x%04x)\n\n", ethertype);
Function that converts the
ethertype from network byte
order to host byte order
}
18
Endianess
Need to use ntohX() and
htonX() to convert data
Host-based order for Intel CPU
0x0D 0x0C 0x0B 0x0A
Offset 3
0x0D
Offset 2
0x0C
Offset 1
0x0B
Offset 0
0x0A
Little-endian
Tutte le volte che devo accedere a qualcosa che non è 8 bit ma 16
o 32 devo usare:
- ntoh: da network a host
- hton: da host a network (voglio scrivere dei dati all'interno del pck)
X = s (short), l (long)
Su Windows devo aggiungere una libreria per poter usare queste
due funzioni.
0x0A 0x0B 0x0C 0x0D
Big-endian
Network byte order (raw packet data)
19
Esempio un po' più complesso in cui ho due strutture dati. Occhio
al campo lenver: è 8 bit, ma ho comunque problemi di byte ordering.
Parsing packets: a more complex example (1)
#ifdef WIN32
#include <winsock2.h> /* Needed for ntohs() in Windows */
#endif
struct ether_header {
u_int8_t ether_dhost[6];
u_int8_t ether_shost[6];
u_int16_t ether_type;
};
struct ip_header {
u_int8_t
lenver;
u_int8_t
ip_tos;
u_int16_t ip_len;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t
ip_ttl;
u_int8_t
ip_p;
u_int16_t ip_sum;
u_int8_t
ip_src[4];
u_int8_t
ip_dst[4];
};
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/* 6 bytes destination address*/
/* 6 bytes source address */
/* 2 bytes ethertype */
Warning!
Byte ordering problems
are present here as well
header length + version*/
type of service */
total length */
identification */
fragment offset field */
time to live */
protocol */
checksum */
source and dest address */
source and dest address */
int main(int argc, char **argv) { ... }
This definition makes easy to get access to each
single digit, but is not very efficient when we need
to compare addresses; in that case, better to
transform the IP address in a u_int32_t
20
Parsing packets: a more complex example (2)
Abbastanza simile a prima. Se ethertype = 800 allora uso la struttura
ipptr.
void dispatcher_handler(u_char *temp1, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct ether_header *eptr;
u_int16_t ethertype;
eptr = (struct ether_header *) pkt_data;
ethertype= ntohs(eptr->ether_type);
if (ethertype == 0x800)
{
struct ip_header *ipptr;
Even trivial protocol parsing usually
requires several checks on the packets;
for instance, our code does not support
VLANs, does not check if the IP has
options, etc.
ipptr = (struct ip_header *) &pkt_data[14];
/* Print on screen the IP addresses of each packet */
printf("%d.%d.%d.%d --> %d.%d.%d.%d (length %d)\n\n",
ipptr->ip_src[0], ipptr->ip_src[1], ipptr->ip_src[2], ipptr->ip_src[3],
ipptr->ip_dst[0], ipptr->ip_dst[1], ipptr->ip_dst[2], ipptr->ip_dst[3],
ntohs(ipptr->ip_len));
}
else
printf("Not an IP packet (ethertype: 0x%04x)\n\n", ethertype);
}
Although it works (in this
case), better to avoid fixed
offsets in the code
21
Filtraggio di traffico. La sintassi di filtering è comune a tutti i tool che
si basano su libpcap e si trova sulla pagina indicata.
Filtering traffic
n
The setfilter() function allows to filter incoming traffic
n
The filtering syntax is common among all the libpcap-based
tools (e.g., tcpdump/WinDump)
n
Some sample filters
n
n
ip
n
host 1.2.3.4
n
src host 1.1.1.1 and dst port 80
tcpdump/WinDump man page:
http://www.winpcap.org/windump/docs/manual.htm
22
Documentation
n
Full list of (working) samples and a step-by-step tutorial to
libpcap/WinPcap programming
http://www.winpcap.org
n
n
(section “Documentation” – “Manual”)
A small example (slightly modified from the WinPcap site)
available on the course website
23
Caveats
n
Creating packet processing code is easy
n
Creating good packet processing code is hard
n
24
n
Efficiency matters, when you have a few clock cycles per packet
n
Avoid copying memory
n
Avoid memory allocations
n
Avoid function calls
n
Consider CPU-level issues (cache alignment, cache and memory
latencies, CPU cores bindings, etc)
Necessity to deal with tons of low-level details
n
Complex protocol encapsulations
n
IP segmentation
n
TCP session handling and payload reassembly
Alcuni warning. Creare codice che lavora sui pacchetti è relativamente semplice (a limite un attimo noioso perchè scrivo tonnellate di codice preparatorio a risolvere il problema, e poi risolverlo è easy).
Scrivere codice efficiente è un altro paio di maniche per tutti i motivi
riportati: siccome ogni tanto me la gioco su 100 colpi di clock e per
accedere a memoria ce ne metto 180 sono panato.
Poi devo gestire tonnellate di problemi di basso livello, tra cui la segmentazione IP e gestire una tabella di sessioni (i pacchetti arrivano
interlacciati)
Esistono versioni customizzate di libpcap che permettono di andare
più veloce.
Conclusions
n
De-facto standard library for packet sniffing and raw-packet
creation
n
Rather easy primitives
n
Leaves a lot of code under the responsibility of the
programmer
n
Customized
versions
available
(through
accelerated drivers) if performance are an issue
25
NIC-specific