Академический Документы
Профессиональный Документы
Культура Документы
Diamond Editions :
http://www.ed-diamond.com
http://www.gnulinuxmag.com
Ainsi que :
http://www.linux-pratique.com
et
http://www.miscmag.com
sécurité Réseau
Programmation réseau
avec Libnet et Libpcap
Cyril Nocton
EN DEUX MOTS Les bibliothèques C Libnet et Libpcap accord avec les règles de filtrage actives et applique des tests
d’intégrité dépendant de la plate-forme considérée. En mode
simplifient la programmation d’applications réseau
link, les datagrammes sont injectés au niveau de la couche de
de bas niveau. Nous appuierons notre présentation liaison, court-circuitant les contrôles du noyau.
sur une version simplifiée de l’utilitaire traceroute
baptisée YAT (Yet Another Traceroute). Plate- Somme de Adresse
Identifiant
forme contrôle source
Linux 2+ Fixée Fixé si 0 Fixée si 0
Pré-requis OpenBSD Fixée
a lecture de cet article réclame une 2.8+
bonne connaissance du langage
C et de la suite de protocoles Solaris 2.6+ Fixée
Internet. Le programme est Tests d’intégrité en mode raw
compilé avec GCC. Les tests ont été effectués
sous Mac OS X. Libpcap est une bibliothèque de capture de datagrammes
initialement développée pour épauler l’utilitaire Tcpdump.
Elle peut être combinée avec un filtre de paquets pour des
Présentation des performances optimales.
bibliothèques Libnet et
Libpcap Installation des bibliothèques
Libnet est une bibliothèque portable Libnet et Libpcap
conçue pour construire et injecter des Téléchargez les sources des bibliothèques (cf. URL en annexe).
datagrammes dans tout type de réseau. Elle Lancez les scripts d’installation.
apporte un niveau d’abstraction suffisant
pour un déploiement rapide d’applications $ tar -xzf libnet-1.1.0.tar.gz
$ cd libnet-1.1.0
réclamant un contrôle fin des données $ ./configure
transmises. Libnet gère nativement de $ make
nombreux protocoles. Représentons les $ sudo make install
plus communs dans l’optique d’un modèle $ cd ..
$ tar -xzf libpcap-0.8.3.tar.gz
réseau simplifié à quatre couches. $ cd libpcap-0.8.3
$ make
$ sudo make install
void
error(const char *format, ...)
{
va_list list;
va_start(list, format);
fprintf(stderr, «%s: «, command);
vfprintf(stderr, format, list);
va_end(list);
exit(EXIT_FAILURE);
}
Les fonctions libnet_geterror() et pcap_geterr() retournent
un message explicatif quand une des bibliothèques génère
une erreur.
Contexte Libnet
Argument ou résultat Description
l Descripteur Libnet Voici son prototype
SUCCES Un message d’erreur libnet_t *libnet_init(int injection_type, char *device, char *err_buf)
Fonction libnet_geterror()
Et la description des arguments
Construction de
datagrammes Internet libnet_ptag_t libnet_build_tcp(u_short sp, u_short dp, u_long seq,
Les fonctions de construction de datagrammes u_long ack, u_char control, u_short win, u_short sum, u_short urg,
ont des prototypes homogènes. On procède u_short len, u_char *payload, u_long payload_size, libnet_t *l,
de la couche de transport vers la couche libnet_ptag_t ptag)
de liaison.
struct probe_info_t
{
u_long ip; /* Adresse IP passerelle (big endian) */
double tm_snt; /* Heure émission sonde UDP (µs) */
double tm_rcv; /* Heure réception réponse ICMP (µs) */
char *flag; /* Drapeau associé au message */
bool reject; /* Rejet par la passerelle */
};
double
now(void)
{
Chaînage de Pblocks
Les datagrammes sont captés en aval du pilote réseau. Un Voici l’expression du filtre dans le langage
programme écrit dans un langage d’assemblage spécifique intermédiaire adopté par Tcpdump.
décide de leur validité. Les datagrammes retenus sont dupliqués #define CODE «ip dst host %s and ip[0] & 15 == 5 and ip[2:2] == 56 \
dans l’espace utilisateur sans emprunter la pile IP. Linux 2.2+ and (icmp[0] == 11 or icmp[0] == 3) and icmp[8] & 240 == 64 \
intègre un filtre LSF (Linux Socket Filter) dérivé de BPF. Nous and icmp[8] & 15 == 5 and icmp[17] == 17 and icmp[20:4] == %lu \
considérons le cas de sockets de type PF_PACKET. and icmp[24:4] == %lu and icmp[28:2] == %u and icmp[30:2] == %u»
Et sa traduction en langage d’assemblage
BPF.
(000) ldh [12]
(001) jeq #ETHERTYPE_IP jt 2 jf 34 ‘ Prologue suivi d’un datagramme IPv4
(002) ld [30]
(003) jeq #SRC_IP jt 4 jf 34 ‘ Adresse IP destination ok
(004) ldb [14]
(005) and #0xf
(006) jeq #0x5 jt 7 jf 34 ‘ En-tête IP sans options
(007) ldh [16]
(008) jeq #0x38 jt 9 jf 34 ‘ Datagramme IP de 56 octets
(009) ldb [23]
(010) jeq #PROTO_ICMP jt 11 jf 34 ‘ Datagramme IP encapsule ICMP
(011) ldh [20]
(012) jset #0x1fff jt 34 jf 13 ‘ Offset données nul
(013) ldxb 4*([14]&0xf)
(014) ldb [x + 14]
(015) jeq #ICMP_TIMXCEED jt 17 jf 16 ‘ Message ICMP Time Exceeded ou...
(016) jeq #ICMP_UNREACH jt 17 jf 34 ‘ Message ICMP Destination Unreachable
(017) ldb [x + 22]
(018) and #0xf0
(019) jeq #0x40 jt 20 jf 34 ‘ Citation IP de type IPv4
Architecture du filtre LSF (020) ldb [x + 22]
(021) and #0xf
(022) jeq #0x5 jt 23 jf 34 ‘ Citation IP sans options
Un datagramme validé par une appel sk_run_filter() est (023) ldb [x + 31]
cloné au niveau de la couche de liaison. (024) jeq #PROTO_UDP jt 25 jf 34 ‘ Citation IP encapsule UDP
YAT analyse les messages ICMP TTL Excedeed in Transit et (025) ld [x + 34]
(026) jeq #SRC_IP jt 27 jf 34 ‘ Citation adresse IP source ok
Destination Unreachable retournés par les routeurs placés
(027) ld [x + 38]
sur le chemin recherché. Ils sont formés en cascade de blocs (028) jeq #DST_IP jt 29 jf 34 ‘ Citation adresse IP destination ok
IPv4, ICMP, IPv4 et UDP. En effet, la RFC 792 stipule que ces (029) ldh [x + 42]
messages sont suivis de l’en-tête IP et des 8 premiers octets (030) jeq #SRC_PORT jt 31 jf 34 ‘ Citation port UDP source ok
de données du datagramme qui a déclenché leur envoi. Le (031) ldh [x + 44]
schéma suivant montre cet enchaînement. Les champs de (032) jeq #DST_PORT jt 33 jf 34 ‘ Citation port UDP destination ok
(033) ret #SNAP_LEN ‘ Succès
couleur rouge seront testés par un filtre BPF/LSF.
(034) ret #0 ‘ Echec
int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, Calcul d’une somme de contrôle
bpf_u_int32 netmask)
Internet
Les datagrammes échangés sur Internet possèdent un champ
Argument ou résultat Description somme de contrôle qui permet de vérifier leur intégrité.
p Descripteur Libpcap Elle est définie par la RFC 791 comme le complément à 1
fp Un programme BPF sur 16 bits de la somme en complément à 1 des mots de
16 bits composant le bloc. Le champ somme de contrôle
str Expression BPF est initialisé à 0 lors du calcul. La somme de contrôle d’un
Optimise le code si datagramme IP porte sur son en-tête. La somme de contrôle
optimize
différent de 0 d’un datagramme ICMP englobe les données. Une fonction
netmask Masque réseau ou 0 in_checksum() reprend un algorithme de calcul proposé
par la RFC 1071.
ECHEC -1
Fonction pcap_compile()
/* in_checksum - calcule une somme de contrôle Internet */
void
En C, les additions ont lieu en complément à 2. L’opposé d’un
attach_filter(void)
{ nombre positif est obtenu en ajoutant 1 à son complément à
struct bpf_program prog; 1. L’addition a lieu sans report de l’éventuelle retenue.
char code[256];
+5 00000101
sprintf(code, CODE, libnet_addr2name4(src_ip, LIBNET_DONT_RESOLVE), -3 11111101
ntohl(src_ip), ntohl(dst_ip), src_port, dst_port); --------
if (pcap_compile(capd, &prog, code, 1, 0) == -1) S 00000010
{ R 00000001
error(«can’t compile packet filter (%s)\n», pcap_geterr(capd)); --------
} S 00000010
if (pcap_setfilter(capd, &prog) == -1) Le passage en complément à 1 s’opère en reportant les
{
error(«can’t attach packet filter (%s)\n», pcap_geterr(capd));
retenues. Pour ce faire, les mots de 16 bits sont additionnés
} dans un accumulateur de 32 bits. Puis les 16 bits de plus
pcap_freecode(&prog); fort poids sont additionnés aux bits de plus faible poids au
} plus deux fois.
0 0 1
1 1 1 2
2 2 2 3
1
3 3 3
2
3
4 4
4
5 5
6 6
7 7 4
{ # yat www.freeix.net
printf(«\n%2d «, ttl); route to www2.free.fr (213.228.0.181)
} 1 192.168.0.1 (192.168.0.1) 20.6 ms 1.6 ms 1.5 ms
printf(«%s (%s) «, libnet_addr2name4(ip, LIBNET_RESOLVE), 2 1.1.99-84.rev.gaoland.net (84.99.1.1) 14.3 ms 14.1 ms 14.5 ms
libnet_addr2name4(ip, LIBNET_DONT_RESOLVE)); 3 165.226.96-84.rev.gaoland.net (84.96.226.165) 14.4 ms * 34.9 ms
last_ip = ip; 4 v3855.rou1-co-1.gaoland.net (84.96.251.109) 14.4 ms 14.2 ms *
} 5 v3856.par1-co-2.gaoland.net (84.96.251.106) 16.2 ms * 30.3 ms
printf(«%.1f ms %s «, (pinfo.tm_rcv - pinfo.tm_snt) / 1E3, 6 v4078.th21-co2.n9uf.net (62.39.148.66) 37.9 ms * *
pinfo.flag); 7 v4070.th21-co-1.n9uf.net (62.39.148.97) 27.1 ms * 29.1 ms
n_reject += pinfo.reject; 8 th1-6k-2.free.n9uf.net (84.96.235.38) 83.6 ms 16.5 ms 23.4 ms
found = found || ip == dst_ip; /* Big Endian */ 9 vlq-6k-2-v806.intf.routers.proxad.net (212.27.50.42) 16.3 ms * 32.4 ms
} 10 vlq-6k-1-po1.intf.routers.proxad.net (212.27.50.2) 16.1 ms 16.6 ms *
else 11 www2.free.fr (213.228.0.181) 27.0 ms UP 16.3 ms UP 25.0 ms UP
{
printf(«* «);
}
L’étoile marque l’absence de réponse dans un délai fixé par
fflush(stdout); défaut à une seconde. Le drapeau UP repère un message
} ICMP Port Unreachable.
putchar(‘\n’);
ttl++;
}
while (ttl <= MAX_TTL && !found && n_reject < n_queries); Liens
if (!found)
{ Sources de la bibliothèque Libnet
printf(«Destination not reached\n»); Téléchargez ici les sources officielles de la bibliothèque
} Libnet :
}
http://www.packetfactory.net/projects/libnet/
Chaque adresse IP intermédiaire est
enregistrée dans la variable last_ip.
Un passage à la ligne est généré si la valeur
change pour une distance TTL donnée.
Ceci peut arriver si une technique de
répartition de charge (load balancing) est
mise en œuvre par exemple.
Compilation du
programme
Les sources de YAT sont disponibles en ligne
(http://cyril.nocton.neuf.fr/lm/yat.zip). Pour
compiler le programme, tapez :
$ gcc -Wall `libnet-config --defines` yat.c -o yat -lnet -lpcap
Cyril Nocton,
Traçons par exemple la route vers le site web
du nœud d’échange Internet Freeix.