Créer, analyser et manipuler les paquets de données. Cette caisse fournit des outils qui peuvent être utilisés pour travailler facilement avec des paquets de données à l'aide d'une interface intuitive de haut niveau. Si vous souhaitez demander des fonctionnalités ou des améliorations, veuillez simplement ouvrir un problème, de même pour signaler tous les bogues bien sûr.
Veuillez noter que toutes les annotations de type dans cette documentation, telles que let data: Vec<u8> = packet.into_vec(); , ne sont ajoutés que pour plus de clarté et ne sont pas requis dans votre code.
Étape 1
Importez les parties appropriées du package et créez une nouvelle structure de paquets afin de commencer à le remplir. Il existe deux méthodes de création d'un nouveau paquet, la méthode 1 définira la capacité du tampon interne à la longueur appropriée pour les protocoles donnés, et la méthode 2 créera simplement un paquet totalement vide avec la capacité de tampon interne définie sur 0. La méthode 1 est préférée pour les grands paquets car chaque fois plus efficace, car
extern crate packet_crafter;
use packet_crafter::{
//import sub-modules
headers,
protocol_numbers,
ethertype_numbers,
//import data types
Packet,
Protocol
};
fn main() {
// method 1 (preferred)
let mut new_packet = Packet::new(
vec![
Protocol::ETH,
Protocol::IP,
Protocol::TCP
]
);
// method 2
let mut new_packet = Packet::new_empty();
Étape 2
Créez les en-têtes et ajoutez-les dans le paquet. Ici, nous allons aller avec la structure des paquets dans la méthode 1 de l'étape 1, qui Ethernet> IP> TCP
new_packet.add_header(
headers::EthernetHeader::new(
[6,5,4,3,2,1], // source mac address
[1,2,3,4,5,6], // destination mac address
ethertype_numbers::ETHERTYPE_IPV4
)
);
new_packet.add_header(
headers::IpHeader::new(
[192, 168, 1, 128], // source IP
[192, 168, 1, 38], // destination IP
Protocol::TCP // next protocol
)
);
new_packet.add_header(
headers::TcpHeader::new(
3838, // source port
3838 // destination port
)
);
Étape 3
Cette étape peut ne pas toujours être nécessaire, dans des cas tels que les échos ICMP où il n'est pas nécessaire qu'il n'y ait pas de données car seuls les en-têtes sont lus. Dans de nombreux cas, cependant, vous voudrez probablement ajouter des données de charge utile. Encore une fois, il existe deux façons de procéder, la méthode 1 écrasera les données de charge utile existantes (s'il s'agit d'un nouveau paquet, il n'y en aura pas de toute façon, mais s'il s'agit d'un paquet qui a été analysé à partir de données brutes, il peut y en avoir), et la méthode 2 ajoutera aux données de charge utile existantes. Remarquez l'absence de .collect() dans la méthode 2. Le code fonctionnerait toujours avec lui, cependant, il n'est pas nécessaire. Vous verrez pourquoi si vous regardez la signature de la fonction dans la source.
// method 1
new_packet.set_payload("Hello, world!".bytes().collect());
// method 2
new_packet.extend_payload("Hello, world!".bytes());
Étape 4
Les données sont maintenant prêtes, nous avons donc juste besoin de cuire le paquet. C'est là que les champs de somme de contrôle et les champs de longueur tels que celui de l'en-tête IP seront remplis (voir cette page Doc pour expliquer pourquoi j'ai décidé de les calculer même si le système d'exploitation les écrasera probablement)
let data: Vec<u8> = new_packet.into_vec();
}
N'oubliez pas que &Vec<u8> peut être transmis dans des fonctions en attendant &[u8] :)
L'analyse d'un paquet est rendue très simple, tant que le paquet est un en commençant par l'en-tête IP ou l'en-tête Ethernet II:
extern crate packet_crafter;
use packet_crafter::Packet;
fn main() {
let raw_data: &[u8] = your_function_to_read_a_packet_from_socket();
let parsed_packet: Result<Packet, packet_crafter::ParseError> = Packet::parse(raw_data);
}
Remarque: l'analyse n'a pas encore été implémentée pour les paquets IPv6
Disons que nous venons d'analyser le paquet qui est créé dans l'exemple de création du nouveau paquet , donc c'est un paquet eth> ip> TCP, et nous voulons mettre à jour le port de désinage du champ TCP ainsi que la destination IP:
// imports elided
fn main() {
let raw_data: &[u8] = your_function_to_read_a_packet_from_socket();
let mut packet = Packet::parse(raw_data).unwrap();
let mut tcp_header = packet.get_tcp_header().unwrap();
tcp_header.set_dst_port(21);
let mut ip_header = packet.get_ip_header().unwrap();
ip_header.set_dst_ip([192, 168, 1, 84]);
packet.update_header(ip_header);
// packet is now good to go, so make it and then send it:
let data = packet.into_vec();
your_function_to_send_packet_down_socket(&data);
}