├── .gitignore ├── Cargo.toml ├── examples ├── pkt.py ├── perf.py └── pkt.rs ├── tests ├── pcap.rs └── lib.rs ├── src ├── parser │ ├── mod.rs │ ├── slow.rs │ └── fast.rs ├── types.rs ├── lib.rs ├── utils.rs ├── packet.rs └── headers.rs ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.bk 4 | *.pcap 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "packet_rs" 3 | version = "0.4.0" 4 | authors = ["Ravi V"] 5 | edition = "2021" 6 | description = """ 7 | A Scapy like interface to build and define custom packet headers 8 | """ 9 | keywords = ["networking", "headers", "packets", "generation", "scapy"] 10 | repository = "https://github.com/ravi861/packet-rs" 11 | readme = "README.md" 12 | license = "Apache-2.0" 13 | exclude = [".github", ".gitignore", "*.pcap", "*.log", "tags"] 14 | 15 | [dependencies] 16 | bitfield = "0.13.2" 17 | paste = "1.0.5" 18 | pyo3 = { version = "0.16.5", optional = true } 19 | pyo3_nullify = { version = "0.1.0" } 20 | 21 | [lib] 22 | name = "packet_rs" 23 | crate-type = ["cdylib", "rlib"] 24 | 25 | [features] 26 | python-module = ["pyo3/extension-module"] 27 | default = [] 28 | 29 | [[example]] 30 | name = "pkt" 31 | 32 | [profile.release] 33 | strip = true 34 | codegen-units = 1 35 | lto = true 36 | panic = "abort" 37 | -------------------------------------------------------------------------------- /examples/pkt.py: -------------------------------------------------------------------------------- 1 | from packet_rs import * 2 | 3 | # create an ethernet header 4 | eth = Ether() 5 | eth.show() 6 | 7 | # get ethertype using idiomatic python get 8 | etype = eth.etype 9 | print(etype) 10 | 11 | # set ethertype using idiomatic python set 12 | eth.etype = 0x8100 13 | eth.show() 14 | 15 | # use the Packet helper function to create ethernet header 16 | eth = Packet.ethernet("00:11:11:11:11:11", "00:11:11:11:11:11", 0x8100) 17 | eth.show() 18 | 19 | # create a new packet of size 100 20 | pkt = Packet(100) 21 | # append above ethernet header 22 | pkt = pkt + Ether() 23 | pkt.show() 24 | 25 | # headers can also be appended to obtained a packet 26 | pkt = Ether() + Vxlan() 27 | pkt.show() 28 | 29 | # create a TCP packet appending each header 30 | pkt = Packet(100) + Ether() + IPv4() + TCP() 31 | pkt.show() 32 | 33 | # create a TCP packet using the Packet helper function 34 | pkt = Packet.create_tcp_packet("00:11:11:11:11:11", "00:06:07:08:09:0a", False, 35 | 10, 3, 5, "10.10.10.1", "11.11.11.1", 0, 64, 36 | 115, 0, [], 8888, 9090, 100, 101, 5, 0, 2, 0, 0, 37 | False, 100) 38 | # convert packet to byte array 39 | pkt.to_vec() 40 | 41 | # duplicate a packet using clone method 42 | new_pkt = pkt.clone() 43 | -------------------------------------------------------------------------------- /tests/pcap.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fs::OpenOptions, 3 | io::Write, 4 | time::{SystemTime, UNIX_EPOCH}, 5 | }; 6 | 7 | pub fn pcap_write(packets: &Vec>) { 8 | let start = SystemTime::now(); 9 | let since_the_epoch = start 10 | .duration_since(UNIX_EPOCH) 11 | .expect("Time went backwards"); 12 | let tv_sec = since_the_epoch.as_secs() as u32; 13 | let tv_usec = since_the_epoch.subsec_millis() as u32; 14 | let mut temp = OpenOptions::new() 15 | .create(true) 16 | .write(true) 17 | .append(false) 18 | .open("temp.pcap") 19 | .unwrap(); 20 | let global_header = vec![ 21 | 0xd4, 0xc3, 0xb2, 0xa1, 0x2, 0x0, 0x4, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 1, 0, 22 | 0, 0, 23 | ]; 24 | temp.write_all(global_header.as_slice()).unwrap(); 25 | 26 | for packet in packets { 27 | let plen = packet.len() as u32; 28 | let mut pcap_header = Vec::new(); 29 | pcap_header.extend_from_slice(&tv_sec.to_le_bytes()); 30 | pcap_header.extend_from_slice(&tv_usec.to_le_bytes()); 31 | pcap_header.extend_from_slice(&plen.to_le_bytes()); 32 | pcap_header.extend_from_slice(&plen.to_le_bytes()); 33 | 34 | temp.write_all(pcap_header.as_slice()).unwrap(); 35 | temp.write_all(packet).unwrap(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/parser/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Parser module to deserialize network packets 2 | //! 3 | //! This module is intended to provide full parsing capability to a variety of packet types. 4 | //! 5 | //! * Fast parsing is for quick lookup into the packet contents 6 | //! * Slow parsing is when a copy of the packet is required 7 | //! * Both APIs allow full access to all the headers within the packet and each field within each header 8 | //! * Fast parsing is atleast 3x faster than slow parsing 9 | //! 10 | //! ## Fast parsing 11 | //! 12 | //! ```ignore 13 | //! let slice: PacketSlice = fast::parse(&stream); 14 | //! ``` 15 | //! This returns a `PacketSlice` whose lifetime is same as the stream. 16 | //! 17 | //! * [`fast::parse`] is the top-level parse API which takes a full packet. 18 | //! * [`fast::parse_arp`] parses from the ARP header and below 19 | //! * [`fast::parse_ipv6`] parses from the ipv6 header and below 20 | //! * [`fast::parse_gre`] parses from the gre header and below 21 | //! 22 | //! ## Slow parsing 23 | //! 24 | //! ```ignore 25 | //! let pkt: Packet = slow::parse(&stream) 26 | //! ``` 27 | //! This returns the `Packet` struct which can then be modified or retransmitted. Below APIs return a full packet from the request offset. 28 | //! 29 | //! * [`slow::parse`] is the top-level parse API which takes a full packet. 30 | //! * [`slow::parse_ethernet`] parses from the ethernet header and below 31 | //! * [`slow::parse_ipv4`] parses from the ipv4 header and below 32 | //! * [`slow::parse_vxlan`] parses from the vxlan header and below 33 | //! 34 | pub mod fast; 35 | pub mod slow; 36 | -------------------------------------------------------------------------------- /examples/perf.py: -------------------------------------------------------------------------------- 1 | from ptf.testutils import * 2 | from packet_rs import * 3 | from datetime import datetime 4 | import copy 5 | 6 | import scapy.layers.l2 7 | import scapy.layers.inet 8 | 9 | iEther = scapy.layers.l2.Ether 10 | iIP = scapy.layers.inet.IP 11 | iTCP = scapy.layers.inet.TCP 12 | 13 | ''' 14 | Results from running this script: 15 | 0:00:15.593012 100000 Scapy construct TCP 16 | 0:00:06.082119 10000 PTF simple_tcp_packet 17 | 0:00:00.493261 100000 Rscapy construct TCP 18 | 0:00:00.173716 100000 Rscapy create_tcp_packet 19 | 20 | 0:00:07.370621 100000 Scapy clone 21 | 0:00:00.998611 10000 PTF clone 22 | 0:00:00.033968 100000 Rscapy clone 23 | ''' 24 | 25 | cnt = 100000 26 | tstart = datetime.now() 27 | for i in range(0,cnt): 28 | p = iEther() / iIP() / iTCP() 29 | print(datetime.now() - tstart, cnt, "Scapy construct TCP") 30 | 31 | pkt = iEther() / iIP() / iTCP() 32 | tstart = datetime.now() 33 | for i in range(0,cnt): 34 | p = copy.deepcopy(pkt) 35 | print(datetime.now() - tstart, cnt, "Scapy clone") 36 | 37 | tstart = datetime.now() 38 | for i in range(0,10000): 39 | p = simple_tcp_packet() 40 | print(datetime.now() - tstart, 10000, " PTF simple_tcp_packet") 41 | 42 | pkt = simple_tcp_packet() 43 | tstart = datetime.now() 44 | for i in range(0,10000): 45 | p = copy.deepcopy(pkt) 46 | print(datetime.now() - tstart, 10000, " PTF clone") 47 | 48 | tstart = datetime.now() 49 | for i in range(0,cnt): 50 | p = Ether() + IPv4() + TCP() 51 | print(datetime.now() - tstart, cnt, "Rscapy construct TCP") 52 | 53 | tstart = datetime.now() 54 | for i in range(0,cnt): 55 | p = Packet.create_tcp_packet("00:11:11:11:11:11", "00:06:07:08:09:0a", False, 56 | 10, 3, 5, "10.10.10.1", "11.11.11.1", 0, 64, 115, 57 | 0, [], 8888, 9090, 100, 101, 5, 0, 2, 0, 0, False, 58 | 100) 59 | print(datetime.now() - tstart, cnt, "Rscapy create_tcp_packet") 60 | 61 | pkt = Packet.create_tcp_packet("00:11:11:11:11:11", "00:06:07:08:09:0a", False, 62 | 10, 3, 5, "10.10.10.1", "11.11.11.1", 0, 64, 115, 63 | 0, [], 8888, 9090, 100, 101, 5, 0, 2, 0, 0, False, 64 | 100) 65 | tstart = datetime.now() 66 | for i in range(0,cnt): 67 | p = pkt.clone_me() 68 | print(datetime.now() - tstart, cnt, "Rscapy clone") 69 | -------------------------------------------------------------------------------- /examples/pkt.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate packet_rs; 3 | 4 | use packet_rs::headers::*; 5 | use packet_rs::utils; 6 | use packet_rs::Packet; 7 | 8 | fn main() { 9 | make_header!( 10 | MyHeader 4 11 | ( 12 | field_1: 0-2, 13 | field_2: 3-3, 14 | field_3: 4-15, 15 | field_4: 16-31 16 | ) 17 | vec![0x0, 0xa, 0x8, 0x0] // <= optional default data 18 | ); 19 | 20 | // 2 ways to use a header 21 | // Call new on the *MyHeader* header 22 | let hdr = MyHeader::new(); 23 | hdr.show(); 24 | 25 | // Pass a data buffer as an argument 26 | let mut hdr = MyHeader::from(vec![0xF3, 0x01, 0x08, 0xFF]); 27 | // fetch the field_2 value 28 | println!("{}", hdr.field_2()); 29 | // set the field_2 value 30 | hdr.set_field_2(1); 31 | hdr.show(); 32 | 33 | // create a simple Ether header 34 | let mut eth = Ether::new(); 35 | eth.show(); 36 | 37 | // get the etype field from the header 38 | let etype = eth.etype(); 39 | println!("{}", etype); 40 | 41 | // update the etype field in the header 42 | eth.set_etype(0x8100); 43 | eth.show(); 44 | 45 | // use the Packet associate function to create ethernet header 46 | let eth = Packet::ethernet("00:11:11:11:11:11", "00:11:11:11:11:11", 0x8100); 47 | eth.show(); 48 | 49 | // create a UDP packet by pushing each header in sequence 50 | let mut pkt = Packet::new(); 51 | pkt.push(Ether::new()); 52 | pkt.push(IPv4::new()); 53 | pkt.push(UDP::new()); 54 | pkt.show(); 55 | 56 | // convert packet to byte array 57 | let v = pkt.to_vec(); 58 | println!("{:?}", v); 59 | 60 | // duplicate a packet using clone 61 | let new_pkt = pkt.clone(); 62 | new_pkt.show(); 63 | 64 | let payload: Vec = (0..100).collect::>(); 65 | // create a TCP packet using the Packet associate function 66 | let pkt = utils::create_tcp_packet( 67 | "00:01:02:03:04:05", 68 | "00:06:07:08:09:0a", 69 | false, 70 | 10, 71 | 3, 72 | 5, 73 | "10.10.10.1", 74 | "11.11.11.1", 75 | 0, 76 | 64, 77 | 115, 78 | 0, 79 | Vec::new(), 80 | 1234, 81 | 9090, 82 | 100, 83 | 101, 84 | 5, 85 | 0, 86 | 0x10, 87 | 2, 88 | 0, 89 | false, 90 | &payload, 91 | ); 92 | pkt.show(); 93 | } 94 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | 3 | pub const MAC_LEN: usize = 6; 4 | pub const IPV4_LEN: usize = 4; 5 | pub const IPV6_LEN: usize = 16; 6 | 7 | pub const UDP_PORT_VXLAN: u16 = 4789; 8 | 9 | pub enum IpType { 10 | V4 = 4, 11 | V6 = 6, 12 | } 13 | impl TryFrom for IpType { 14 | type Error = String; 15 | 16 | fn try_from(v: u8) -> Result { 17 | match v { 18 | x if x == IpType::V4 as u8 => Ok(IpType::V4), 19 | x if x == IpType::V6 as u8 => Ok(IpType::V6), 20 | _ => Err(format!("Unsupported IpType {}", v)), 21 | } 22 | } 23 | } 24 | 25 | pub enum IpProtocol { 26 | ICMP = 1, 27 | IPIP = 4, 28 | TCP = 6, 29 | UDP = 17, 30 | IPV6 = 41, 31 | GRE = 47, 32 | ICMPV6 = 58, 33 | } 34 | impl TryFrom for IpProtocol { 35 | type Error = String; 36 | 37 | fn try_from(v: u8) -> Result { 38 | match v { 39 | x if x == IpProtocol::ICMP as u8 => Ok(IpProtocol::ICMP), 40 | x if x == IpProtocol::IPIP as u8 => Ok(IpProtocol::IPIP), 41 | x if x == IpProtocol::TCP as u8 => Ok(IpProtocol::TCP), 42 | x if x == IpProtocol::UDP as u8 => Ok(IpProtocol::UDP), 43 | x if x == IpProtocol::IPV6 as u8 => Ok(IpProtocol::IPV6), 44 | x if x == IpProtocol::GRE as u8 => Ok(IpProtocol::GRE), 45 | x if x == IpProtocol::ICMPV6 as u8 => Ok(IpProtocol::ICMPV6), 46 | _ => Err(format!("Unsupported IpProtocol {}", v)), 47 | } 48 | } 49 | } 50 | 51 | pub enum EtherType { 52 | IPV4 = 0x0800, 53 | ARP = 0x0806, 54 | DOT1Q = 0x8100, 55 | IPV6 = 0x86DD, 56 | MPLS = 0x8847, 57 | ERSPANII = 0x88be, 58 | ERSPANIII = 0x22eb, 59 | } 60 | impl TryFrom for EtherType { 61 | type Error = String; 62 | 63 | fn try_from(v: u16) -> Result { 64 | match v { 65 | x if x == EtherType::IPV4 as u16 => Ok(EtherType::IPV4), 66 | x if x == EtherType::ARP as u16 => Ok(EtherType::ARP), 67 | x if x == EtherType::DOT1Q as u16 => Ok(EtherType::DOT1Q), 68 | x if x == EtherType::IPV6 as u16 => Ok(EtherType::IPV6), 69 | x if x == EtherType::MPLS as u16 => Ok(EtherType::MPLS), 70 | x if x == EtherType::ERSPANII as u16 => Ok(EtherType::ERSPANII), 71 | x if x == EtherType::ERSPANIII as u16 => Ok(EtherType::ERSPANIII), 72 | _ => Err(format!("Unsupported EtherType {}", v)), 73 | } 74 | } 75 | } 76 | 77 | pub enum ErspanVersion { 78 | II = 1, 79 | III = 2, 80 | } 81 | impl TryFrom for ErspanVersion { 82 | type Error = String; 83 | 84 | fn try_from(v: u16) -> Result { 85 | match v { 86 | x if x == ErspanVersion::II as u16 => Ok(ErspanVersion::II), 87 | x if x == ErspanVersion::III as u16 => Ok(ErspanVersion::III), 88 | _ => Err(format!("Unsupported ErspanVersion {}", v)), 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | packet_rs is a Rust based Scapy alternative 2 | 3 | Introduction 4 | ============ 5 | packet_rs is a rust based alternative to the popular python Scapy packet library. It tries to provide a scapy like API interface to define new headers and construct packets. 6 |
7 | packet_rs has the most common networking headers already pre-defined. 8 | 9 | make_header 10 | =========== 11 | The core of the library is the *make_header* macro which provides a flexible way to create new headers.
12 | Describe a new header in the below format with defaults as a vector. 13 | ``` 14 | make_header! { 15 | ( 16 | - , 17 | - , 18 | ) 19 | 20 | }; 21 | ``` 22 | 23 | Define a header 24 | --------------- 25 | Add a new header by using the *make_header* macro. This automatically creates a set_*field*() and a *field*() helper methods for each field. 26 | 27 | ```rust 28 | #[macro_use] 29 | extern crate packet_rs; 30 | 31 | use packet_rs::headers::*; 32 | use packet_rs::Packet; 33 | 34 | make_header!( 35 | MyHeader 4 36 | ( 37 | field_1: 0-2, 38 | field_2: 3-3, 39 | field_3: 4-15, 40 | field_4: 16-31 41 | ) 42 | vec![0x0, 0xa, 0x8, 0x0] // <= optional default data 43 | ); 44 | ``` 45 | 2 ways to create a header 46 | ------------------------- 47 | ```rust 48 | // Call new on the *MyHeader* header 49 | let hdr = MyHeader::new(); 50 | 51 | // Pass a data buffer as an argument 52 | let hdr = MyHeader([0x00, 0x0a, 0x08, 0x10]); 53 | ``` 54 | make_header! generates helper methods and associated functions for each header and fields 55 | ```rust 56 | hdr.octets(); // get the vlan header as a byte array 57 | println!("{}", hdr.field_2()); // fetch the cfi field value 58 | hdr.set_field_2(1); // set the cfi field value 59 | let hdr_new = hdr.clone(); // clone the packet 60 | hdr.show(); // display the vlan header 61 | 62 | Output of show(): 63 | Raw: 00 0a 08 00 64 | #### MyHeader Size Data 65 | ------------------------------------------- 66 | field_1 : 3 : 02 67 | field_2 : 1 : 01 68 | field_3 : 12 : 00 10 69 | field_4 : 16 : 08 00 70 | ``` 71 | Create a Packet 72 | --------------- 73 | A packet is an ordered list of headers. Push headers as required into a packet. 74 | ```rust 75 | let mut pkt = Packet::new(100); 76 | pkt.push(Ether::new())); 77 | pkt.push(IPv4::new()); 78 | pkt.show() 79 | 80 | #### Ether Size Data 81 | ------------------------------------------- 82 | dst : 48 : 00 01 02 03 04 05 83 | src : 48 : 00 06 07 08 09 0a 84 | etype : 16 : 08 00 85 | #### IPv4 Size Data 86 | ------------------------------------------- 87 | version : 4 : 04 88 | ihl : 4 : 05 89 | diffserv : 8 : 00 90 | total_len : 16 : 00 14 91 | identification : 16 : 00 33 92 | flags : 3 : 02 93 | frag_startset : 13 : 06 29 94 | ttl : 8 : 64 95 | protocol : 8 : 06 96 | header_checksum : 16 : fa ec 97 | src : 32 : c0 a8 00 01 98 | dst : 32 : c0 a8 00 02 99 | 100 | // access ethernet header immutable 101 | let x: &Ether> = (&pkt["Ether"]).into(); 102 | println!("{}", x.etype()); 103 | 104 | // access ethernet header mutable 105 | let x: &mut Ether> = (&mut pkt["Ether"]).into(); 106 | x.set_etype(0x1111); 107 | ``` 108 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Ravi V 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! # packet_rs 10 | //! 11 | //! packet_rs is a rust based alternative to the popular python Scapy packet library. It tries to provide a scapy like API interface to define new headers and construct packets. 12 | //! 13 | //! * The [`headers`] module, defines commonly used network packet headers and allows for defining new header types 14 | //! * The [`Packet`] struct, a convenient abstraction of a network packet and container to hold a group of headers 15 | //! * The [`parser`] module, provides a super fast packet deserializer to compose Packets from slices 16 | //! 17 | //! ### Terminology 18 | //! * Packet refers to a container which represents a network packet 19 | //! * Headers are network headers like ARP, IP, Vxlan, etc 20 | //! * Slice is a network packet represented as a series of u8 bytes 21 | //! 22 | //! ### Create a header 23 | //! A header is a network protocol header and allows to individually get/set each field in the header 24 | //! ``` 25 | //! # extern crate packet_rs; 26 | //! # use packet_rs::headers::{Ether}; 27 | //! # 28 | //! let mut eth = Ether::new(); 29 | //! eth.set_dst(0xaabbccddeeff); 30 | //! println!("{}", eth.etype()); 31 | //! ``` 32 | //! 33 | //! ### Create a Packet 34 | //! A packet is an ordered list of headers. 35 | //! 36 | //! * Push or pop headers into the packet 37 | //! * Mutably/immutably retrieve existing headers 38 | //! * Set a custom payload 39 | //! ``` 40 | //! # extern crate packet_rs; 41 | //! # use packet_rs::Packet; 42 | //! # use packet_rs::headers::{Ether, IPv4}; 43 | //! # 44 | //! let mut pkt = Packet::new(); 45 | //! pkt.push(Ether::new()); 46 | //! pkt.push(IPv4::new()); 47 | //! pkt.push(Packet::udp(1023, 1234, 95)); 48 | //! ``` 49 | //! 50 | //! ### Parse a byte stream 51 | //! Parse a byte stream to generate a [`Packet`] or a [`PacketSlice`] 52 | //! 53 | //! * The parser fast module is zero-copy and generates a PacketSlice. PacketSlice has the same lifetime as the byte stream. 54 | //! * The parser slow module creates a new packet from the byte stream. 55 | //! 56 | //! Both of the above parsing options provide full access to all the headers and each field within the header. 57 | //! ``` 58 | //! # extern crate packet_rs; 59 | //! # use packet_rs::Packet; 60 | //! # use packet_rs::parser; 61 | //! # use packet_rs::headers::*; 62 | //! # 63 | //! # let mut data = Packet::new(); 64 | //! # data.push(Ether::new()); 65 | //! # data.push(IPv4::new()); 66 | //! # data.push(TCP::new()); 67 | //! # let data = data.to_vec(); 68 | //! 69 | //! let mut pkt: Packet = parser::slow::parse(&data.as_slice()); 70 | //! let eth: &mut Ether = (&mut pkt["Ether"]).into(); 71 | //! println!("{}", eth.etype()); 72 | //! ``` 73 | //! Similar semantics apply for fast parsing except where a PacketSlice is returned. 74 | //! * [`parser::slow::parse_ethernet`] for parsing from an Ethernet header and below and then edit it 75 | //! * [`parser::fast::parse_ipv4`] for parsing`] from an IPv4 and below and is read-only 76 | //! 77 | //! ### Define a header 78 | //! 79 | //! Define a header which can go into a new protocol stack 80 | //! 81 | //! ```ignore 82 | //! # #[macro_use] 83 | //! # extern crate packet_rs; 84 | //! # use packet_rs::make_header; 85 | //! make_header!( 86 | //! MyHeader 4 87 | //! ( 88 | //! field_1: 0-2, 89 | //! field_2: 3-3, 90 | //! field_3: 4-15, 91 | //! field_4: 16-31 92 | //! ) 93 | //! vec![0x0, 0xa, 0x8, 0x0] // <= optional default data 94 | //! ); 95 | //! 96 | //! // Create the custom header 97 | //! let hdr = MyHeader::new(); 98 | //! 99 | //! // make_header! generates helper methods and associated functions for each field in the header 100 | //! println!("{}", hdr.field_2()); // fetch the field_2 value 101 | //! hdr.set_field_2(1); // set the field_2 value 102 | //! hdr.show(); // display the MyHeader header 103 | //! ``` 104 | //! 105 | //! ### Python support 106 | //! 107 | //! packet_rs supports Rust bindings for Python. All of the pre-defined header and Packet APIs are available as Python APIs 108 | //! Please refer to examples/pkt.py and pyo3/maturin documentation on how to use the bindings. 109 | //! 110 | //! ```sh 111 | //! cargo build --features python-module 112 | //! ``` 113 | //! 114 | 115 | pub mod headers; 116 | mod packet; 117 | pub mod parser; 118 | pub(crate) mod types; 119 | pub mod utils; 120 | 121 | use headers::*; 122 | 123 | #[cfg(not(feature = "python-module"))] 124 | use pyo3_nullify::*; 125 | 126 | #[cfg(feature = "python-module")] 127 | use pyo3::prelude::*; 128 | 129 | #[pyclass] 130 | /// Structure used to hold an ordered list of headers 131 | pub struct Packet { 132 | hdrs: Vec>, 133 | payload: Vec, 134 | } 135 | 136 | /// Structure used to hold an ordered list of header slices 137 | pub struct PacketSlice<'a> { 138 | hdrs: Vec>, 139 | payload: &'a [u8], 140 | } 141 | 142 | #[cfg(feature = "python-module")] 143 | #[pymodule] 144 | fn packet(_py: Python, m: &PyModule) -> PyResult<()> { 145 | m.add_class::()?; 146 | m.add_class::()?; 147 | m.add_class::()?; 148 | m.add_class::()?; 149 | m.add_class::()?; 150 | m.add_class::()?; 151 | m.add_class::()?; 152 | m.add_class::()?; 153 | m.add_class::()?; 154 | m.add_class::()?; 155 | m.add_class::()?; 156 | m.add_class::()?; 157 | m.add_class::()?; 158 | m.add_class::()?; 159 | m.add_class::()?; 160 | m.add_class::()?; 161 | m.add_class::()?; 162 | m.add_class::()?; 163 | m.add_class::()?; 164 | m.add_class::()?; 165 | m.add_class::()?; 166 | m.add_class::()?; 167 | 168 | Ok(()) 169 | } 170 | -------------------------------------------------------------------------------- /src/parser/slow.rs: -------------------------------------------------------------------------------- 1 | use crate::headers::*; 2 | use crate::types::*; 3 | use crate::Packet; 4 | 5 | pub fn parse(arr: &[u8]) -> Packet { 6 | let length: u16 = ((arr[12] as u16) << 8) | arr[13] as u16; 7 | if length < 1500 { 8 | parse_dot3(arr) 9 | } else { 10 | parse_ethernet(arr) 11 | } 12 | } 13 | pub fn parse_dot3(arr: &[u8]) -> Packet { 14 | let dot3 = Dot3::from(arr[0..Dot3::size()].to_vec()); 15 | let mut pkt = parse_llc(&arr[Dot3::size()..]); 16 | pkt.insert(dot3); 17 | pkt 18 | } 19 | pub fn parse_llc(arr: &[u8]) -> Packet { 20 | let llc = LLC::from(arr[0..LLC::size()].to_vec()); 21 | let mut pkt = if arr[0] == 0xAA && arr[1] == 0xAA && arr[2] == 0x03 { 22 | parse_snap(&arr[LLC::size()..]) 23 | } else { 24 | accept(&arr[LLC::size()..]) 25 | }; 26 | pkt.insert(llc); 27 | pkt 28 | } 29 | pub fn parse_snap(arr: &[u8]) -> Packet { 30 | let snap = SNAP::from(arr[0..SNAP::size()].to_vec()); 31 | let mut pkt = accept(&arr[SNAP::size()..]); 32 | pkt.insert(snap); 33 | pkt 34 | } 35 | pub fn parse_ethernet(arr: &[u8]) -> Packet { 36 | let eth = Ether::from(arr[0..Ether::size()].to_vec()); 37 | let etype = EtherType::try_from(eth.etype() as u16); 38 | let mut pkt = match etype { 39 | Ok(EtherType::DOT1Q) => parse_vlan(&arr[Ether::size()..]), 40 | Ok(EtherType::ARP) => parse_arp(&arr[Ether::size()..]), 41 | Ok(EtherType::IPV4) => parse_ipv4(&arr[Ether::size()..]), 42 | Ok(EtherType::IPV6) => parse_ipv6(&arr[Ether::size()..]), 43 | Ok(EtherType::MPLS) => parse_mpls(&arr[Ether::size()..]), 44 | _ => accept(&arr[Ether::size()..]), 45 | }; 46 | pkt.insert(eth); 47 | pkt 48 | } 49 | pub fn parse_vlan(arr: &[u8]) -> Packet { 50 | let vlan = Vlan::from(arr[0..Vlan::size()].to_vec()); 51 | let etype = EtherType::try_from(vlan.etype() as u16); 52 | let mut pkt = match etype { 53 | Ok(EtherType::DOT1Q) => parse_vlan(&arr[Vlan::size()..]), 54 | Ok(EtherType::ARP) => parse_arp(&arr[Vlan::size()..]), 55 | Ok(EtherType::IPV4) => parse_ipv4(&arr[Vlan::size()..]), 56 | Ok(EtherType::IPV6) => parse_ipv6(&arr[Vlan::size()..]), 57 | Ok(EtherType::MPLS) => parse_mpls(&arr[Vlan::size()..]), 58 | _ => accept(&arr[Vlan::size()..]), 59 | }; 60 | pkt.insert(vlan); 61 | pkt 62 | } 63 | pub fn parse_mpls(arr: &[u8]) -> Packet { 64 | let mpls = MPLS::from(arr[0..MPLS::size()].to_vec()); 65 | let bos = mpls.bos(); 66 | let mut pkt = if bos == 1 { 67 | parse_mpls_bos(&arr[MPLS::size()..]) 68 | } else { 69 | parse_mpls(&arr[MPLS::size()..]) 70 | }; 71 | pkt.insert(mpls); 72 | pkt 73 | } 74 | pub fn parse_mpls_bos(arr: &[u8]) -> Packet { 75 | let mpls = MPLS::from(arr[0..MPLS::size()].to_vec()); 76 | let mut pkt = match IpType::try_from(arr[MPLS::size()] >> 4 & 0xf) { 77 | Ok(IpType::V4) => parse_ipv4(&arr[MPLS::size()..]), 78 | Ok(IpType::V6) => parse_ipv6(&arr[MPLS::size()..]), 79 | _ => parse_ethernet(&arr[MPLS::size()..]), 80 | }; 81 | pkt.insert(mpls); 82 | pkt 83 | } 84 | pub fn parse_ipv4(arr: &[u8]) -> Packet { 85 | let ipv4 = IPv4::from(arr[0..IPv4::size()].to_vec()); 86 | let proto = IpProtocol::try_from(ipv4.protocol() as u8); 87 | let mut pkt = match proto { 88 | Ok(IpProtocol::ICMP) => parse_icmp(&arr[IPv4::size()..]), 89 | Ok(IpProtocol::IPIP) => parse_ipv4(&arr[IPv4::size()..]), 90 | Ok(IpProtocol::TCP) => parse_tcp(&arr[IPv4::size()..]), 91 | Ok(IpProtocol::UDP) => parse_udp(&arr[IPv4::size()..]), 92 | Ok(IpProtocol::IPV6) => parse_ipv6(&arr[IPv4::size()..]), 93 | Ok(IpProtocol::GRE) => parse_gre(&arr[IPv4::size()..]), 94 | _ => accept(&arr[IPv4::size()..]), 95 | }; 96 | pkt.insert(ipv4); 97 | pkt 98 | } 99 | pub fn parse_ipv6(arr: &[u8]) -> Packet { 100 | let ipv6 = IPv6::from(arr[0..IPv6::size()].to_vec()); 101 | let next_hdr = IpProtocol::try_from(ipv6.next_hdr() as u8); 102 | let mut pkt = match next_hdr { 103 | Ok(IpProtocol::ICMPV6) => parse_icmp(&arr[IPv6::size()..]), 104 | Ok(IpProtocol::IPIP) => parse_ipv4(&arr[IPv6::size()..]), 105 | Ok(IpProtocol::TCP) => parse_tcp(&arr[IPv6::size()..]), 106 | Ok(IpProtocol::UDP) => parse_udp(&arr[IPv6::size()..]), 107 | Ok(IpProtocol::IPV6) => parse_ipv6(&arr[IPv6::size()..]), 108 | Ok(IpProtocol::GRE) => parse_gre(&arr[IPv6::size()..]), 109 | _ => accept(&arr[IPv6::size()..]), 110 | }; 111 | pkt.insert(ipv6); 112 | pkt 113 | } 114 | pub fn parse_gre(arr: &[u8]) -> Packet { 115 | let gre = GRE::from(arr[0..GRE::size()].to_vec()); 116 | let proto = EtherType::try_from(gre.proto() as u16); 117 | let chksum_present = gre.chksum_present(); 118 | let seqnum_present = gre.seqnum_present(); 119 | let key_present = gre.key_present(); 120 | let mut offset = 0; 121 | offset += GRE::size(); 122 | let gco = if chksum_present == 1 { 123 | let p = Some(GREChksumOffset::from( 124 | arr[offset..offset + GREChksumOffset::size()].to_vec(), 125 | )); 126 | offset += GREChksumOffset::size(); 127 | p 128 | } else { 129 | None 130 | }; 131 | let gk = if key_present == 1 { 132 | let p = Some(GREKey::from(arr[offset..offset + GREKey::size()].to_vec())); 133 | offset += GREKey::size(); 134 | p 135 | } else { 136 | None 137 | }; 138 | let gsn = if seqnum_present == 1 { 139 | let p = Some(GRESequenceNum::from( 140 | arr[offset..offset + GRESequenceNum::size()].to_vec(), 141 | )); 142 | offset += GRESequenceNum::size(); 143 | p 144 | } else { 145 | None 146 | }; 147 | let mut pkt = match proto { 148 | Ok(EtherType::IPV4) => parse_ipv4(&arr[offset..]), 149 | Ok(EtherType::IPV6) => parse_ipv6(&arr[offset..]), 150 | Ok(EtherType::ERSPANII) => parse_erspan2(&arr[offset..]), 151 | Ok(EtherType::ERSPANIII) => parse_erspan3(&arr[offset..]), 152 | _ => accept(&arr[offset..]), 153 | }; 154 | if let Some(p) = gco { 155 | pkt.insert(p); 156 | } 157 | if let Some(p) = gk { 158 | pkt.insert(p); 159 | } 160 | if let Some(p) = gsn { 161 | pkt.insert(p); 162 | } 163 | pkt.insert(gre); 164 | pkt 165 | } 166 | pub fn parse_erspan2(arr: &[u8]) -> Packet { 167 | let erspan2 = ERSPAN2::from(arr[0..ERSPAN2::size()].to_vec()); 168 | let mut pkt = parse_ethernet(&arr[ERSPAN2::size()..]); 169 | pkt.insert(erspan2); 170 | pkt 171 | } 172 | pub fn parse_erspan3(arr: &[u8]) -> Packet { 173 | let erspan3 = ERSPAN3::from(arr[0..ERSPAN3::size()].to_vec()); 174 | let o = erspan3.o(); 175 | let mut offset = 0; 176 | offset += ERSPAN3::size(); 177 | let platform = if o == 1 { 178 | let p = Some(ERSPANPLATFORM::from( 179 | arr[offset..offset + ERSPANPLATFORM::size()].to_vec(), 180 | )); 181 | offset += ERSPANPLATFORM::size(); 182 | p 183 | } else { 184 | None 185 | }; 186 | let mut pkt = parse_ethernet(&arr[offset..]); 187 | if let Some(p) = platform { 188 | pkt.insert(p); 189 | } 190 | pkt.insert(erspan3); 191 | pkt 192 | } 193 | pub fn parse_arp(arr: &[u8]) -> Packet { 194 | let mut pkt = accept(&arr[ARP::size()..]); 195 | pkt.insert(ARP::from(arr[0..ARP::size()].to_vec())); 196 | pkt 197 | } 198 | pub fn parse_icmp(arr: &[u8]) -> Packet { 199 | let mut pkt = accept(&arr[ICMP::size()..]); 200 | pkt.insert(ICMP::from(arr[0..ICMP::size()].to_vec())); 201 | pkt 202 | } 203 | pub fn parse_tcp(arr: &[u8]) -> Packet { 204 | let mut pkt = accept(&arr[TCP::size()..]); 205 | pkt.insert(TCP::from(arr[0..TCP::size()].to_vec())); 206 | pkt 207 | } 208 | pub fn parse_udp(arr: &[u8]) -> Packet { 209 | let udp = UDP::from(arr[0..UDP::size()].to_vec()); 210 | let dst = udp.dst() as u16; 211 | let mut pkt = match dst { 212 | UDP_PORT_VXLAN => parse_vxlan(&arr[UDP::size()..]), 213 | _ => accept(&arr[UDP::size()..]), 214 | }; 215 | pkt.insert(udp); 216 | pkt 217 | } 218 | pub fn parse_vxlan(arr: &[u8]) -> Packet { 219 | let mut pkt = parse_ethernet(&arr[Vxlan::size()..]); 220 | pkt.insert(Vxlan::from(arr[0..Vxlan::size()].to_vec())); 221 | pkt 222 | } 223 | fn accept(arr: &[u8]) -> Packet { 224 | let mut pkt = Packet::new(); 225 | pkt.set_payload(arr); 226 | pkt 227 | } 228 | -------------------------------------------------------------------------------- /src/parser/fast.rs: -------------------------------------------------------------------------------- 1 | use crate::headers::*; 2 | use crate::types::*; 3 | use crate::PacketSlice; 4 | 5 | pub fn parse<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 6 | let length: u16 = ((arr[12] as u16) << 8) | arr[13] as u16; 7 | if length < 1500 { 8 | parse_dot3(arr) 9 | } else { 10 | parse_ethernet(arr) 11 | } 12 | } 13 | pub fn parse_dot3<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 14 | let dot3 = Dot3Slice::from(&arr[0..Dot3::size()]); 15 | let mut pkt = parse_llc(&arr[Dot3::size()..]); 16 | pkt.insert(dot3); 17 | pkt 18 | } 19 | pub fn parse_llc<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 20 | let llc = LLCSlice::from(&arr[0..LLC::size()]); 21 | let mut pkt = if arr[0] == 0xAA && arr[1] == 0xAA && arr[2] == 0x03 { 22 | parse_snap(&arr[LLC::size()..]) 23 | } else { 24 | accept(&arr[LLC::size()..]) 25 | }; 26 | pkt.insert(llc); 27 | pkt 28 | } 29 | pub fn parse_snap<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 30 | let snap = SNAPSlice::from(&arr[0..SNAP::size()]); 31 | let mut pkt = accept(&arr[SNAP::size()..]); 32 | pkt.insert(snap); 33 | pkt 34 | } 35 | pub fn parse_ethernet<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 36 | let eth = EtherSlice::from(&arr[0..Ether::size()]); 37 | let etype = EtherType::try_from(eth.etype() as u16); 38 | let mut pkt = match etype { 39 | Ok(EtherType::DOT1Q) => parse_vlan(&arr[Ether::size()..]), 40 | Ok(EtherType::ARP) => parse_arp(&arr[Ether::size()..]), 41 | Ok(EtherType::IPV4) => parse_ipv4(&arr[Ether::size()..]), 42 | Ok(EtherType::IPV6) => parse_ipv6(&arr[Ether::size()..]), 43 | Ok(EtherType::MPLS) => parse_mpls(&arr[Ether::size()..]), 44 | _ => accept(&arr[Ether::size()..]), 45 | }; 46 | pkt.insert(eth); 47 | pkt 48 | } 49 | pub fn parse_vlan<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 50 | let vlan = VlanSlice::from(&arr[0..Vlan::size()]); 51 | let etype = EtherType::try_from(vlan.etype() as u16); 52 | let mut pkt = match etype { 53 | Ok(EtherType::DOT1Q) => parse_vlan(&arr[Vlan::size()..]), 54 | Ok(EtherType::ARP) => parse_arp(&arr[Vlan::size()..]), 55 | Ok(EtherType::IPV4) => parse_ipv4(&arr[Vlan::size()..]), 56 | Ok(EtherType::IPV6) => parse_ipv6(&arr[Vlan::size()..]), 57 | Ok(EtherType::MPLS) => parse_mpls(&arr[Vlan::size()..]), 58 | _ => accept(&arr[Vlan::size()..]), 59 | }; 60 | pkt.insert(vlan); 61 | pkt 62 | } 63 | pub fn parse_mpls<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 64 | let mpls = MPLSSlice::from(&arr[0..MPLS::size()]); 65 | let bos = mpls.bos(); 66 | let mut pkt = if bos == 1 { 67 | parse_mpls_bos(&arr[MPLS::size()..]) 68 | } else { 69 | parse_mpls(&arr[MPLS::size()..]) 70 | }; 71 | pkt.insert(mpls); 72 | pkt 73 | } 74 | pub fn parse_mpls_bos<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 75 | let mpls = MPLSSlice::from(&arr[0..MPLS::size()]); 76 | let mut pkt = match IpType::try_from(arr[MPLS::size()] >> 4 & 0xf) { 77 | Ok(IpType::V4) => parse_ipv4(&arr[MPLS::size()..]), 78 | Ok(IpType::V6) => parse_ipv6(&arr[MPLS::size()..]), 79 | _ => parse_ethernet(&arr[MPLS::size()..]), 80 | }; 81 | pkt.insert(mpls); 82 | pkt 83 | } 84 | pub fn parse_ipv4<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 85 | let ipv4 = IPv4Slice::from(&arr[0..IPv4::size()]); 86 | let proto = IpProtocol::try_from(ipv4.protocol() as u8); 87 | let mut pkt = match proto { 88 | Ok(IpProtocol::ICMP) => parse_icmp(&arr[IPv4::size()..]), 89 | Ok(IpProtocol::IPIP) => parse_ipv4(&arr[IPv4::size()..]), 90 | Ok(IpProtocol::TCP) => parse_tcp(&arr[IPv4::size()..]), 91 | Ok(IpProtocol::UDP) => parse_udp(&arr[IPv4::size()..]), 92 | Ok(IpProtocol::IPV6) => parse_ipv6(&arr[IPv4::size()..]), 93 | Ok(IpProtocol::GRE) => parse_gre(&arr[IPv4::size()..]), 94 | _ => accept(&arr[IPv4::size()..]), 95 | }; 96 | pkt.insert(ipv4); 97 | pkt 98 | } 99 | pub fn parse_ipv6<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 100 | let ipv6 = IPv6Slice::from(&arr[0..IPv6::size()]); 101 | let next_hdr = IpProtocol::try_from(ipv6.next_hdr() as u8); 102 | let mut pkt = match next_hdr { 103 | Ok(IpProtocol::ICMPV6) => parse_icmp(&arr[IPv6::size()..]), 104 | Ok(IpProtocol::IPIP) => parse_ipv4(&arr[IPv6::size()..]), 105 | Ok(IpProtocol::TCP) => parse_tcp(&arr[IPv6::size()..]), 106 | Ok(IpProtocol::UDP) => parse_udp(&arr[IPv6::size()..]), 107 | Ok(IpProtocol::IPV6) => parse_ipv6(&arr[IPv6::size()..]), 108 | Ok(IpProtocol::GRE) => parse_gre(&arr[IPv6::size()..]), 109 | _ => accept(&arr[IPv6::size()..]), 110 | }; 111 | pkt.insert(ipv6); 112 | pkt 113 | } 114 | pub fn parse_gre<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 115 | let gre = GRESlice::from(&arr[0..GRE::size()]); 116 | let proto = EtherType::try_from(gre.proto() as u16); 117 | let chksum_present = gre.chksum_present(); 118 | let seqnum_present = gre.seqnum_present(); 119 | let key_present = gre.key_present(); 120 | let mut offset = 0; 121 | offset += GRE::size(); 122 | let gco = if chksum_present == 1 { 123 | let p = Some(GREChksumOffsetSlice::from( 124 | &arr[offset..offset + GREChksumOffset::size()], 125 | )); 126 | offset += GREChksumOffset::size(); 127 | p 128 | } else { 129 | None 130 | }; 131 | let gk = if key_present == 1 { 132 | let p = Some(GREKeySlice::from(&arr[offset..offset + GREKey::size()])); 133 | offset += GREKey::size(); 134 | p 135 | } else { 136 | None 137 | }; 138 | let gsn = if seqnum_present == 1 { 139 | let p = Some(GRESequenceNumSlice::from( 140 | &arr[offset..offset + GRESequenceNum::size()], 141 | )); 142 | offset += GRESequenceNum::size(); 143 | p 144 | } else { 145 | None 146 | }; 147 | let mut pkt = match proto { 148 | Ok(EtherType::IPV4) => parse_ipv4(&arr[offset..]), 149 | Ok(EtherType::IPV6) => parse_ipv6(&arr[offset..]), 150 | Ok(EtherType::ERSPANII) => parse_erspan2(&arr[offset..]), 151 | Ok(EtherType::ERSPANIII) => parse_erspan3(&arr[offset..]), 152 | _ => accept(&arr[offset..]), 153 | }; 154 | if let Some(p) = gco { 155 | pkt.insert(p); 156 | } 157 | if let Some(p) = gk { 158 | pkt.insert(p); 159 | } 160 | if let Some(p) = gsn { 161 | pkt.insert(p); 162 | } 163 | pkt.insert(gre); 164 | pkt 165 | } 166 | pub fn parse_erspan2<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 167 | let erspan2 = ERSPAN2Slice::from(&arr[0..ERSPAN2::size()]); 168 | let mut pkt = parse_ethernet(&arr[ERSPAN2::size()..]); 169 | pkt.insert(erspan2); 170 | pkt 171 | } 172 | pub fn parse_erspan3<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 173 | let erspan3 = ERSPAN3Slice::from(&arr[0..ERSPAN3::size()]); 174 | let o = erspan3.o(); 175 | let mut offset = 0; 176 | offset += ERSPAN3::size(); 177 | let platform = if o == 1 { 178 | let p = Some(ERSPANPLATFORMSlice::from( 179 | &arr[offset..offset + ERSPANPLATFORM::size()], 180 | )); 181 | offset += ERSPANPLATFORM::size(); 182 | p 183 | } else { 184 | None 185 | }; 186 | let mut pkt = parse_ethernet(&arr[offset..]); 187 | if let Some(p) = platform { 188 | pkt.insert(p); 189 | } 190 | pkt.insert(erspan3); 191 | pkt 192 | } 193 | pub fn parse_arp<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 194 | let mut pkt = accept(&arr[ARP::size()..]); 195 | pkt.insert(ARPSlice::from(&arr[0..ARP::size()])); 196 | pkt 197 | } 198 | pub fn parse_icmp<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 199 | let mut pkt = accept(&arr[ICMP::size()..]); 200 | pkt.insert(ICMPSlice::from(&arr[0..ICMP::size()])); 201 | pkt 202 | } 203 | pub fn parse_tcp<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 204 | let mut pkt = accept(&arr[TCP::size()..]); 205 | pkt.insert(TCPSlice::from(&arr[0..TCP::size()])); 206 | pkt 207 | } 208 | pub fn parse_udp<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 209 | let udp = UDPSlice::from(&arr[0..UDP::size()]); 210 | let dst = udp.dst() as u16; 211 | let mut pkt = match dst { 212 | UDP_PORT_VXLAN => parse_vxlan(&arr[UDP::size()..]), 213 | _ => accept(&arr[UDP::size()..]), 214 | }; 215 | pkt.insert(udp); 216 | pkt 217 | } 218 | pub fn parse_vxlan<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 219 | let mut pkt = parse_ethernet(&arr[Vxlan::size()..]); 220 | pkt.insert(VxlanSlice::from(&arr[0..Vxlan::size()])); 221 | pkt 222 | } 223 | fn accept<'a>(arr: &'a [u8]) -> PacketSlice<'a> { 224 | let mut pkt = PacketSlice::new(); 225 | pkt.set_payload(arr); 226 | pkt 227 | } 228 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | //! # Helper utilities to generate packets 2 | 3 | use crate::headers::*; 4 | use crate::types::*; 5 | use crate::Packet; 6 | 7 | pub fn create_eth_packet( 8 | eth_dst: &str, 9 | eth_src: &str, 10 | vlan_enable: bool, 11 | vlan_vid: u16, 12 | vlan_pcp: u8, 13 | etype: u16, 14 | payload: &[u8], 15 | ) -> Packet { 16 | let mut pkt = Packet::new(); 17 | if vlan_enable { 18 | pkt.push(Packet::ethernet(eth_dst, eth_src, EtherType::DOT1Q as u16)); 19 | pkt.push(Packet::vlan(vlan_pcp, 0, vlan_vid, etype)); 20 | } else { 21 | pkt.push(Packet::ethernet(eth_dst, eth_src, etype)); 22 | } 23 | pkt.set_payload(payload); 24 | pkt 25 | } 26 | 27 | pub fn create_arp_packet( 28 | eth_dst: &str, 29 | eth_src: &str, 30 | vlan_enable: bool, 31 | vlan_vid: u16, 32 | vlan_pcp: u8, 33 | opcode: u16, 34 | sender_mac: &str, 35 | target_mac: &str, 36 | sender_ip: &str, 37 | target_ip: &str, 38 | payload: &[u8], 39 | ) -> Packet { 40 | let mut pkt = create_eth_packet( 41 | eth_dst, 42 | eth_src, 43 | vlan_enable, 44 | vlan_vid, 45 | vlan_pcp, 46 | EtherType::ARP as u16, 47 | payload, 48 | ); 49 | pkt.push(Packet::arp( 50 | opcode, sender_mac, target_mac, sender_ip, target_ip, 51 | )); 52 | pkt 53 | } 54 | 55 | pub fn create_ipv4_packet( 56 | eth_dst: &str, 57 | eth_src: &str, 58 | vlan_enable: bool, 59 | vlan_vid: u16, 60 | vlan_pcp: u8, 61 | ip_ihl: u8, 62 | ip_src: &str, 63 | ip_dst: &str, 64 | ip_proto: u8, 65 | ip_tos: u8, 66 | ip_ttl: u8, 67 | ip_id: u16, 68 | ip_frag: u16, 69 | _ip_options: Vec, 70 | payload: &[u8], 71 | ) -> Packet { 72 | let mut pkt = create_eth_packet( 73 | eth_dst, 74 | eth_src, 75 | vlan_enable, 76 | vlan_vid, 77 | vlan_pcp, 78 | EtherType::IPV4 as u16, 79 | payload, 80 | ); 81 | let pktlen = IPv4::size() + payload.len(); 82 | let ipv4 = Packet::ipv4( 83 | ip_ihl, 84 | ip_tos, 85 | ip_id, 86 | ip_ttl, 87 | ip_frag, 88 | ip_proto, 89 | ip_src, 90 | ip_dst, 91 | pktlen as u16, 92 | ); 93 | pkt.push(ipv4); 94 | pkt 95 | } 96 | 97 | pub fn create_ipv6_packet( 98 | eth_dst: &str, 99 | eth_src: &str, 100 | vlan_enable: bool, 101 | vlan_vid: u16, 102 | vlan_pcp: u8, 103 | ip_traffic_class: u8, 104 | ip_flow_label: u32, 105 | ip_next_hdr: u8, 106 | ip_hop_limit: u8, 107 | ip_src: &str, 108 | ip_dst: &str, 109 | payload: &[u8], 110 | ) -> Packet { 111 | let mut pkt = create_eth_packet( 112 | eth_dst, 113 | eth_src, 114 | vlan_enable, 115 | vlan_vid, 116 | vlan_pcp, 117 | EtherType::IPV6 as u16, 118 | payload, 119 | ); 120 | let ipv6 = Packet::ipv6( 121 | ip_traffic_class, 122 | ip_flow_label, 123 | ip_next_hdr, 124 | ip_hop_limit, 125 | ip_src, 126 | ip_dst, 127 | payload.len() as u16, 128 | ); 129 | pkt.push(ipv6); 130 | pkt 131 | } 132 | 133 | pub fn create_tcp_packet( 134 | eth_dst: &str, 135 | eth_src: &str, 136 | vlan_enable: bool, 137 | vlan_vid: u16, 138 | vlan_pcp: u8, 139 | ip_ihl: u8, 140 | ip_src: &str, 141 | ip_dst: &str, 142 | ip_tos: u8, 143 | ip_ttl: u8, 144 | ip_id: u16, 145 | ip_frag: u16, 146 | ip_options: Vec, 147 | tcp_dst: u16, 148 | tcp_src: u16, 149 | tcp_seq_no: u32, 150 | tcp_ack_no: u32, 151 | tcp_data_offset: u8, 152 | tcp_res: u8, 153 | tcp_flags: u8, 154 | tcp_window: u16, 155 | tcp_urgent_ptr: u16, 156 | _tcp_checksum: bool, 157 | payload: &[u8], 158 | ) -> Packet { 159 | let mut pkt = create_ipv4_packet( 160 | eth_dst, 161 | eth_src, 162 | vlan_enable, 163 | vlan_vid, 164 | vlan_pcp, 165 | ip_ihl, 166 | ip_src, 167 | ip_dst, 168 | IpProtocol::TCP as u8, 169 | ip_tos, 170 | ip_ttl, 171 | ip_id, 172 | ip_frag, 173 | ip_options, 174 | payload, 175 | ); 176 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 177 | ipv4.set_total_len(ipv4.total_len() + TCP::size() as u64); 178 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 179 | ipv4.set_header_checksum(chksum as u64); 180 | 181 | let tcp = Packet::tcp( 182 | tcp_src, 183 | tcp_dst, 184 | tcp_seq_no, 185 | tcp_ack_no, 186 | tcp_data_offset, 187 | tcp_res, 188 | tcp_flags, 189 | tcp_window, 190 | 0, 191 | tcp_urgent_ptr, 192 | ); 193 | pkt.push(tcp); 194 | pkt 195 | } 196 | 197 | pub fn create_udp_packet( 198 | eth_dst: &str, 199 | eth_src: &str, 200 | vlan_enable: bool, 201 | vlan_vid: u16, 202 | vlan_pcp: u8, 203 | ip_ihl: u8, 204 | ip_src: &str, 205 | ip_dst: &str, 206 | ip_tos: u8, 207 | ip_ttl: u8, 208 | ip_id: u16, 209 | ip_frag: u16, 210 | ip_options: Vec, 211 | udp_dst: u16, 212 | udp_src: u16, 213 | _udp_checksum: bool, 214 | payload: &[u8], 215 | ) -> Packet { 216 | let mut pkt = create_ipv4_packet( 217 | eth_dst, 218 | eth_src, 219 | vlan_enable, 220 | vlan_vid, 221 | vlan_pcp, 222 | ip_ihl, 223 | ip_src, 224 | ip_dst, 225 | IpProtocol::UDP as u8, 226 | ip_tos, 227 | ip_ttl, 228 | ip_id, 229 | ip_frag, 230 | ip_options, 231 | payload, 232 | ); 233 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 234 | ipv4.set_total_len(ipv4.total_len() + UDP::size() as u64); 235 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 236 | ipv4.set_header_checksum(chksum as u64); 237 | 238 | let l4_len = UDP::size() + payload.len(); 239 | let udp = Packet::udp(udp_src, udp_dst, l4_len as u16); 240 | pkt.push(udp); 241 | pkt 242 | } 243 | 244 | pub fn create_icmp_packet( 245 | eth_dst: &str, 246 | eth_src: &str, 247 | vlan_enable: bool, 248 | vlan_vid: u16, 249 | vlan_pcp: u8, 250 | ip_ihl: u8, 251 | ip_src: &str, 252 | ip_dst: &str, 253 | ip_tos: u8, 254 | ip_ttl: u8, 255 | ip_id: u16, 256 | ip_frag: u16, 257 | ip_options: Vec, 258 | icmp_type: u8, 259 | icmp_code: u8, 260 | _icmp_data: Vec, 261 | _udp_checksum: bool, 262 | payload: &[u8], 263 | ) -> Packet { 264 | let mut pkt = create_ipv4_packet( 265 | eth_dst, 266 | eth_src, 267 | vlan_enable, 268 | vlan_vid, 269 | vlan_pcp, 270 | ip_ihl, 271 | ip_src, 272 | ip_dst, 273 | IpProtocol::ICMP as u8, 274 | ip_tos, 275 | ip_ttl, 276 | ip_id, 277 | ip_frag, 278 | ip_options, 279 | payload, 280 | ); 281 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 282 | ipv4.set_total_len(ipv4.total_len() + ICMP::size() as u64); 283 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 284 | ipv4.set_header_checksum(chksum as u64); 285 | 286 | let icmp = Packet::icmp(icmp_type, icmp_code); 287 | pkt.push(icmp); 288 | pkt 289 | } 290 | 291 | pub fn create_ipv4ip_packet( 292 | eth_dst: &str, 293 | eth_src: &str, 294 | vlan_enable: bool, 295 | vlan_vid: u16, 296 | vlan_pcp: u8, 297 | ip_ihl: u8, 298 | ip_src: &str, 299 | ip_dst: &str, 300 | ip_tos: u8, 301 | ip_ttl: u8, 302 | ip_id: u16, 303 | ip_frag: u16, 304 | ip_options: Vec, 305 | inner_pkt: Packet, 306 | ) -> Packet { 307 | let ipkt_vec = inner_pkt.to_vec(); 308 | 309 | let ip_proto = match IpType::try_from(ipkt_vec[0] >> 4 & 0xf as u8) { 310 | Ok(IpType::V4) => IpProtocol::IPIP, 311 | Ok(IpType::V6) => IpProtocol::IPV6, 312 | _ => IpProtocol::IPIP, 313 | }; 314 | let pkt = create_ipv4_packet( 315 | eth_dst, 316 | eth_src, 317 | vlan_enable, 318 | vlan_vid, 319 | vlan_pcp, 320 | ip_ihl, 321 | ip_src, 322 | ip_dst, 323 | ip_proto as u8, 324 | ip_tos, 325 | ip_ttl, 326 | ip_id, 327 | ip_frag, 328 | ip_options, 329 | ipkt_vec.as_slice(), 330 | ); 331 | pkt 332 | } 333 | 334 | pub fn create_ipv6ip_packet( 335 | eth_dst: &str, 336 | eth_src: &str, 337 | vlan_enable: bool, 338 | vlan_vid: u16, 339 | vlan_pcp: u8, 340 | ip_traffic_class: u8, 341 | ip_flow_label: u32, 342 | ip_hop_limit: u8, 343 | ip_src: &str, 344 | ip_dst: &str, 345 | inner_pkt: Packet, 346 | ) -> Packet { 347 | let ipkt_vec = inner_pkt.to_vec(); 348 | 349 | let ip_nxt_hdr = match IpType::try_from(ipkt_vec[0] >> 4 & 0xf as u8) { 350 | Ok(IpType::V4) => IpProtocol::IPIP, 351 | Ok(IpType::V6) => IpProtocol::IPV6, 352 | _ => IpProtocol::IPIP, 353 | }; 354 | let pkt = create_ipv6_packet( 355 | eth_dst, 356 | eth_src, 357 | vlan_enable, 358 | vlan_vid, 359 | vlan_pcp, 360 | ip_traffic_class, 361 | ip_flow_label, 362 | ip_nxt_hdr as u8, 363 | ip_hop_limit, 364 | ip_src, 365 | ip_dst, 366 | ipkt_vec.as_slice(), 367 | ); 368 | pkt 369 | } 370 | 371 | pub fn create_tcpv6_packet( 372 | eth_dst: &str, 373 | eth_src: &str, 374 | vlan_enable: bool, 375 | vlan_vid: u16, 376 | vlan_pcp: u8, 377 | ip_traffic_class: u8, 378 | ip_flow_label: u32, 379 | ip_hop_limit: u8, 380 | ip_src: &str, 381 | ip_dst: &str, 382 | tcp_dst: u16, 383 | tcp_src: u16, 384 | tcp_seq_no: u32, 385 | tcp_ack_no: u32, 386 | tcp_data_offset: u8, 387 | tcp_res: u8, 388 | tcp_flags: u8, 389 | tcp_window: u16, 390 | tcp_urgent_ptr: u16, 391 | payload: &[u8], 392 | ) -> Packet { 393 | let mut pkt = create_ipv6_packet( 394 | eth_dst, 395 | eth_src, 396 | vlan_enable, 397 | vlan_vid, 398 | vlan_pcp, 399 | ip_traffic_class, 400 | ip_flow_label, 401 | IpProtocol::TCP as u8, 402 | ip_hop_limit, 403 | ip_src, 404 | ip_dst, 405 | payload, 406 | ); 407 | let ipv6: &mut IPv6 = (&mut pkt["IPv6"]).into(); 408 | ipv6.set_payload_len(ipv6.payload_len() + TCP::size() as u64); 409 | 410 | let tcp = Packet::tcp( 411 | tcp_src, 412 | tcp_dst, 413 | tcp_seq_no, 414 | tcp_ack_no, 415 | tcp_data_offset, 416 | tcp_res, 417 | tcp_flags, 418 | tcp_window, 419 | 0, 420 | tcp_urgent_ptr, 421 | ); 422 | pkt.push(tcp); 423 | pkt 424 | } 425 | 426 | pub fn create_udpv6_packet( 427 | eth_dst: &str, 428 | eth_src: &str, 429 | vlan_enable: bool, 430 | vlan_vid: u16, 431 | vlan_pcp: u8, 432 | ip_traffic_class: u8, 433 | ip_flow_label: u32, 434 | ip_hop_limit: u8, 435 | ip_src: &str, 436 | ip_dst: &str, 437 | udp_dst: u16, 438 | udp_src: u16, 439 | _udp_checksum: bool, 440 | payload: &[u8], 441 | ) -> Packet { 442 | let mut pkt = create_ipv6_packet( 443 | eth_dst, 444 | eth_src, 445 | vlan_enable, 446 | vlan_vid, 447 | vlan_pcp, 448 | ip_traffic_class, 449 | ip_flow_label, 450 | IpProtocol::UDP as u8, 451 | ip_hop_limit, 452 | ip_src, 453 | ip_dst, 454 | payload, 455 | ); 456 | let ipv6: &mut IPv6 = (&mut pkt["IPv6"]).into(); 457 | ipv6.set_payload_len(ipv6.payload_len() + UDP::size() as u64); 458 | 459 | let l4_len = UDP::size() + payload.len(); 460 | let mut udp = Packet::udp(udp_src, udp_dst, l4_len as u16); 461 | udp.set_checksum(0xffff); 462 | pkt.push(udp); 463 | pkt 464 | } 465 | 466 | pub fn create_icmpv6_packet( 467 | eth_dst: &str, 468 | eth_src: &str, 469 | vlan_enable: bool, 470 | vlan_vid: u16, 471 | vlan_pcp: u8, 472 | ip_traffic_class: u8, 473 | ip_flow_label: u32, 474 | ip_hop_limit: u8, 475 | ip_src: &str, 476 | ip_dst: &str, 477 | icmp_type: u8, 478 | icmp_code: u8, 479 | _icmp_data: Vec, 480 | _udp_checksum: bool, 481 | payload: &[u8], 482 | ) -> Packet { 483 | let mut pkt = create_ipv6_packet( 484 | eth_dst, 485 | eth_src, 486 | vlan_enable, 487 | vlan_vid, 488 | vlan_pcp, 489 | ip_traffic_class, 490 | ip_flow_label, 491 | IpProtocol::ICMPV6 as u8, 492 | ip_hop_limit, 493 | ip_src, 494 | ip_dst, 495 | payload, 496 | ); 497 | let ipv6: &mut IPv6 = (&mut pkt["IPv6"]).into(); 498 | ipv6.set_payload_len(ipv6.payload_len() + ICMP::size() as u64); 499 | let icmp = Packet::icmp(icmp_type, icmp_code); 500 | pkt.push(icmp); 501 | pkt 502 | } 503 | 504 | pub fn create_vxlan_packet( 505 | eth_dst: &str, 506 | eth_src: &str, 507 | vlan_enable: bool, 508 | vlan_vid: u16, 509 | vlan_pcp: u8, 510 | ip_ihl: u8, 511 | ip_src: &str, 512 | ip_dst: &str, 513 | ip_tos: u8, 514 | ip_ttl: u8, 515 | ip_id: u16, 516 | ip_frag: u16, 517 | ip_options: Vec, 518 | udp_dst: u16, 519 | udp_src: u16, 520 | _udp_checksum: bool, 521 | vxlan_vni: u32, 522 | inner_pkt: Packet, 523 | ) -> Packet { 524 | let ipkt_vec = inner_pkt.to_vec(); 525 | let mut pkt = create_ipv4_packet( 526 | eth_dst, 527 | eth_src, 528 | vlan_enable, 529 | vlan_vid, 530 | vlan_pcp, 531 | ip_ihl, 532 | ip_src, 533 | ip_dst, 534 | IpProtocol::UDP as u8, 535 | ip_tos, 536 | ip_ttl, 537 | ip_id, 538 | ip_frag, 539 | ip_options, 540 | ipkt_vec.as_slice(), 541 | ); 542 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 543 | ipv4.set_total_len(ipv4.total_len() + (UDP::size() + Vxlan::size()) as u64); 544 | 545 | let l4_len = UDP::size() + Vxlan::size() + ipkt_vec.len(); 546 | let udp = Packet::udp(udp_src, udp_dst, l4_len as u16); 547 | pkt.push(udp); 548 | pkt.push(Packet::vxlan(vxlan_vni)); 549 | pkt 550 | } 551 | 552 | pub fn create_vxlanv6_packet( 553 | eth_dst: &str, 554 | eth_src: &str, 555 | vlan_enable: bool, 556 | vlan_vid: u16, 557 | vlan_pcp: u8, 558 | ip_traffic_class: u8, 559 | ip_flow_label: u32, 560 | ip_hop_limit: u8, 561 | ip_src: &str, 562 | ip_dst: &str, 563 | udp_dst: u16, 564 | udp_src: u16, 565 | _udp_checksum: bool, 566 | vxlan_vni: u32, 567 | inner_pkt: Packet, 568 | ) -> Packet { 569 | let ipkt_vec = inner_pkt.to_vec(); 570 | let mut pkt = create_ipv6_packet( 571 | eth_dst, 572 | eth_src, 573 | vlan_enable, 574 | vlan_vid, 575 | vlan_pcp, 576 | ip_traffic_class, 577 | ip_flow_label, 578 | IpProtocol::UDP as u8, 579 | ip_hop_limit, 580 | ip_src, 581 | ip_dst, 582 | ipkt_vec.as_slice(), 583 | ); 584 | let ipv6: &mut IPv6 = (&mut pkt["IPv6"]).into(); 585 | ipv6.set_payload_len(ipv6.payload_len() + (UDP::size() + Vxlan::size()) as u64); 586 | 587 | let l4_len = UDP::size() + Vxlan::size() + ipkt_vec.len(); 588 | let mut udp = Packet::udp(udp_src, udp_dst, l4_len as u16); 589 | udp.set_checksum(0xffff); 590 | pkt.push(udp); 591 | 592 | pkt.push(Packet::vxlan(vxlan_vni)); 593 | 594 | pkt = pkt + inner_pkt; 595 | pkt 596 | } 597 | 598 | pub fn create_gre_packet( 599 | eth_dst: &str, 600 | eth_src: &str, 601 | vlan_enable: bool, 602 | vlan_vid: u16, 603 | vlan_pcp: u8, 604 | ip_ihl: u8, 605 | ip_src: &str, 606 | ip_dst: &str, 607 | ip_tos: u8, 608 | ip_ttl: u8, 609 | ip_id: u16, 610 | ip_frag: u16, 611 | ip_options: Vec, 612 | gre_chksum_present: bool, 613 | gre_routing_present: bool, 614 | gre_key_present: bool, 615 | gre_seqnum_present: bool, 616 | gre_strict_route_src: bool, 617 | gre_flags: u8, 618 | gre_version: u8, 619 | gre_chksum: u16, 620 | gre_offset: u16, 621 | gre_key: u32, 622 | gre_seqnum: u32, 623 | gre_routing: &[u8], 624 | inner_pkt: Option, 625 | ) -> Packet { 626 | let (proto, ipkt_vec) = match inner_pkt { 627 | Some(ref p) => { 628 | let ipkt_vec = p.to_vec(); 629 | match ipkt_vec[0] >> 4 & 0xf { 630 | 4 => (EtherType::IPV4 as u16, ipkt_vec), 631 | 6 => (EtherType::IPV6 as u16, ipkt_vec), 632 | _ => (0, ipkt_vec), 633 | } 634 | } 635 | None => (0, Vec::new()), 636 | }; 637 | let mut pktlen = GRE::size(); 638 | if gre_chksum_present { 639 | pktlen += GREChksumOffset::size(); 640 | } 641 | if gre_key_present { 642 | pktlen += GREKey::size(); 643 | } 644 | if gre_seqnum_present { 645 | pktlen += GRESequenceNum::size(); 646 | } 647 | if gre_routing_present { 648 | pktlen += gre_routing.len(); 649 | } 650 | 651 | let mut pkt = create_ipv4_packet( 652 | eth_dst, 653 | eth_src, 654 | vlan_enable, 655 | vlan_vid, 656 | vlan_pcp, 657 | ip_ihl, 658 | ip_src, 659 | ip_dst, 660 | IpProtocol::GRE as u8, 661 | ip_tos, 662 | ip_ttl, 663 | ip_id, 664 | ip_frag, 665 | ip_options, 666 | ipkt_vec.as_slice(), 667 | ); 668 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 669 | ipv4.set_total_len(ipv4.total_len() + pktlen as u64); 670 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 671 | ipv4.set_header_checksum(chksum as u64); 672 | 673 | let gre = Packet::gre( 674 | gre_chksum_present, 675 | gre_routing_present, 676 | gre_key_present, 677 | gre_seqnum_present, 678 | gre_strict_route_src, 679 | gre_flags, 680 | gre_version, 681 | proto, 682 | ); 683 | pkt.push(gre); 684 | 685 | if gre_chksum_present { 686 | pkt.push(Packet::gre_chksum_offset(gre_chksum, gre_offset)); 687 | } 688 | if gre_key_present { 689 | pkt.push(Packet::gre_key(gre_key)); 690 | } 691 | if gre_seqnum_present { 692 | pkt.push(Packet::gre_sequence_number(gre_seqnum)); 693 | } 694 | pkt 695 | } 696 | 697 | pub fn create_erspan_2_packet( 698 | eth_dst: &str, 699 | eth_src: &str, 700 | vlan_enable: bool, 701 | vlan_vid: u16, 702 | vlan_pcp: u8, 703 | ip_ihl: u8, 704 | ip_src: &str, 705 | ip_dst: &str, 706 | ip_tos: u8, 707 | ip_ttl: u8, 708 | ip_id: u16, 709 | ip_frag: u16, 710 | ip_options: Vec, 711 | gre_seqnum: u32, 712 | erspan_vlan: u16, 713 | erpsan_cos: u8, 714 | erspan_en: u8, 715 | erspan_t: u8, 716 | erspan_session_id: u16, 717 | erspan_index: u32, 718 | inner_pkt: Option, 719 | ) -> Packet { 720 | let ipkt_vec = match inner_pkt { 721 | Some(ref p) => p.to_vec(), 722 | None => Vec::new(), 723 | }; 724 | let mut pktlen = GRE::size() + ERSPAN2::size(); 725 | 726 | if gre_seqnum != 0 { 727 | pktlen += GRESequenceNum::size(); 728 | } 729 | pktlen += match inner_pkt { 730 | Some(ref p) => p.len(), 731 | None => 0, 732 | }; 733 | 734 | let mut pkt = create_ipv4_packet( 735 | eth_dst, 736 | eth_src, 737 | vlan_enable, 738 | vlan_vid, 739 | vlan_pcp, 740 | ip_ihl, 741 | ip_src, 742 | ip_dst, 743 | IpProtocol::GRE as u8, 744 | ip_tos, 745 | ip_ttl, 746 | ip_id, 747 | ip_frag, 748 | ip_options, 749 | ipkt_vec.as_slice(), 750 | ); 751 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 752 | ipv4.set_total_len(ipv4.total_len() + pktlen as u64); 753 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 754 | ipv4.set_header_checksum(chksum as u64); 755 | 756 | let mut gre = GRE::new(); 757 | gre.set_proto(EtherType::ERSPANII as u64); 758 | if gre_seqnum != 0 { 759 | gre.set_seqnum_present(1 as u64); 760 | } 761 | pkt.push(gre); 762 | 763 | if gre_seqnum != 0 { 764 | pkt.push(Packet::gre_sequence_number(gre_seqnum)); 765 | } 766 | let erspan = Packet::erspan2( 767 | erspan_vlan, 768 | erpsan_cos, 769 | erspan_en, 770 | erspan_t, 771 | erspan_session_id, 772 | erspan_index, 773 | ); 774 | pkt.push(erspan); 775 | pkt 776 | } 777 | 778 | pub fn create_erspan_3_packet( 779 | eth_dst: &str, 780 | eth_src: &str, 781 | vlan_enable: bool, 782 | vlan_vid: u16, 783 | vlan_pcp: u8, 784 | ip_ihl: u8, 785 | ip_src: &str, 786 | ip_dst: &str, 787 | ip_tos: u8, 788 | ip_ttl: u8, 789 | ip_id: u16, 790 | ip_frag: u16, 791 | ip_options: Vec, 792 | gre_seqnum: u32, 793 | erspan_vlan: u16, 794 | erpsan_cos: u8, 795 | erspan_en: u8, 796 | erspan_t: u8, 797 | erspan_session_id: u16, 798 | erspan_timestamp: u32, 799 | erspan_sgt: u16, 800 | erspan_ft_d_other: u16, 801 | erspan_pltfm_id: u8, 802 | erspan_pltfm_info: u64, 803 | inner_pkt: Option, 804 | ) -> Packet { 805 | let ipkt_vec = match inner_pkt { 806 | Some(ref p) => p.to_vec(), 807 | None => Vec::new(), 808 | }; 809 | let mut pktlen = GRE::size() + ERSPAN3::size(); 810 | 811 | if gre_seqnum != 0 { 812 | pktlen += GRESequenceNum::size(); 813 | } 814 | if erspan_ft_d_other & 0x1 == 1 { 815 | pktlen += ERSPANPLATFORM::size(); 816 | } 817 | pktlen += match inner_pkt { 818 | Some(ref p) => p.len(), 819 | None => 0, 820 | }; 821 | 822 | let mut pkt = create_ipv4_packet( 823 | eth_dst, 824 | eth_src, 825 | vlan_enable, 826 | vlan_vid, 827 | vlan_pcp, 828 | ip_ihl, 829 | ip_src, 830 | ip_dst, 831 | IpProtocol::GRE as u8, 832 | ip_tos, 833 | ip_ttl, 834 | ip_id, 835 | ip_frag, 836 | ip_options, 837 | ipkt_vec.as_slice(), 838 | ); 839 | let ipv4: &mut IPv4 = (&mut pkt["IPv4"]).into(); 840 | ipv4.set_total_len(ipv4.total_len() + pktlen as u64); 841 | let chksum = Packet::ipv4_checksum(ipv4.to_vec().as_slice()); 842 | ipv4.set_header_checksum(chksum as u64); 843 | 844 | let mut gre = GRE::new(); 845 | gre.set_proto(EtherType::ERSPANIII as u64); 846 | gre.set_seqnum_present(gre_seqnum as u64); 847 | pkt.push(gre); 848 | 849 | if gre_seqnum != 0 { 850 | pkt.push(Packet::gre_sequence_number(gre_seqnum)); 851 | } 852 | let erspan = Packet::erspan3( 853 | erspan_vlan, 854 | erpsan_cos, 855 | erspan_en, 856 | erspan_t, 857 | erspan_session_id, 858 | erspan_timestamp, 859 | erspan_sgt, 860 | erspan_ft_d_other, 861 | ); 862 | pkt.push(erspan); 863 | 864 | if erspan_ft_d_other & 0x1 == 1 { 865 | let pltfm: u64 = (erspan_pltfm_id as u64) << 58 | erspan_pltfm_info; 866 | pkt.push(ERSPANPLATFORM::from(pltfm.to_be_bytes().to_vec())); 867 | } 868 | 869 | match inner_pkt { 870 | Some(p) => { 871 | pkt = pkt + p; 872 | } 873 | None => (), 874 | }; 875 | pkt 876 | } 877 | -------------------------------------------------------------------------------- /tests/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate packet_rs; 3 | 4 | use packet_rs::headers::*; 5 | use packet_rs::utils; 6 | 7 | use std::time::Instant; 8 | 9 | mod pcap; 10 | 11 | const UDP_PORT_VXLAN: u16 = 4789; 12 | 13 | pub fn ipv4_checksum_verify(v: &[u8]) -> u16 { 14 | let mut chksum: u32 = 0; 15 | for i in (0..v.len()).step_by(2) { 16 | let msb: u16 = (v[i] as u16) << 8; 17 | chksum += msb as u32 | v[i + 1] as u32; 18 | } 19 | while chksum >> 16 != 0 { 20 | chksum = (chksum >> 16) + chksum & 0xFFFF; 21 | } 22 | let out = !(chksum as u16); 23 | out 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | 29 | use super::*; 30 | use packet_rs::parser; 31 | use packet_rs::Packet; 32 | use pcap::pcap_write; 33 | 34 | #[test] 35 | fn custom_header_test() { 36 | make_header!( 37 | MyOwnHeader 10 38 | ( 39 | bytes_1: 0-7, 40 | bytes_2: 8-23, 41 | bytes_3: 32-47, 42 | bytes_4: 48-79 43 | ) 44 | ); 45 | let data: Vec = vec![0; 10]; 46 | let mut my_header = MyOwnHeader::from(data); 47 | my_header.to_vec().as_slice(); 48 | my_header.show(); 49 | 50 | my_header.set_bytes_1(0x22); 51 | assert_eq!(0x22, my_header.bytes_1()); 52 | 53 | my_header.set_bytes_2(0x3344); 54 | assert_eq!(0x3344, my_header.bytes_2()); 55 | my_header.show(); 56 | } 57 | #[test] 58 | fn ethernet_header_test() { 59 | let mut eth = Ether::new(); 60 | eth.show(); 61 | 62 | // dst 63 | assert_eq!(0x102030405, eth.dst()); 64 | eth.set_dst(0x60708090a0b as u64); 65 | assert_eq!(0x60708090a0b, eth.dst()); 66 | 67 | // src 68 | assert_eq!(0x60708090a0b, eth.src()); 69 | eth.set_src(0x102030405 as u64); 70 | assert_eq!(0x102030405, eth.src()); 71 | 72 | // etype 73 | assert_eq!(0x800, eth.etype()); 74 | eth.set_etype(0x8100 as u64); 75 | assert_eq!(0x8100, eth.etype()); 76 | 77 | let a = [ 78 | 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x86, 0xdd, 79 | ]; 80 | let eth = Ether::from(a.to_vec()); 81 | let t = eth.to_vec(); 82 | let b = t.as_slice(); 83 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 14); 84 | assert_eq!(0xaaaaaaaaaaaa, eth.dst()); 85 | assert_eq!(0xbbbbbbbbbbbb, eth.src()); 86 | assert_eq!(0x86dd, eth.etype()); 87 | } 88 | #[test] 89 | fn vlan_header_test() { 90 | let mut vlan = Vlan::new(); 91 | vlan.show(); 92 | 93 | // pcp 94 | assert_eq!(vlan.pcp(), 0x0); 95 | vlan.set_pcp(0x5 as u64); 96 | assert_eq!(vlan.pcp(), 0x5); 97 | 98 | // cfi 99 | assert_eq!(vlan.cfi(), 0x0); 100 | vlan.set_cfi(0x1 as u64); 101 | assert_eq!(vlan.cfi(), 0x1); 102 | 103 | // vid 104 | assert_eq!(vlan.vid(), 0xa); 105 | vlan.set_vid(0xb as u64); 106 | assert_eq!(vlan.vid(), 0xb); 107 | 108 | let a = [0x7f, 0xff, 0x08, 0x00]; 109 | let vlan = Vlan::from(a.to_vec()); 110 | let t = vlan.to_vec(); 111 | let b = t.as_slice(); 112 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 4); 113 | assert_eq!(vlan.vid(), 4095); 114 | assert_eq!(vlan.pcp(), 3); 115 | assert_eq!(vlan.cfi(), 1); 116 | } 117 | #[test] 118 | fn ip_header_test() { 119 | let ipv4 = IPv4::new(); 120 | ipv4.to_vec().as_slice(); 121 | ipv4.show(); 122 | 123 | let data = [ 124 | 0x45, 0x00, 0x00, 0x14, 0x00, 0x33, 0x40, 0xdd, 0x40, 0x06, 0xfa, 0xec, 0xa, 0xa, 0xa, 125 | 0x1, 0xb, 0xb, 0xb, 0x1, 126 | ]; 127 | let ipv4 = IPv4::from(data.to_vec()); 128 | ipv4.show(); 129 | 130 | let ipv4 = Packet::ipv4(5, 10, 4, 64, 0xdd, 6, "10.10.10.1", "11.11.11.1", 86); 131 | assert_eq!(ipv4_checksum_verify(ipv4.to_vec().as_slice()), 0); 132 | 133 | let data: Vec = vec![0; IPv6::size()]; 134 | let ipv6 = IPv6::from(data); 135 | ipv6.to_vec().as_slice(); 136 | ipv6.show(); 137 | } 138 | #[test] 139 | fn vxlan_header_test() { 140 | let vxlan = Vxlan::new(); 141 | vxlan.show(); 142 | assert_eq!(vxlan.flags(), 0x8); 143 | assert_eq!(vxlan.vni(), 2000); 144 | 145 | let vxlan1 = Packet::vxlan(2000); 146 | vxlan1.show(); 147 | assert_eq!(vxlan1.flags(), 0x8); 148 | assert_eq!(vxlan1.vni(), 2000); 149 | } 150 | #[test] 151 | fn ip_checksum_test() { 152 | let payload: Vec = (0..100).collect::>(); 153 | let ips = vec![ 154 | "10.10.10.1", 155 | "11.11.11.1", 156 | "12.12.12.1", 157 | "13.13.13.1", 158 | "14.14.14.1", 159 | "15.15.15.1", 160 | "16.16.16.1", 161 | "17.17.17.1", 162 | "18.18.18.1", 163 | "19.19.19.1", 164 | ]; 165 | for sip in &ips { 166 | for dip in &ips { 167 | for ttl in 1..255 { 168 | let pkt = utils::create_tcp_packet( 169 | "00:01:02:03:04:05", 170 | "00:06:07:08:09:0a", 171 | false, 172 | 10, 173 | 3, 174 | 5, 175 | sip, 176 | dip, 177 | 0, 178 | ttl, 179 | 115, 180 | 0, 181 | Vec::new(), 182 | 80, 183 | 9090, 184 | 100, 185 | 101, 186 | 0, 187 | 0, 188 | 1, 189 | 0, 190 | 0, 191 | false, 192 | &payload, 193 | ); 194 | let ip: &IPv4 = (&pkt["IPv4"]).into(); 195 | assert_eq!(ipv4_checksum_verify(ip.to_vec().as_slice()), 0); 196 | 197 | let ipv4 = Packet::ipv4(5, 0, 115, ttl, 0, 6, sip, dip, 140); 198 | assert_eq!(ipv4_checksum_verify(ipv4.to_vec().as_slice()), 0); 199 | 200 | assert_eq!(ip.header_checksum(), ipv4.header_checksum()); 201 | } 202 | } 203 | } 204 | } 205 | #[test] 206 | fn arp_header_test() { 207 | let arp = ARP::new(); 208 | arp.show(); 209 | assert_eq!(arp.hwtype(), 0x1); 210 | assert_eq!(arp.proto_type(), 0x800); 211 | assert_eq!(arp.hwlen(), 0x6); 212 | assert_eq!(arp.proto_len(), 0x4); 213 | assert_eq!(arp.opcode(), 1); 214 | assert_eq!(arp.sender_hw_addr(), 0x000102030405); 215 | assert_eq!(arp.sender_proto_addr(), 0xa000001); 216 | assert_eq!(arp.target_hw_addr(), 0x0000000000); 217 | assert_eq!(arp.target_proto_addr(), 0x0); 218 | } 219 | #[test] 220 | fn create_packet_test() { 221 | let payload: Vec = (0..100).collect::>(); 222 | let _tcp = utils::create_tcp_packet( 223 | "00:01:02:03:04:05", 224 | "00:06:07:08:09:0a", 225 | false, 226 | 10, 227 | 3, 228 | 5, 229 | "10.10.10.1", 230 | "11.11.11.1", 231 | 0, 232 | 64, 233 | 115, 234 | 0, 235 | Vec::new(), 236 | 1234, 237 | 9090, 238 | 100, 239 | 101, 240 | 5, 241 | 0, 242 | 0x10, 243 | 2, 244 | 0, 245 | false, 246 | &payload, 247 | ); 248 | 249 | let _udp = utils::create_udp_packet( 250 | "00:01:02:03:04:05", 251 | "00:06:07:08:09:0a", 252 | false, 253 | 10, 254 | 3, 255 | 5, 256 | "192.168.0.199", 257 | "192.168.0.1", 258 | 0, 259 | 64, 260 | 0, 261 | 0x4000, 262 | Vec::new(), 263 | 1234, 264 | 9090, 265 | false, 266 | &payload, 267 | ); 268 | 269 | let _icmp = utils::create_icmp_packet( 270 | "00:01:02:03:04:05", 271 | "00:06:07:08:09:0a", 272 | false, 273 | 10, 274 | 3, 275 | 5, 276 | "192.168.0.199", 277 | "192.168.0.1", 278 | 0, 279 | 64, 280 | 0, 281 | 0x4000, 282 | Vec::new(), 283 | 8, 284 | 0, 285 | Vec::new(), 286 | false, 287 | &payload, 288 | ); 289 | 290 | let _tcpv6 = utils::create_tcpv6_packet( 291 | "00:01:02:03:04:05", 292 | "00:06:07:08:09:0a", 293 | false, 294 | 10, 295 | 3, 296 | 5, 297 | 4, 298 | 64, 299 | "AAAA::1", 300 | "BBBB::1", 301 | 1234, 302 | 9090, 303 | 100, 304 | 101, 305 | 5, 306 | 0, 307 | 1, 308 | 0, 309 | 0, 310 | &payload, 311 | ); 312 | 313 | let _udpv6 = utils::create_udpv6_packet( 314 | "00:01:02:03:04:05", 315 | "00:06:07:08:09:0a", 316 | false, 317 | 10, 318 | 3, 319 | 5, 320 | 4, 321 | 64, 322 | "AAAA::1", 323 | "BBBB::1", 324 | 1234, 325 | 9090, 326 | false, 327 | &payload, 328 | ); 329 | 330 | let _icmpv6 = utils::create_icmpv6_packet( 331 | "00:01:02:03:04:05", 332 | "00:06:07:08:09:0a", 333 | false, 334 | 10, 335 | 3, 336 | 5, 337 | 4, 338 | 64, 339 | "AAAA::1", 340 | "BBBB::1", 341 | 135, 342 | 0, 343 | Vec::new(), 344 | false, 345 | &payload, 346 | ); 347 | 348 | let _vxlan_udp = utils::create_vxlan_packet( 349 | "00:01:02:03:04:05", 350 | "00:06:07:08:09:0a", 351 | false, 352 | 10, 353 | 3, 354 | 5, 355 | "192.168.0.199", 356 | "192.168.0.1", 357 | 0, 358 | 64, 359 | 0, 360 | 0x4000, 361 | Vec::new(), 362 | UDP_PORT_VXLAN, 363 | 9090, 364 | false, 365 | 2000, 366 | _udp.clone(), 367 | ); 368 | 369 | let _vxlan_tcp = utils::create_vxlan_packet( 370 | "00:01:02:03:04:05", 371 | "00:06:07:08:09:0a", 372 | false, 373 | 10, 374 | 3, 375 | 5, 376 | "192.168.0.199", 377 | "192.168.0.1", 378 | 0, 379 | 64, 380 | 0, 381 | 0x4000, 382 | Vec::new(), 383 | UDP_PORT_VXLAN, 384 | 9090, 385 | false, 386 | 2000, 387 | _tcp.clone(), 388 | ); 389 | 390 | let _vxlanv6_udp = utils::create_vxlanv6_packet( 391 | "00:01:02:03:04:05", 392 | "00:06:07:08:09:0a", 393 | false, 394 | 10, 395 | 3, 396 | 5, 397 | 4, 398 | 64, 399 | "AAAA::1", 400 | "BBBB::1", 401 | UDP_PORT_VXLAN, 402 | 9090, 403 | false, 404 | 2000, 405 | _udp.clone(), 406 | ); 407 | 408 | let _vxlanv6_tcp = utils::create_vxlanv6_packet( 409 | "00:01:02:03:04:05", 410 | "00:06:07:08:09:0a", 411 | false, 412 | 10, 413 | 3, 414 | 5, 415 | 4, 416 | 64, 417 | "AAAA::1", 418 | "BBBB::1", 419 | UDP_PORT_VXLAN, 420 | 9090, 421 | false, 422 | 2000, 423 | _tcp.clone(), 424 | ); 425 | 426 | let _arp_req = utils::create_arp_packet( 427 | "FF:FF:FF:FF:FF:FF", 428 | "00:06:07:08:09:0a", 429 | false, 430 | 10, 431 | 3, 432 | 1, 433 | "00:06:07:08:09:0a", 434 | "00:00:00:00:00:00", 435 | "10.10.10.1", 436 | "0.0.0.0", 437 | &payload, 438 | ); 439 | 440 | let _arp_resp = utils::create_arp_packet( 441 | "00:06:07:08:09:0a", 442 | "00:01:02:03:04:05", 443 | false, 444 | 10, 445 | 3, 446 | 2, 447 | "00:01:02:03:04:05", 448 | "00:06:07:08:09:0a", 449 | "10.10.10.2", 450 | "10.10.10.1", 451 | &payload, 452 | ); 453 | 454 | let mut ip_tcp = _tcp.clone(); 455 | ip_tcp.remove(0); 456 | let mut ip_udp = _udp.clone(); 457 | ip_udp.remove(0); 458 | let mut ip_tcpv6 = _tcpv6.clone(); 459 | ip_tcpv6.remove(0); 460 | let mut ip_udpv6 = _udpv6.clone(); 461 | ip_udpv6.remove(0); 462 | 463 | let _ip4ip4 = utils::create_ipv4ip_packet( 464 | "00:01:02:03:04:05", 465 | "00:06:07:08:09:0a", 466 | false, 467 | 10, 468 | 3, 469 | 5, 470 | "192.168.0.199", 471 | "192.168.0.1", 472 | 0, 473 | 64, 474 | 0, 475 | 0x4000, 476 | Vec::new(), 477 | ip_tcp.clone(), 478 | ); 479 | 480 | let _ip4ip6 = utils::create_ipv4ip_packet( 481 | "00:01:02:03:04:05", 482 | "00:06:07:08:09:0a", 483 | false, 484 | 10, 485 | 3, 486 | 5, 487 | "192.168.0.199", 488 | "192.168.0.1", 489 | 0, 490 | 64, 491 | 0, 492 | 0x4000, 493 | Vec::new(), 494 | ip_udpv6.clone(), 495 | ); 496 | 497 | let _ip6ip4 = utils::create_ipv6ip_packet( 498 | "00:01:02:03:04:05", 499 | "00:06:07:08:09:0a", 500 | false, 501 | 10, 502 | 3, 503 | 5, 504 | 4, 505 | 64, 506 | "AAAA::1", 507 | "BBBB::1", 508 | ip_udp.clone(), 509 | ); 510 | 511 | let _ip6ip6 = utils::create_ipv6ip_packet( 512 | "00:01:02:03:04:05", 513 | "00:06:07:08:09:0a", 514 | false, 515 | 10, 516 | 3, 517 | 5, 518 | 4, 519 | 64, 520 | "AAAA::1", 521 | "BBBB::1", 522 | ip_tcpv6.clone(), 523 | ); 524 | 525 | let _greip4 = utils::create_gre_packet( 526 | "00:01:02:03:04:05", 527 | "00:06:07:08:09:0a", 528 | false, 529 | 10, 530 | 3, 531 | 5, 532 | "192.168.0.199", 533 | "192.168.0.1", 534 | 0, 535 | 64, 536 | 0, 537 | 0x4000, 538 | Vec::new(), 539 | false, 540 | false, 541 | false, 542 | false, 543 | false, 544 | 0, 545 | 0, 546 | 0, 547 | 0, 548 | 0, 549 | 0, 550 | &[], 551 | Some(ip_tcp.clone()), 552 | ); 553 | 554 | let _greip6 = utils::create_gre_packet( 555 | "00:01:02:03:04:05", 556 | "00:06:07:08:09:0a", 557 | false, 558 | 10, 559 | 3, 560 | 5, 561 | "192.168.0.199", 562 | "192.168.0.1", 563 | 0, 564 | 64, 565 | 0, 566 | 0x4000, 567 | Vec::new(), 568 | false, 569 | false, 570 | false, 571 | false, 572 | false, 573 | 0, 574 | 0, 575 | 0, 576 | 0, 577 | 0, 578 | 0, 579 | &[], 580 | Some(ip_udpv6.clone()), 581 | ); 582 | 583 | let _erspan2 = utils::create_erspan_2_packet( 584 | "00:01:02:03:04:05", 585 | "00:06:07:08:09:0a", 586 | false, 587 | 10, 588 | 3, 589 | 5, 590 | "192.168.0.199", 591 | "192.168.0.1", 592 | 0, 593 | 64, 594 | 0, 595 | 0x4000, 596 | Vec::new(), 597 | 23, 598 | 0, 599 | 0, 600 | 1, 601 | 0, 602 | 10, 603 | 10, 604 | Some(_udpv6.clone()), 605 | ); 606 | 607 | let _erspan3 = utils::create_erspan_3_packet( 608 | "00:01:02:03:04:05", 609 | "00:06:07:08:09:0a", 610 | false, 611 | 10, 612 | 3, 613 | 5, 614 | "192.168.0.199", 615 | "192.168.0.1", 616 | 0, 617 | 64, 618 | 0, 619 | 0x4000, 620 | Vec::new(), 621 | 23, 622 | 0, 623 | 0, 624 | 1, 625 | 0, 626 | 10, 627 | 10, 628 | 10, 629 | 1, 630 | 4, 631 | 0xffffffff, 632 | Some(_icmp.clone()), 633 | ); 634 | 635 | let mut _llc = Packet::new(); 636 | _llc.push(Dot3::from(vec![ 637 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x0, 86, 638 | ])); 639 | _llc.push(LLC::from(vec![0x0, 0x04, 0x0])); 640 | 641 | let mut _snap = Packet::new(); 642 | _snap.push(Dot3::from(vec![ 643 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x0, 86, 644 | ])); 645 | _snap.push(LLC::from(vec![0xaa, 0xaa, 0x03])); 646 | _snap.push(SNAP::from(vec![0x0, 0x80, 0xc2, 0x8, 0x0])); 647 | 648 | let pkts: Vec<&Packet> = vec![ 649 | &_tcp, 650 | &_udp, 651 | &_icmp, 652 | &_tcpv6, 653 | &_udpv6, 654 | &_icmpv6, 655 | &_vxlan_udp, 656 | &_vxlanv6_udp, 657 | &_vxlan_tcp, 658 | &_vxlanv6_tcp, 659 | &_arp_req, 660 | &_arp_resp, 661 | &_ip4ip4, 662 | &_ip4ip6, 663 | &_ip6ip4, 664 | &_ip6ip6, 665 | &_llc, 666 | &_snap, 667 | &_greip4, 668 | &_greip6, 669 | &_erspan2, 670 | &_erspan3, 671 | ]; 672 | pcap_write(&pkts.iter().map(|x| x.to_vec() as Vec).collect()); 673 | 674 | for pkt in pkts { 675 | let parsed = parser::slow::parse(pkt.to_vec().as_slice()); 676 | // parsed.show(); 677 | // pkt.show(); 678 | assert!(parsed.compare(&pkt)); 679 | } 680 | } 681 | 682 | fn test_tcp_packet_with_payload(payload: &[u8]) -> Packet { 683 | utils::create_tcp_packet( 684 | "00:11:11:11:11:11", 685 | "00:06:07:08:09:0a", 686 | false, 687 | 10, 688 | 3, 689 | 5, 690 | "10.10.10.1", 691 | "11.11.11.1", 692 | 0, 693 | 64, 694 | 115, 695 | 0, 696 | Vec::new(), 697 | 8888, 698 | 9090, 699 | 100, 700 | 101, 701 | 5, 702 | 0, 703 | 2, 704 | 0, 705 | 0, 706 | false, 707 | payload, 708 | ) 709 | } 710 | 711 | fn test_tcp_packet() -> Packet { 712 | let payload: Vec = (0..100).collect::>(); 713 | test_tcp_packet_with_payload(&payload) 714 | } 715 | 716 | #[test] 717 | fn update_packet_test() { 718 | let mut pkt = test_tcp_packet(); 719 | pkt.show(); 720 | let x: &mut Box = &mut pkt["Ether"]; 721 | let x: &mut Ether = x.into(); 722 | x.set_etype(0x86dd); 723 | x.show(); 724 | 725 | let new_pkt = pkt.clone(); 726 | new_pkt.show(); 727 | pkt.show(); 728 | assert_eq!(true, pkt.compare(&new_pkt)); 729 | assert_eq!(true, pkt.compare_with_slice(new_pkt.to_vec().as_slice())); 730 | 731 | // immutable 732 | let x: &Ether = pkt.get_header("Ether").unwrap(); 733 | println!("{}", x.etype()); 734 | x.show(); 735 | 736 | let y: &Box = &pkt["Ether"]; 737 | let x: &Ether = y.into(); 738 | println!("{}", x.etype()); 739 | x.show(); 740 | 741 | let x: &Ether = (&pkt["Ether"]).into(); 742 | println!("{}", x.etype()); 743 | x.show(); 744 | 745 | // mutable 746 | let x: &mut Ether = pkt.get_header_mut("Ether").unwrap(); 747 | x.set_etype(0x9999); 748 | x.show(); 749 | 750 | let x: &mut Box = &mut pkt["Ether"]; 751 | let x: &mut Ether = x.into(); 752 | x.set_etype(0x9999); 753 | x.show(); 754 | } 755 | #[test] 756 | fn pktgen_perf_test() { 757 | let cnt = 300000; 758 | let mut pkt = test_tcp_packet(); 759 | 760 | // new packet in every iteration 761 | let start = Instant::now(); 762 | for _ in 0..cnt { 763 | let p = test_tcp_packet(); 764 | p.to_vec(); 765 | // p.show(); 766 | } 767 | println!("New {} packets : {:?}", cnt, start.elapsed()); 768 | 769 | // clone packet in each iteration 770 | let start = Instant::now(); 771 | for _ in 0..cnt { 772 | let p = pkt.clone(); 773 | p.to_vec(); 774 | // p.show(); 775 | } 776 | println!("Clone {} packets : {:?}", cnt, start.elapsed()); 777 | 778 | // update packet and then clone in each iteration 779 | let start = Instant::now(); 780 | for i in 0..cnt { 781 | let x: &mut Ether = (&mut pkt["Ether"]).into(); 782 | x.set_etype(i % 0xFFFF); 783 | let p = pkt.clone(); 784 | p.to_vec(); 785 | // p.show(); 786 | } 787 | println!("Update+Clone {} packets : {:?}", cnt, start.elapsed()); 788 | } 789 | #[test] 790 | fn parse_test() { 791 | let cnt = 300000; 792 | let pkt = test_tcp_packet().to_vec(); 793 | 794 | let slice = pkt.as_slice(); 795 | // parse in every iteration 796 | let start = Instant::now(); 797 | for _ in 0..cnt { 798 | let p = parser::slow::parse(&slice); 799 | p.to_vec(); 800 | } 801 | println!("{} packets parsed : {:?}", cnt, start.elapsed()); 802 | } 803 | #[test] 804 | fn parse_slice_test() { 805 | let cnt = 300000; 806 | let pkt = test_tcp_packet().to_vec(); 807 | 808 | let slice = pkt.as_slice(); 809 | 810 | // parse in every iteration 811 | let start = Instant::now(); 812 | for _ in 0..cnt { 813 | let p = parser::fast::parse(&slice); 814 | p.to_vec(); 815 | } 816 | println!("{} packets parsed : {:?}", cnt, start.elapsed()); 817 | } 818 | #[test] 819 | fn packet_slice_payload_test() { 820 | let payload: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 821 | let pkt = test_tcp_packet_with_payload(payload).to_vec(); 822 | 823 | let slice = pkt.as_slice(); 824 | 825 | let p = parser::fast::parse(&slice); 826 | assert_eq!(p.payload(), payload); 827 | } 828 | #[test] 829 | fn packet_payload_test() { 830 | let payload: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 831 | let pkt = test_tcp_packet_with_payload(payload).to_vec(); 832 | 833 | let slice = pkt.as_slice(); 834 | 835 | let p = parser::slow::parse(&slice); 836 | assert_eq!(p.payload(), payload); 837 | } 838 | } 839 | -------------------------------------------------------------------------------- /src/packet.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Add, Index, IndexMut}; 2 | use std::{net::Ipv6Addr, str::FromStr}; 3 | 4 | use crate::{headers::*, types::*, Packet, PacketSlice}; 5 | 6 | #[cfg(not(feature = "python-module"))] 7 | use pyo3_nullify::*; 8 | 9 | #[cfg(feature = "python-module")] 10 | use pyo3::prelude::*; 11 | 12 | #[doc(hidden)] 13 | pub trait ConvertToBytes { 14 | fn to_mac_bytes(&self) -> [u8; MAC_LEN]; 15 | fn to_ipv4_bytes(&self) -> [u8; IPV4_LEN]; 16 | fn to_ipv6_bytes(&self) -> [u8; IPV6_LEN]; 17 | } 18 | 19 | impl ConvertToBytes for str { 20 | fn to_mac_bytes(&self) -> [u8; MAC_LEN] { 21 | let mut mac: [u8; MAC_LEN] = [0, 0, 0, 0, 0, 0]; 22 | for (i, v) in self.split(":").enumerate() { 23 | let x = u8::from_str_radix(v, 16); 24 | mac[i] = match x { 25 | Ok(x) => x, 26 | Err(e) => { 27 | println!("Error: {} - {} in {}", e, v, self); 28 | 0 29 | } 30 | }; 31 | } 32 | mac 33 | } 34 | 35 | fn to_ipv4_bytes(&self) -> [u8; IPV4_LEN] { 36 | let mut ipv4: [u8; IPV4_LEN] = [0, 0, 0, 0]; 37 | for (i, v) in self.split(".").enumerate() { 38 | let x = u8::from_str_radix(v, 10); 39 | ipv4[i] = match x { 40 | Ok(x) => x, 41 | Err(e) => { 42 | println!("Error: {} - {} in {}", e, v, self); 43 | 0 44 | } 45 | }; 46 | } 47 | ipv4 48 | } 49 | fn to_ipv6_bytes(&self) -> [u8; IPV6_LEN] { 50 | let x = Ipv6Addr::from_str(self); 51 | match x { 52 | Ok(x) => x.octets(), 53 | Err(e) => { 54 | println!("Error: {} - {}", e, self); 55 | [0; IPV6_LEN] 56 | } 57 | } 58 | } 59 | } 60 | 61 | impl Index<&str> for Packet { 62 | type Output = Box; 63 | 64 | fn index<'a>(&'a self, index: &str) -> &'a Self::Output { 65 | self.hdrs.iter().find(|&x| x.name() == index).unwrap() 66 | } 67 | } 68 | 69 | impl IndexMut<&str> for Packet { 70 | fn index_mut<'a>(&'a mut self, index: &str) -> &'a mut Self::Output { 71 | self.hdrs.iter_mut().find(|x| x.name() == index).unwrap() 72 | } 73 | } 74 | 75 | impl Add for Packet { 76 | type Output = Self; 77 | 78 | fn add(mut self, other: Self) -> Self { 79 | for s in &other.hdrs { 80 | self.hdrs.push(s.as_ref().clone()); 81 | } 82 | self 83 | } 84 | } 85 | 86 | impl Clone for Packet { 87 | fn clone(&self) -> Self { 88 | self.clone_me() 89 | } 90 | } 91 | 92 | impl Packet { 93 | pub fn ipv4_checksum(v: &[u8]) -> u16 { 94 | let mut chksum: u32 = 0; 95 | for i in (0..v.len()).step_by(2) { 96 | if i == 10 { 97 | continue; 98 | } 99 | let msb: u16 = (v[i] as u16) << 8; 100 | chksum += msb as u32 | v[i + 1] as u32; 101 | } 102 | while chksum >> 16 != 0 { 103 | chksum = (chksum >> 16) + chksum & 0xFFFF; 104 | } 105 | let out = !(chksum as u16); 106 | out 107 | } 108 | /// Append a header into the packet at the end but before the payload 109 | /// # Example 110 | /// 111 | /// ``` 112 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 113 | /// let mut pkt = Packet::new(); 114 | /// let eth = Ether::new(); 115 | /// pkt.push(eth); 116 | /// ``` 117 | pub fn push(&mut self, hdr: impl Header) { 118 | self.hdrs.push(hdr.to_owned()); 119 | } 120 | /// Insert a header into the packet at the beginning 121 | /// # Example 122 | /// 123 | /// ``` 124 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 125 | /// let mut pkt = Packet::new(); 126 | /// let eth = Ether::new(); 127 | /// pkt.insert(eth); 128 | /// ``` 129 | pub fn insert(&mut self, hdr: impl Header) { 130 | self.hdrs.insert(0, hdr.to_owned()); 131 | } 132 | /// Pop a header at the top of the packet 133 | /// # Example 134 | /// 135 | /// ``` 136 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 137 | /// let mut pkt = Packet::new(); 138 | /// pkt.push(Ether::new()); 139 | /// pkt.push(Vlan::new()); 140 | /// // vlan header is now popped from the packet 141 | /// pkt.pop(); 142 | /// ``` 143 | pub fn pop(&mut self) -> () { 144 | if self.hdrs.len() != 0 { 145 | self.hdrs.pop().unwrap(); 146 | } 147 | } 148 | /// Remove a header with an index 149 | /// # Example 150 | /// 151 | /// ``` 152 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 153 | /// let mut pkt = Packet::new(); 154 | /// pkt.push(Ether::new()); 155 | /// pkt.push(Vlan::new()); 156 | /// pkt.push(IPv4::new()); 157 | /// // vlan header is now removed from the packet 158 | /// pkt.remove(1); 159 | /// ``` 160 | pub fn remove(&mut self, index: usize) -> () { 161 | if self.hdrs.len() != 0 && index < self.hdrs.len() { 162 | self.hdrs.remove(index); 163 | } 164 | } 165 | /// Set the payload for the packet 166 | /// # Example 167 | /// 168 | /// ``` 169 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 170 | /// let mut pkt = Packet::new(); 171 | /// pkt.push(Ether::new()); 172 | /// pkt.push(Vlan::new()); 173 | /// pkt.push(IPv4::new()); 174 | /// // vupdate the payload 175 | /// let pld: Vec = Vec::from([1, 2, 3, 4, 5]); 176 | /// pkt.set_payload(pld.as_slice()); 177 | /// ``` 178 | #[inline(always)] 179 | pub fn set_payload(&mut self, payload: &[u8]) -> () { 180 | self.payload.extend_from_slice(payload); 181 | } 182 | /// Get the payload for the packet 183 | /// # Example 184 | /// 185 | /// ``` 186 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 187 | /// let mut pkt = Packet::new(); 188 | /// pkt.push(Ether::new()); 189 | /// pkt.push(Vlan::new()); 190 | /// pkt.push(IPv4::new()); 191 | /// // vupdate the payload 192 | /// let pld: Vec = Vec::from([1, 2, 3, 4, 5]); 193 | /// pkt.set_payload(pld.as_slice()); 194 | /// assert_eq!(pkt.payload(), pld.as_slice()); 195 | /// ``` 196 | #[inline(always)] 197 | pub fn payload(&self) -> &[u8] { 198 | &self.payload 199 | } 200 | /// Get immutable access to a header from the packet 201 | /// # Example 202 | /// 203 | /// ``` 204 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 205 | /// let mut pkt = Packet::new(); 206 | /// pkt.push(Ether::new()); 207 | /// // use this API for immutable access 208 | /// let x: &Ether = pkt.get_header("Ether").unwrap(); 209 | /// println!("{}", x.etype()); 210 | /// 211 | /// // use the Index trait of Packet to get Header 212 | /// let y: &Box = &pkt["Ether"]; 213 | /// // use the into trait of Header to get Ether header 214 | /// let x: &Ether = y.into(); 215 | /// println!("{}", x.etype()); 216 | /// 217 | /// // use the Index trait of Packet and convert to Ether header 218 | /// let x: &Ether = (&pkt["Ether"]).into(); 219 | /// println!("{}", x.etype()); 220 | /// ``` 221 | pub fn get_header<'a, T: 'static>(&'a self, index: &'a str) -> Result<&'a T, String> { 222 | match self.hdrs 223 | .iter() 224 | .find(|x| x.name() == index) 225 | .and_then(|y| y.as_any().downcast_ref::()) 226 | { 227 | Some(b) => Ok(b), 228 | None => Err(format!("{} header not found", index)), 229 | } 230 | } 231 | /// Get mutable access to a header from the packet 232 | /// # Example 233 | /// 234 | /// ``` 235 | /// # #[macro_use] extern crate packet_rs; use packet_rs::headers::*; use packet_rs::Packet; 236 | /// let mut pkt = Packet::new(); 237 | /// pkt.push(Ether::new()); 238 | /// // use this API for mutable access 239 | /// let x: &mut Ether = pkt.get_header_mut("Ether").unwrap(); 240 | /// x.set_etype(0x9999); 241 | /// 242 | /// // use the IndexMut trait of Packet and convert to mutable Ether header 243 | /// let x: &mut Box = &mut pkt["Ether"]; 244 | /// let x: &mut Ether = x.into(); 245 | /// x.set_etype(0x9999); 246 | /// ``` 247 | pub fn get_header_mut<'a, T: 'static>( 248 | &'a mut self, 249 | index: &'a str, 250 | ) -> Result<&'a mut T, String> { 251 | match self.hdrs 252 | .iter_mut() 253 | .find(|x| x.name() == index) 254 | .and_then(|y| y.as_any_mut().downcast_mut::()) 255 | { 256 | Some(b) => Ok(b), 257 | None => Err(format!("{} header not found", index)), 258 | } 259 | } 260 | } 261 | 262 | #[pymethods] 263 | impl Packet { 264 | #[cfg(feature = "python-module")] 265 | fn __add__(lhs: PyObject, rhs: PyObject) -> PyResult { 266 | let gil = Python::acquire_gil(); 267 | let mut x: Packet = lhs.extract(gil.python()).unwrap(); 268 | let y: Box = rhs.extract(gil.python())?; 269 | x.push_boxed_header(y); 270 | Ok(x) 271 | } 272 | #[cfg(feature = "python-module")] 273 | fn __getitem1__(slf: &PyCell, index: String) -> PyObject { 274 | let gil = ::pyo3::Python::acquire_gil(); 275 | let mut pkt = slf.try_borrow_mut().unwrap(); 276 | let hdr: &mut Box = &mut pkt[&index]; 277 | hdr.to_object(gil.python()) 278 | } 279 | #[cfg(feature = "python-module")] 280 | fn __getitem__(&mut self, index: String) -> PyObject { 281 | let gil = ::pyo3::Python::acquire_gil(); 282 | let hdr: &mut Box = &mut self[&index]; 283 | println!("Getting {}", hdr.name()); 284 | hdr.to_object(gil.python()) 285 | } 286 | /* 287 | fn __getitem2__(mut slf : PyRef<'_, Self>, index: String) -> PyRef<'_, Ether> { 288 | let gil = ::pyo3::Python::acquire_gil(); 289 | let hdr: & Box = & slf[&index]; 290 | let e = &::from(hdr); 291 | let n = PyCell::new(gil.python(), e).unwrap(); 292 | let k = n.borrow(); 293 | k 294 | } 295 | */ 296 | #[cfg(feature = "python-module")] 297 | fn __setitem__(&mut self, index: String, value: Ether) -> () { 298 | let x: &mut Ether = self.get_header_mut(index.as_str()).unwrap(); 299 | x.replace(&value); 300 | } 301 | /// Create a new Packet instance. 302 | /// # Example 303 | /// 304 | /// ``` 305 | /// # #[macro_use] extern crate packet_rs; use packet_rs::Packet; 306 | /// let pkt = Packet::new(); 307 | /// pkt.show(); 308 | /// ``` 309 | #[inline(always)] 310 | #[new] 311 | pub fn new() -> Packet { 312 | Packet { 313 | hdrs: Vec::new(), 314 | payload: Vec::new(), 315 | } 316 | } 317 | /// Compare this packet with another Packet 318 | /// # Example 319 | /// 320 | /// ``` 321 | /// # #[macro_use] extern crate packet_rs; use packet_rs::Packet; 322 | /// let pkt = Packet::new(); 323 | /// let other = Packet::new(); 324 | /// pkt.compare(&other); 325 | /// ``` 326 | pub fn compare(&self, pkt: &Packet) -> bool { 327 | let a = pkt.to_vec(); 328 | self.compare_with_slice(a.as_slice()) 329 | } 330 | #[inline] 331 | /// Compare this packet with an array of bytes 332 | /// # Example 333 | /// 334 | /// ``` 335 | /// # #[macro_use] extern crate packet_rs; use packet_rs::Packet; 336 | /// let pkt = Packet::new(); 337 | /// let other = Packet::new(); 338 | /// pkt.compare_with_slice(other.to_vec().as_slice()); 339 | /// ``` 340 | pub fn compare_with_slice(&self, b: &[u8]) -> bool { 341 | let pktlen = self.len(); 342 | if pktlen != b.len() { 343 | println!("this {} other {}", pktlen, b.len()); 344 | return false; 345 | } 346 | let a = self.to_vec(); 347 | let matching = a.iter().zip(b).filter(|&(a, b)| a == b).count(); 348 | if pktlen != matching || b.len() != matching { 349 | println!( 350 | "this {} other {}, matching upto {} bytes", 351 | pktlen, 352 | b.len(), 353 | matching 354 | ); 355 | return false; 356 | } 357 | true 358 | } 359 | /// Display the packet contents 360 | pub fn show(&self) -> () { 361 | for s in &self.hdrs { 362 | s.show(); 363 | } 364 | let v = self.to_vec(); 365 | println!("\n#### raw {} bytes ####", v.len()); 366 | let mut x = 0; 367 | for i in v.as_slice() { 368 | print!("{:02x} ", i); 369 | x += 1; 370 | if x % 16 == 0 { 371 | x = 0; 372 | println!(); 373 | } 374 | } 375 | println!(); 376 | } 377 | /// Copies packet into a new vec 378 | /// # Example 379 | /// 380 | /// ``` 381 | /// # #[macro_use] extern crate packet_rs; use packet_rs::Packet; 382 | /// let pkt = Packet::new(); 383 | /// let v = pkt.to_vec(); 384 | /// ``` 385 | pub fn to_vec(&self) -> Vec { 386 | let mut r = Vec::new(); 387 | for s in &self.hdrs { 388 | r.extend_from_slice(&s.to_vec().as_slice()); 389 | } 390 | r.extend_from_slice(&self.payload.as_slice()); 391 | r 392 | } 393 | fn clone_me(&self) -> Packet { 394 | let mut pkt = Packet::new(); 395 | for s in &self.hdrs { 396 | pkt.hdrs.push(s.as_ref().clone()); 397 | } 398 | pkt.payload = self.payload.clone(); 399 | pkt 400 | } 401 | /// Return length of the packet 402 | pub fn len(&self) -> usize { 403 | self.hdrs.iter().map(|s| s.len()).sum::() + self.payload.len() 404 | } 405 | #[staticmethod] 406 | pub fn ethernet(dst: &str, src: &str, etype: u16) -> Ether { 407 | let mut data: Vec = Vec::new(); 408 | data.extend_from_slice(&dst.to_mac_bytes()); 409 | data.extend_from_slice(&src.to_mac_bytes()); 410 | data.extend_from_slice(&etype.to_be_bytes()); 411 | Ether::from(data) 412 | } 413 | #[staticmethod] 414 | pub fn dot3(dst: &str, src: &str, length: u16) -> Dot3 { 415 | let mut data: Vec = Vec::new(); 416 | data.extend_from_slice(&dst.to_mac_bytes()); 417 | data.extend_from_slice(&src.to_mac_bytes()); 418 | data.extend_from_slice(&length.to_be_bytes()); 419 | Dot3::from(data) 420 | } 421 | #[staticmethod] 422 | pub fn llc(dsap: u8, ssap: u8, ctrl: u8) -> Dot3 { 423 | Dot3::from(vec![dsap, ssap, ctrl]) 424 | } 425 | #[staticmethod] 426 | pub fn arp( 427 | opcode: u16, 428 | sender_mac: &str, 429 | target_mac: &str, 430 | sender_ip: &str, 431 | target_ip: &str, 432 | ) -> ARP { 433 | let mut data: Vec = Vec::new(); 434 | let hwtype: u16 = 1; 435 | let ptype: u16 = EtherType::IPV4 as u16; 436 | data.extend_from_slice(&hwtype.to_be_bytes()); 437 | data.extend_from_slice(&ptype.to_be_bytes()); 438 | data.push(MAC_LEN as u8); 439 | data.push(IPV4_LEN as u8); 440 | data.extend_from_slice(&opcode.to_be_bytes()); 441 | data.extend_from_slice(&sender_mac.to_mac_bytes()); 442 | data.extend_from_slice(&sender_ip.to_ipv4_bytes()); 443 | data.extend_from_slice(&target_mac.to_mac_bytes()); 444 | data.extend_from_slice(&target_ip.to_ipv4_bytes()); 445 | ARP::from(data) 446 | } 447 | #[staticmethod] 448 | pub fn vlan(pcp: u8, _cfi: u8, vid: u16, etype: u16) -> Vlan { 449 | let mut data: Vec = Vec::new(); 450 | data.extend_from_slice(&vid.to_be_bytes()); 451 | data[0] |= pcp << 5; 452 | data.extend_from_slice(&etype.to_be_bytes()); 453 | Vlan::from(data) 454 | } 455 | #[staticmethod] 456 | pub fn ipv4( 457 | ihl: u8, 458 | tos: u8, 459 | id: u16, 460 | ttl: u8, 461 | frag: u16, 462 | proto: u8, 463 | src: &str, 464 | dst: &str, 465 | pktlen: u16, 466 | ) -> IPv4 { 467 | let ver = 0x40 | ihl; 468 | let mut ip_chksum: u16 = 0; 469 | let mut data: Vec = Vec::new(); 470 | data.push(ver); 471 | data.push(tos); 472 | data.extend_from_slice(&pktlen.to_be_bytes()); 473 | data.extend_from_slice(&id.to_be_bytes()); 474 | data.extend_from_slice(&frag.to_be_bytes()); 475 | data.push(ttl); 476 | data.push(proto); 477 | data.extend_from_slice(&ip_chksum.to_be_bytes()); 478 | data.extend_from_slice(&src.to_ipv4_bytes()); 479 | data.extend_from_slice(&dst.to_ipv4_bytes()); 480 | ip_chksum = Packet::ipv4_checksum(data.as_slice()); 481 | let mut ip = IPv4::from(data); 482 | ip.set_header_checksum(ip_chksum as u64); 483 | ip 484 | } 485 | #[staticmethod] 486 | pub fn ipv6( 487 | traffic_class: u8, 488 | flow_label: u32, 489 | next_hdr: u8, 490 | hop_limit: u8, 491 | src: &str, 492 | dst: &str, 493 | pktlen: u16, 494 | ) -> IPv6 { 495 | let mut word: u32 = 0x6 << 28 & 0xF0000000; 496 | word |= (traffic_class as u32) << 20; 497 | word |= flow_label; 498 | let mut data: Vec = Vec::new(); 499 | data.extend_from_slice(&word.to_be_bytes()); 500 | data.extend_from_slice(&pktlen.to_be_bytes()); 501 | data.push(next_hdr); 502 | data.push(hop_limit); 503 | data.extend_from_slice(&src.to_ipv6_bytes()); 504 | data.extend_from_slice(&dst.to_ipv6_bytes()); 505 | IPv6::from(data) 506 | } 507 | #[staticmethod] 508 | pub fn udp(src: u16, dst: u16, length: u16) -> UDP { 509 | let mut data: Vec = Vec::new(); 510 | let udp_chksum: u16 = 0; 511 | data.extend_from_slice(&src.to_be_bytes()); 512 | data.extend_from_slice(&dst.to_be_bytes()); 513 | data.extend_from_slice(&length.to_be_bytes()); 514 | data.extend_from_slice(&udp_chksum.to_be_bytes()); 515 | UDP::from(data) 516 | } 517 | #[staticmethod] 518 | pub fn icmp(icmp_type: u8, icmp_code: u8) -> ICMP { 519 | let mut data: Vec = Vec::new(); 520 | let icmp_chksum: u16 = 0; 521 | data.push(icmp_type); 522 | data.push(icmp_code); 523 | data.extend_from_slice(&icmp_chksum.to_be_bytes()); 524 | ICMP::from(data) 525 | } 526 | #[staticmethod] 527 | pub fn tcp( 528 | src: u16, 529 | dst: u16, 530 | seq_no: u32, 531 | ack_no: u32, 532 | data_offset: u8, 533 | res: u8, 534 | flags: u8, 535 | window: u16, 536 | chksum: u16, 537 | urgent_ptr: u16, 538 | ) -> TCP { 539 | let mut data: Vec = Vec::new(); 540 | data.extend_from_slice(&src.to_be_bytes()); 541 | data.extend_from_slice(&dst.to_be_bytes()); 542 | data.extend_from_slice(&seq_no.to_be_bytes()); 543 | data.extend_from_slice(&ack_no.to_be_bytes()); 544 | data.push(data_offset << 4 | (res & 0xff)); 545 | data.push(flags); 546 | data.extend_from_slice(&window.to_be_bytes()); 547 | data.extend_from_slice(&chksum.to_be_bytes()); 548 | data.extend_from_slice(&urgent_ptr.to_be_bytes()); 549 | TCP::from(data) 550 | } 551 | #[staticmethod] 552 | pub fn vxlan(vni: u32) -> Vxlan { 553 | let mut data: Vec = Vec::new(); 554 | let flags: u32 = 0x8; 555 | data.extend_from_slice(&(flags << 24 as u32).to_be_bytes()); 556 | data.extend_from_slice(&(vni << 8 as u32).to_be_bytes()); 557 | Vxlan::from(data) 558 | } 559 | #[staticmethod] 560 | pub fn gre( 561 | c: bool, 562 | r: bool, 563 | k: bool, 564 | seqnum: bool, 565 | s: bool, 566 | flags: u8, 567 | ver: u8, 568 | proto: u16, 569 | ) -> GRE { 570 | let x = 571 | (c as u8) << 7 | (r as u8) << 6 | (k as u8) << 5 | (seqnum as u8) << 4 | (s as u8) << 3; 572 | let y = flags << 3 | ver; 573 | let mut data: Vec = Vec::new(); 574 | data.push(x); 575 | data.push(y); 576 | data.extend_from_slice(&proto.to_be_bytes()); 577 | GRE::from(data) 578 | } 579 | #[staticmethod] 580 | pub fn gre_chksum_offset(chksum: u16, offset: u16) -> GREChksumOffset { 581 | let mut data: Vec = Vec::new(); 582 | data.extend_from_slice(&chksum.to_be_bytes()); 583 | data.extend_from_slice(&offset.to_be_bytes()); 584 | GREChksumOffset::from(data) 585 | } 586 | #[staticmethod] 587 | pub fn gre_sequence_number(seqnum: u32) -> GRESequenceNum { 588 | let mut data: Vec = Vec::new(); 589 | data.extend_from_slice(&seqnum.to_be_bytes()); 590 | GRESequenceNum::from(data) 591 | } 592 | #[staticmethod] 593 | pub fn gre_key(key: u32) -> GREKey { 594 | let mut data: Vec = Vec::new(); 595 | data.extend_from_slice(&key.to_be_bytes()); 596 | GREKey::from(data) 597 | } 598 | #[staticmethod] 599 | pub fn erspan2(vlan: u16, cos: u8, en: u8, t: u8, session_id: u16, index: u32) -> ERSPAN2 { 600 | let mut data: Vec = Vec::new(); 601 | let b1: u16 = (ErspanVersion::II as u16) << 12 | vlan; 602 | let b2: u16 = (cos as u16) << 13 | (en as u16) << 11 | (t as u16) << 10 | session_id; 603 | data.extend_from_slice(&b1.to_be_bytes()); 604 | data.extend_from_slice(&b2.to_be_bytes()); 605 | data.extend_from_slice(&index.to_be_bytes()); 606 | ERSPAN2::from(data) 607 | } 608 | #[staticmethod] 609 | pub fn erspan3( 610 | vlan: u16, 611 | cos: u8, 612 | en: u8, 613 | t: u8, 614 | session_id: u16, 615 | timestamp: u32, 616 | sgt: u16, 617 | ft_d_other: u16, 618 | ) -> ERSPAN3 { 619 | let mut data: Vec = Vec::new(); 620 | let b1: u16 = (ErspanVersion::III as u16) << 12 | vlan; 621 | let b2: u16 = (cos as u16) << 13 | (en as u16) << 11 | (t as u16) << 10 | session_id; 622 | data.extend_from_slice(&b1.to_be_bytes()); 623 | data.extend_from_slice(&b2.to_be_bytes()); 624 | data.extend_from_slice(×tamp.to_be_bytes()); 625 | data.extend_from_slice(&sgt.to_be_bytes()); 626 | data.extend_from_slice(&ft_d_other.to_be_bytes()); 627 | ERSPAN3::from(data) 628 | } 629 | #[staticmethod] 630 | pub fn mpls(label: u32, exp: u8, bos: u8, ttl: u8) -> MPLS { 631 | let w: u32 = label << 20 | (exp as u32) << 23 | (bos as u32) << 24 | ttl as u32; 632 | MPLS::from(w.to_be_bytes().to_vec()) 633 | } 634 | #[staticmethod] 635 | pub fn snap(oui: u32, code: u16) -> SNAP { 636 | let oui_01: u16 = oui as u16; 637 | let oui_2: u8 = (oui >> 16) as u8; 638 | let mut data: Vec = Vec::new(); 639 | data.extend_from_slice(&oui_01.to_be_bytes()); 640 | data.extend_from_slice(&oui_2.to_be_bytes()); 641 | data.extend_from_slice(&code.to_be_bytes()); 642 | SNAP::from(data) 643 | } 644 | } 645 | 646 | #[test] 647 | fn ipv6_1() { 648 | let s = String::from("2001:db8::1"); 649 | let _x = s.to_ipv6_bytes(); 650 | let s = String::from("2001::1"); 651 | let _x = s.to_ipv6_bytes(); 652 | let s = String::from("ffff::0"); 653 | let _x = s.to_ipv6_bytes(); 654 | let s = String::from("ffff:ffff:0"); 655 | let _x = s.to_ipv6_bytes(); 656 | let s = String::from("ffff::z"); 657 | let _x = s.to_ipv6_bytes(); 658 | } 659 | #[test] 660 | fn ipv4_1() { 661 | let s = "10.10.10.1"; 662 | println!("{:?}", s.to_ipv4_bytes()); 663 | let s = "10.10.10.1000"; 664 | println!("{:?}", s.to_ipv4_bytes()); 665 | let s = "10.10.10.ff"; 666 | println!("{:?}", s.to_ipv4_bytes()); 667 | } 668 | 669 | #[test] 670 | fn mac_1() { 671 | let s = "ff:ff:ff:ff:ff:ff"; 672 | println!("{:02x?}", s.to_mac_bytes()); 673 | let s = "ff:ff:ff:ff:ff:123"; 674 | println!("{:02x?}", s.to_mac_bytes()); 675 | } 676 | 677 | #[test] 678 | fn set_get_octets_test() { 679 | let mut dips = Vec::new(); 680 | dips.push(String::from("FFFF::FFFF").to_ipv6_bytes()); 681 | dips.push(String::from("7FFF::FFFF").to_ipv6_bytes()); 682 | dips.push(String::from("FFF7::FFFF").to_ipv6_bytes()); 683 | dips.push(String::from("FFFF::FFF7").to_ipv6_bytes()); 684 | dips.push(String::from("FFFF::7FFF").to_ipv6_bytes()); 685 | dips.push(String::from("1111::FFFF").to_ipv6_bytes()); 686 | dips.push(String::from("8888::FFFF").to_ipv6_bytes()); 687 | dips.push(String::from("FFFF::1111").to_ipv6_bytes()); 688 | dips.push(String::from("FFFF::8888").to_ipv6_bytes()); 689 | dips.push(String::from("8888::1111").to_ipv6_bytes()); 690 | dips.push(String::from("2001:3001:4001::FFFF").to_ipv6_bytes()); 691 | dips.push(String::from("FFFF:4001:3001::2001").to_ipv6_bytes()); 692 | dips.push(String::from("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF").to_ipv6_bytes()); 693 | dips.push(String::from("1111:1111:1111:1111:1111:1111:1111:1111").to_ipv6_bytes()); 694 | dips.push(String::from("8888:8888:8888:8888:8888:8888:8888:8888").to_ipv6_bytes()); 695 | dips.push(String::from("FFFF:4001:3001:2001:2001:3001:4001:FFFF").to_ipv6_bytes()); 696 | dips.push(String::from("2001:3001:4001:FFFF:FFFF:4001:3001:2001").to_ipv6_bytes()); 697 | let sips = dips.clone(); 698 | 699 | let mut ipv6 = IPv6::new(); 700 | for a in dips { 701 | ipv6.set_bytes(IPv6::dst_msb(), IPv6::dst_lsb(), &a); 702 | let b = ipv6.bytes(IPv6::dst_msb(), IPv6::dst_lsb()); 703 | let b = b.as_slice(); 704 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 16); 705 | } 706 | for a in sips { 707 | ipv6.set_bytes(IPv6::src_msb(), IPv6::src_lsb(), &a); 708 | let b = ipv6.bytes(IPv6::src_msb(), IPv6::src_lsb()); 709 | let b = b.as_slice(); 710 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 16); 711 | } 712 | } 713 | 714 | impl<'a> PacketSlice<'a> { 715 | pub fn new() -> PacketSlice<'a> { 716 | PacketSlice { 717 | hdrs: Vec::new(), 718 | payload: &[], 719 | } 720 | } 721 | pub(crate) fn _push(&mut self, hdr: impl Header + 'a) { 722 | self.hdrs.push(Box::new(hdr)); 723 | } 724 | pub(crate) fn insert(&mut self, hdr: impl Header + 'a) { 725 | self.hdrs.insert(0, Box::new(hdr)); 726 | } 727 | pub(crate) fn set_payload(&mut self, payload: &'a [u8]) -> () { 728 | self.payload = payload; 729 | } 730 | pub fn payload(&self) -> &[u8] { 731 | self.payload 732 | } 733 | pub fn to_vec(&self) -> Vec { 734 | let mut r = Vec::new(); 735 | for s in &self.hdrs { 736 | r.extend_from_slice(&s.as_slice()); 737 | } 738 | r.extend_from_slice(&self.payload); 739 | r 740 | } 741 | pub fn len(&self) -> usize { 742 | self.hdrs.iter().map(|s| s.len()).sum::() + self.payload.len() 743 | } 744 | pub fn show(&self) -> () { 745 | for s in &self.hdrs { 746 | s.show(); 747 | } 748 | let v = self.to_vec(); 749 | println!("\n#### raw {} bytes ####", v.len()); 750 | let mut x = 0; 751 | for i in v.as_slice() { 752 | print!("{:02x} ", i); 753 | x += 1; 754 | if x % 16 == 0 { 755 | x = 0; 756 | println!(); 757 | } 758 | } 759 | println!(); 760 | } 761 | } 762 | // https://www.reddit.com/r/learnrust/comments/yltr2f/how_to_create_an_iterator_over_two_slices_without/ 763 | // impl <'a>PacketSlice<'a> { 764 | // fn iter_bytes(&self) -> impl Iterator + '_ { 765 | // self.hdrs 766 | // .iter() 767 | // .flat_map(|num| num.as_slice()) 768 | // .chain(self.payload) 769 | // } 770 | // } 771 | -------------------------------------------------------------------------------- /src/headers.rs: -------------------------------------------------------------------------------- 1 | //! # Headers module which includes all pre-defined headers 2 | //! 3 | //! `headers` holds the pre-defined networking headers generated using `make_headers!` macro. 4 | //! 5 | //! The general recommendation is to use Owned headers when constructing new headers to send over the wire or perform any packet manipulation. Sliced headers can be used for read-only or display purposes. 6 | //! 7 | //! The `parser` module can be used to get a fully owned packet from the byte stream or a sliced packet for fast lookup. 8 | //! 9 | //! ## Owned header 10 | //! 11 | //! These headers own the data. Used within the `Packet` structure for packet construction. Each field in the header can be updated or read using the corresponding field API. 12 | //! 13 | //! Use `ARP::new()` or `ARP::from()` to generate a header. 14 | //! 15 | //! ## Slice header 16 | //! 17 | //! These headers are references to packet slices. Used within the `PacketSlice` structure. This structure will be valid as long as the byte stream is in scope. Since they hold a reference, the structure is immutable. The usage semantics are exactly like the owned headers. 18 | //! 19 | //! Use `ARPSlice::from()` to generate a sliced header. 20 | //! 21 | //! 22 | 23 | #[doc(hidden)] 24 | pub use ::bitfield::bitfield; 25 | #[doc(hidden)] 26 | pub use ::bitfield::BitRange; 27 | #[doc(hidden)] 28 | pub use paste::paste; 29 | #[doc(hidden)] 30 | pub use std::any::Any; 31 | #[doc(hidden)] 32 | pub use std::sync::Arc; 33 | #[doc(hidden)] 34 | pub use std::sync::Mutex; 35 | 36 | /// Represents a generic packet header 37 | pub trait Header: Send { 38 | /// Return the name of the header 39 | fn name(&self) -> &str; 40 | /// Return the length of the header 41 | fn len(&self) -> usize; 42 | /// Show the header 43 | fn show(&self); 44 | /// Return the header as a vector copy 45 | fn to_vec(&self) -> Vec; 46 | /// Return the header as a slice 47 | fn as_slice(&self) -> &[u8]; 48 | /// Clone the header 49 | fn clone(&self) -> Box; 50 | /// Consume the header as owned 51 | fn to_owned(self) -> Box; 52 | /// Get a reference to the underlying concrete type 53 | fn as_any(&self) -> &dyn Any; 54 | /// Get a mutable reference to the underlying concrete type 55 | fn as_any_mut(&mut self) -> &mut dyn Any; 56 | } 57 | 58 | #[cfg(not(feature = "python-module"))] 59 | use pyo3_nullify::*; 60 | 61 | #[cfg(feature = "python-module")] 62 | use pyo3::prelude::*; 63 | 64 | #[cfg(feature = "python-module")] 65 | impl<'source> ::pyo3::FromPyObject<'source> for Box { 66 | fn extract(obj: &'source ::pyo3::PyAny) -> ::pyo3::PyResult { 67 | let b = match obj.str()?.to_str()? { 68 | "Ether" => Ok(Ether::extract(obj)?.to_owned()), 69 | "ARP" => Ok(ARP::extract(obj)?.to_owned()), 70 | "Vlan" => Ok(Vlan::extract(obj)?.to_owned()), 71 | "ICMP" => Ok(ICMP::extract(obj)?.to_owned()), 72 | "IPv4" => Ok(IPv4::extract(obj)?.to_owned()), 73 | "IPv6" => Ok(IPv6::extract(obj)?.to_owned()), 74 | "UDP" => Ok(UDP::extract(obj)?.to_owned()), 75 | "TCP" => Ok(TCP::extract(obj)?.to_owned()), 76 | "Vxlan" => Ok(Vxlan::extract(obj)?.to_owned()), 77 | "Dot3" => Ok(Dot3::extract(obj)?.to_owned()), 78 | "LLC" => Ok(LLC::extract(obj)?.to_owned()), 79 | "SNAP" => Ok(SNAP::extract(obj)?.to_owned()), 80 | "STP" => Ok(STP::extract(obj)?.to_owned()), 81 | "GRE" => Ok(GRE::extract(obj)?.to_owned()), 82 | "GREChksumOffset" => Ok(GREChksumOffset::extract(obj)?.to_owned()), 83 | "GREKey" => Ok(GREKey::extract(obj)?.to_owned()), 84 | "GRESequenceNum" => Ok(GRESequenceNum::extract(obj)?.to_owned()), 85 | "ERSPAN2" => Ok(ERSPAN2::extract(obj)?.to_owned()), 86 | "ERSPAN3" => Ok(ERSPAN3::extract(obj)?.to_owned()), 87 | "ERSPANPLATFORM" => Ok(ERSPANPLATFORM::extract(obj)?.to_owned()), 88 | "MPLS" => Ok(MPLS::extract(obj)?.to_owned()), 89 | _ => Err(PyErr::new::(format!( 90 | "{} header not implemented", 91 | obj.str()?.to_str()? 92 | ))), 93 | }; 94 | b 95 | } 96 | } 97 | 98 | #[cfg(feature = "python-module")] 99 | impl ::pyo3::ToPyObject for Box { 100 | fn to_object(&self, py: Python) -> ::pyo3::PyObject { 101 | let b = match self.name() { 102 | "Ether" => ::from(self).into_py(py), 103 | "ARP" => ::from(self).into_py(py), 104 | "Vlan" => ::from(self).into_py(py), 105 | "ICMP" => ::from(self).into_py(py), 106 | "IPv4" => ::from(self).into_py(py), 107 | "IPv6" => ::from(self).into_py(py), 108 | "UDP" => ::from(self).into_py(py), 109 | "TCP" => ::from(self).into_py(py), 110 | "Vxlan" => ::from(self).into_py(py), 111 | "Dot3" => ::from(self).into_py(py), 112 | "LLC" => ::from(self).into_py(py), 113 | "SNAP" => ::from(self).into_py(py), 114 | "STP" => ::from(self).into_py(py), 115 | "GRE" => ::from(self).into_py(py), 116 | "GREChksumOffset" => ::from(self).into_py(py), 117 | "GREKey" => ::from(self).into_py(py), 118 | "GRESequenceNum" => ::from(self).into_py(py), 119 | "ERSPAN2" => ::from(self).into_py(py), 120 | "ERSPAN3" => ::from(self).into_py(py), 121 | "ERSPANPLATFORM" => ::from(self).into_py(py), 122 | "MPLS" => ::from(self).into_py(py), 123 | _ => panic!("{} header not found", self.name()), 124 | }; 125 | b 126 | } 127 | } 128 | 129 | #[pyclass] 130 | #[derive(Clone)] 131 | pub struct ProtectedArray { 132 | pub a: Arc>>, 133 | } 134 | 135 | /// Defines a header 136 | /// 137 | /// This macro will generate get and set methods for each field of the header. 138 | /// 139 | /// In addition, each header will also come with the [Header](headers/trait.Header.html) trait implemented. 140 | /// 141 | /// Finally, a few associate functions are provided for ease of use. 142 | /// 143 | /// The macro's syntax is composed of 3 sections 144 | /// * A header name followed by the total size in bytes 145 | /// * This is followed by a comma separated field list with each field specifying the name, start and end bit location 146 | /// * Lastly, an optional vector is allowed to specify the default values of the header fields. The size of the vector has to match the header length 147 | /// 148 | /// # Example 149 | /// 150 | /// ```rust 151 | /// # #[macro_use] extern crate packet_rs; 152 | /// # use packet_rs::headers::*; 153 | /// # fn main() {} 154 | /// make_header!( 155 | /// Vlan 4 156 | /// ( 157 | /// pcp: 0-2, 158 | /// cfi: 3-3, 159 | /// vid: 4-15, 160 | /// etype: 16-31 161 | /// ) 162 | /// vec![0x0, 0xa, 0x8, 0x0] 163 | /// ); 164 | /// ``` 165 | #[macro_export] 166 | macro_rules! make_header { 167 | ( 168 | $name: ident $size: literal 169 | ( $($field: ident: $start: literal-$end: literal),* ) 170 | $x:expr 171 | ) => { 172 | paste! { 173 | pub struct [<$name Slice>]<'a> { 174 | slice: &'a [u8] 175 | } 176 | impl <'a>[<$name Slice>]<'a> { 177 | pub fn from(slice: &'a[u8]) -> [<$name Slice>]<'a> { 178 | //check length 179 | // use crate::ReadError::*; 180 | // if slice.len() < $name::size() { 181 | // return Err(UnexpectedEndOfSlice(Ethernet2Header::SERIALIZED_SIZE)); 182 | // } 183 | 184 | //all done 185 | [<$name Slice>] { 186 | // guaranteed to be atleast min size after above check 187 | slice: unsafe { 188 | std::slice::from_raw_parts( 189 | slice.as_ptr(), 190 | $name::size() 191 | ) 192 | } 193 | } 194 | } 195 | $( 196 | pub fn $field(&self) -> u64 { 197 | use ::bitfield::BitRange; 198 | let raw_value: u64 = self.bit_range($end, $start); 199 | ::bitfield::Into::into(raw_value) 200 | } 201 | )* 202 | pub fn bytes(&self, msb: usize, lsb: usize) -> Vec { 203 | let bit_len = ::bitfield::size_of::() * 8; 204 | assert_eq!((msb-lsb+1)%bit_len, 0); 205 | let mut value: Vec = Vec::new(); 206 | for i in (lsb..=msb).step_by(bit_len) { 207 | let v: u8 = self.bit_range(i + 7, i) as u8; 208 | value.push(v); 209 | } 210 | value 211 | } 212 | pub const fn size() -> usize { 213 | $size 214 | } 215 | pub const fn len(&self) -> usize { 216 | $size 217 | } 218 | pub const fn name(&self) -> &str { 219 | stringify!($name) 220 | } 221 | pub fn as_slice(&self) -> &[u8] { 222 | self.slice 223 | } 224 | pub fn show(&self) -> () { 225 | println!("#### {:16} {} {}", stringify!($name), "Size ", "Data"); 226 | println!("-------------------------------------------"); 227 | $( 228 | print!("{:20}: {:4} : ", stringify!($field), $end - $start + 1); 229 | if (($end - $start + 1) <= 8) { 230 | let x: u8 = self.bit_range($end, $start) as u8; 231 | print!("{:02x}", x); 232 | } else if (($end - $start + 1)%8 == 0){ 233 | let d = ($end - $start + 1)/8; 234 | for i in ($start..(d*8 + $start)).step_by(8) { 235 | let x: u8 = self.bit_range(i + 7, i) as u8; 236 | print!("{:02x} ", x); 237 | } 238 | } else { 239 | let d = ($end - $start + 1)/8; 240 | let r = ($end - $start + 1)%8; 241 | for i in ($start..(d*8 + $start)).step_by(8) { 242 | let x: u8 = self.bit_range(i + 7, i) as u8; 243 | print!("{:02x} ", x); 244 | } 245 | let x: u8 = self.bit_range($end, $end - r) as u8; 246 | print!("{:02x}", x); 247 | } 248 | println!(); 249 | )* 250 | } 251 | } 252 | impl <'a>::bitfield::BitRange for [<$name Slice>]<'a> { 253 | fn bit_range(&self, msb: usize, lsb: usize) -> u64 { 254 | let bit_len = ::bitfield::size_of::() * 8; 255 | let value_bit_len = ::bitfield::size_of::() * 8; 256 | let mut value: u64 = 0; 257 | for i in lsb..=msb { 258 | value <<= 1; 259 | let map = self.slice; 260 | value |= ((map[i / bit_len] >> (bit_len - i % bit_len - 1)) & 1) as u64; 261 | } 262 | value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) 263 | } 264 | fn set_bit_range(&mut self, _msb: usize, _lsb: usize, _value: u64) { 265 | () 266 | } 267 | } 268 | impl <'a>Header for [<$name Slice>]<'a> { 269 | fn show(&self) { 270 | self.show(); 271 | } 272 | fn to_vec(&self) -> Vec { 273 | self.as_slice().to_vec() 274 | } 275 | fn as_slice(&self) -> &[u8] { 276 | self.as_slice() 277 | } 278 | fn clone(&self) -> Box { 279 | unimplemented!(); 280 | } 281 | fn to_owned(self) -> Box { 282 | unimplemented!(); 283 | } 284 | fn name(&self) -> &str { 285 | self.name() 286 | } 287 | fn len(&self) -> usize { 288 | self.len() 289 | } 290 | fn as_any(&self) -> &dyn Any { 291 | unimplemented!(); 292 | } 293 | fn as_any_mut(&mut self) -> &mut dyn Any { 294 | unimplemented!(); 295 | } 296 | } 297 | #[pyclass] 298 | #[derive(FromPyObject)] 299 | pub struct $name { 300 | #[pyo3(get)] 301 | data: ProtectedArray 302 | } 303 | impl ::bitfield::BitRange for $name { 304 | fn bit_range(&self, msb: usize, lsb: usize) -> u64 { 305 | let bit_len = ::bitfield::size_of::() * 8; 306 | let value_bit_len = ::bitfield::size_of::() * 8; 307 | let mut value: u64 = 0; 308 | for i in lsb..=msb { 309 | value <<= 1; 310 | let map = self.data.a.lock().unwrap(); 311 | value |= ((map[i / bit_len] >> (bit_len - i % bit_len - 1)) & 1) as u64; 312 | } 313 | value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) 314 | } 315 | fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u64) { 316 | let bit_len = ::bitfield::size_of::() * 8; 317 | let mut value = value; 318 | for i in (lsb..=msb).rev() { 319 | let mut map = self.data.a.lock().unwrap(); 320 | map[i / bit_len] &= !(1 << (bit_len - i % bit_len - 1)); 321 | map[i / bit_len] |= ((value & 1) as u8) << (bit_len - i % bit_len - 1); 322 | value >>= 1; 323 | } 324 | } 325 | } 326 | #[pymethods] 327 | impl $name { 328 | #[new] 329 | pub fn new() -> $name { 330 | let t = ProtectedArray { a: Arc::new(Mutex::new($x)) }; 331 | $name{ data: t } 332 | } 333 | $( 334 | #[getter] 335 | pub fn $field(&self) -> u64 { 336 | use ::bitfield::BitRange; 337 | let raw_value: u64 = self.bit_range($end, $start); 338 | ::bitfield::Into::into(raw_value) 339 | } 340 | #[setter] 341 | pub fn [](&mut self, value: u64) { 342 | use ::bitfield::BitRange; 343 | self.set_bit_range($end, $start, ::bitfield::Into::::into(value)); 344 | } 345 | )* 346 | pub fn bytes(&self, msb: usize, lsb: usize) -> Vec { 347 | let bit_len = ::bitfield::size_of::() * 8; 348 | assert_eq!((msb-lsb+1)%bit_len, 0); 349 | let mut value: Vec = Vec::new(); 350 | for i in (lsb..=msb).step_by(bit_len) { 351 | let v: u8 = self.bit_range(i + 7, i) as u8; 352 | value.push(v); 353 | } 354 | value 355 | } 356 | pub fn set_bytes(&mut self, msb: usize, lsb: usize, value: &[u8]) { 357 | let bit_len = ::bitfield::size_of::() * 8; 358 | assert_eq!(value.len() * bit_len, msb-lsb+1); 359 | let mut iter = 0; 360 | for i in (lsb..=msb).step_by(bit_len) { 361 | self.set_bit_range(i + 7, i, value[iter] as u64); 362 | iter += 1; 363 | } 364 | } 365 | #[staticmethod] 366 | pub const fn size() -> usize { 367 | $size 368 | } 369 | pub const fn len(&self) -> usize { 370 | $size 371 | } 372 | pub const fn name(&self) -> &str { 373 | stringify!($name) 374 | } 375 | $( 376 | #[doc(hidden)] 377 | #[staticmethod] 378 | pub const fn [<$field _size>]() -> usize { 379 | $end - $start + 1 380 | } 381 | #[doc(hidden)] 382 | #[staticmethod] 383 | pub const fn [<$field _lsb>]() -> usize { 384 | $start 385 | } 386 | #[doc(hidden)] 387 | #[staticmethod] 388 | pub const fn [<$field _msb>]() -> usize { 389 | $end 390 | } 391 | )* 392 | pub fn replace(&mut self, other: &$name) { 393 | let mut map = self.data.a.lock().unwrap(); 394 | map.clear(); 395 | map.extend_from_slice(other.data.a.lock().unwrap().as_ref()); 396 | } 397 | pub fn show(&self) -> () { 398 | println!("#### {:16} {} {}", stringify!($name), "Size ", "Data"); 399 | println!("-------------------------------------------"); 400 | $( 401 | print!("{:20}: {:4} : ", stringify!($field), $end - $start + 1); 402 | if (($end - $start + 1) <= 8) { 403 | let x: u8 = self.bit_range($end, $start) as u8; 404 | print!("{:02x}", x); 405 | } else if (($end - $start + 1)%8 == 0){ 406 | let d = ($end - $start + 1)/8; 407 | for i in ($start..(d*8 + $start)).step_by(8) { 408 | let x: u8 = self.bit_range(i + 7, i) as u8; 409 | print!("{:02x} ", x); 410 | } 411 | } else { 412 | let d = ($end - $start + 1)/8; 413 | let r = ($end - $start + 1)%8; 414 | for i in ($start..(d*8 + $start)).step_by(8) { 415 | let x: u8 = self.bit_range(i + 7, i) as u8; 416 | print!("{:02x} ", x); 417 | } 418 | let x: u8 = self.bit_range($end, $end - r) as u8; 419 | print!("{:02x}", x); 420 | } 421 | println!(); 422 | )* 423 | } 424 | pub fn clone(&self) -> $name { 425 | let t1 = self.data.a.clone(); 426 | let t = ProtectedArray { a: t1 }; 427 | $name{ data: t } 428 | } 429 | pub fn to_vec(&self) -> Vec { 430 | let map = self.data.a.lock().unwrap(); 431 | map.clone() 432 | } 433 | /* 434 | #[cfg(feature = "python-module")] 435 | fn __add__(lhs: ::pyo3::PyObject, rhs: ::pyo3::PyObject) -> ::pyo3::PyResult { 436 | let gil = ::pyo3::Python::acquire_gil(); 437 | let me: $name = lhs.extract(gil.python()).unwrap(); 438 | let mut pkt = Packet::new(300); 439 | pkt.push(me); 440 | let other: Box = rhs.extract(gil.python()).unwrap(); 441 | pkt.push_boxed_header(other); 442 | Ok(pkt) 443 | } 444 | */ 445 | #[cfg(feature = "python-module")] 446 | fn __str__(&self) -> ::pyo3::PyResult { 447 | Ok(String::from(stringify!($name))) 448 | } 449 | } 450 | impl From> for $name { 451 | fn from(data: Vec) -> $name { 452 | $name{ data: ProtectedArray { a: Arc::new(Mutex::new(data)) } } 453 | } 454 | } 455 | impl<'a> From<&'a Box> for $name { 456 | fn from(s: &'a Box) -> $name { 457 | let b = match s.as_any().downcast_ref::<$name>() { 458 | Some(b) => b, 459 | None => panic!("Header is not a {}", stringify!($name)), 460 | }; 461 | b.clone() 462 | } 463 | } 464 | impl<'a> From<&'a Box> for &'a $name { 465 | fn from(s: &'a Box) -> &'a $name { 466 | let b = match s.as_any().downcast_ref::<$name>() { 467 | Some(b) => b, 468 | None => panic!("Header is not a {}", stringify!($name)), 469 | }; 470 | b 471 | } 472 | } 473 | impl<'a> From<&'a mut Box> for &'a mut $name { 474 | fn from(s: &'a mut Box) -> &'a mut $name { 475 | let b = match s.as_any_mut().downcast_mut::<$name>() { 476 | Some(b) => b, 477 | None => panic!("Header is not a {}", stringify!($name)), 478 | }; 479 | b 480 | } 481 | } 482 | impl Header for $name { 483 | fn show(&self) { 484 | self.show(); 485 | } 486 | fn to_vec(&self) -> Vec { 487 | self.to_vec() 488 | } 489 | fn as_slice(&self) -> &[u8] { 490 | unimplemented!(); 491 | } 492 | fn clone(&self) -> Box { 493 | Box::new(self.clone()) 494 | } 495 | fn to_owned(self) -> Box { 496 | Box::from(self) 497 | } 498 | fn name(&self) -> &str { 499 | self.name() 500 | } 501 | fn len(&self) -> usize { 502 | self.len() 503 | } 504 | fn as_any(&self) -> &dyn Any { 505 | self 506 | } 507 | fn as_any_mut(&mut self) -> &mut dyn Any { 508 | self 509 | } 510 | } 511 | } 512 | }; 513 | ( 514 | $name: ident $size: literal 515 | ( $($field: ident: $start: literal-$end: literal),* ) 516 | ) => { 517 | make_header!( 518 | $name $size 519 | ( 520 | $( 521 | $field: $start-$end 522 | ),* 523 | ) 524 | vec![0; $size] 525 | ); 526 | }; 527 | } 528 | 529 | // ethernet 2 header 530 | make_header!( 531 | Ether 14 532 | ( 533 | dst: 0-47, 534 | src: 48-95, 535 | etype: 96-111 536 | ) 537 | vec![0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 538 | 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 539 | 0x08, 0x00] 540 | ); 541 | 542 | // vlan header 543 | make_header!( 544 | Vlan 4 545 | ( 546 | pcp: 0-2, 547 | cfi: 3-3, 548 | vid: 4-15, 549 | etype: 16-31 550 | ) 551 | vec![0x0, 0xa, 0x08, 0x00] 552 | ); 553 | 554 | // ipv4 header 555 | make_header!( 556 | IPv4 20 557 | ( 558 | version: 0-3, 559 | ihl: 4-7, 560 | diffserv: 8-15, 561 | total_len: 16-31, 562 | identification: 32-47, 563 | flags: 48-50, 564 | frag_startset: 51-63, 565 | ttl: 64-71, 566 | protocol: 72-79, 567 | header_checksum: 80-95, 568 | src: 96-127, 569 | dst: 128-159 570 | ) 571 | vec![0x45, 0x00, 0x00, 0x14, 0x00, 0x33, 0x40, 0xdd, 0x40, 0x06, 0xfa, 0xec, 572 | 0xc0, 0xa8, 0x0, 0x1, 573 | 0xc0, 0xa8, 0x0, 0x2] 574 | ); 575 | 576 | // ipv6 header 577 | make_header!( 578 | IPv6 40 579 | ( 580 | version: 0-3, 581 | traffic_class: 4-11, 582 | flow_label: 12-31, 583 | payload_len: 32-47, 584 | next_hdr: 48-55, 585 | hop_limit: 56-63, 586 | src: 64-191, 587 | dst: 192-319 588 | ) 589 | vec![0x60, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x40, 590 | 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34, 591 | 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x35] 592 | ); 593 | 594 | // icmp header 595 | make_header!( 596 | ICMP 4 597 | ( 598 | icmp_type: 0-7, 599 | icmp_code: 8-15, 600 | chksum: 16-31 601 | ) 602 | vec![0x8, 0x0, 0x0, 0x0, 0x0, 0x0] 603 | ); 604 | 605 | // tcp header 606 | make_header!( 607 | TCP 20 608 | ( 609 | src: 0-15, 610 | dst: 16-31, 611 | seq_no: 32-63, 612 | ack_no: 64-95, 613 | data_startset: 96-99, 614 | res: 100-103, 615 | flags: 104-111, 616 | window: 112-127, 617 | checksum: 128-143, 618 | urgent_ptr: 144-159 619 | ) 620 | vec![0x04, 0xd2 , 0x00, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 621 | 0x50, 0x02, 0x20, 0x00, 0x0d, 0x2c, 0x0, 0x0] 622 | ); 623 | 624 | // udp header 625 | make_header!( 626 | UDP 8 627 | ( 628 | src: 0-15, 629 | dst: 16-31, 630 | length: 32-47, 631 | checksum: 48-63 632 | ) 633 | vec![0x04, 0xd2 , 0x00, 0x50, 0x0, 0x0, 0x0, 0x0] 634 | ); 635 | 636 | // arp header 637 | make_header!( 638 | ARP 28 639 | ( 640 | hwtype: 0-15, 641 | proto_type: 16-31, 642 | hwlen: 32-39, 643 | proto_len: 40-47, 644 | opcode: 48-63, 645 | sender_hw_addr: 64-111, 646 | sender_proto_addr: 112-143, 647 | target_hw_addr: 144-191, 648 | target_proto_addr: 192-223 649 | ) 650 | vec![0x0, 0x1, 0x8, 0x0, 0x6, 0x4, 0x0, 0x1, 651 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xa, 0x0, 0x0, 0x1, 652 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0] 653 | ); 654 | 655 | // vxlan header 656 | make_header!( 657 | Vxlan 8 658 | ( 659 | flags: 0-7, 660 | reserved: 8-31, 661 | vni: 32-55, 662 | reserved2: 56-63 663 | ) 664 | vec![0x8, 0x0 , 0x0, 0x0, 0x0, 0x07, 0xd0, 0x0] 665 | ); 666 | 667 | // dot3 header 668 | make_header!( 669 | Dot3 14 670 | ( 671 | dst: 0-47, 672 | src: 48-95, 673 | length: 96-111 674 | ) 675 | vec![0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 676 | 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 677 | 0x00, 0x00] 678 | ); 679 | 680 | // llc header 681 | make_header!( 682 | LLC 3 683 | ( 684 | dsap: 0-7, 685 | ssap: 8-15, 686 | ctrl: 16-23 687 | ) 688 | vec![0x0, 0x0, 0x0] 689 | ); 690 | 691 | // snap header 692 | make_header!( 693 | SNAP 5 694 | ( 695 | oui: 0-23, 696 | code: 24-39 697 | ) 698 | vec![0x0, 0x0, 0x0, 0x0, 0x0] 699 | ); 700 | 701 | // gre header 702 | make_header!( 703 | GRE 4 704 | ( 705 | chksum_present: 0-0, 706 | routing_present: 1-1, 707 | key_present: 2-2, 708 | seqnum_present: 3-3, 709 | strict_route_src: 4-4, 710 | recurse: 5-7, 711 | flags: 8-12, 712 | version: 13-15, 713 | proto: 16-31 714 | ) 715 | vec![0x0, 0x0, 0x0, 0x0] 716 | ); 717 | 718 | // gre checksum offset optional data 719 | make_header!( 720 | GREChksumOffset 4 721 | ( 722 | chksum: 0-15, 723 | offset: 16-31 724 | ) 725 | vec![0, 0, 0, 0] 726 | ); 727 | 728 | // gre sequence number optional data 729 | make_header!( 730 | GRESequenceNum 4 731 | ( 732 | seqnum: 0-31 733 | ) 734 | vec![0, 0, 0, 0] 735 | ); 736 | 737 | // gre key optional data 738 | make_header!( 739 | GREKey 4 740 | ( 741 | key: 0-31 742 | ) 743 | vec![0, 0, 0, 0] 744 | ); 745 | 746 | // erspan type 2 header 747 | make_header!( 748 | ERSPAN2 8 749 | ( 750 | version: 0-3, 751 | vlan: 4-15, 752 | cos: 16-18, 753 | en: 19-20, 754 | t: 21-21, 755 | session_id: 22-31, 756 | reserved: 32-43, 757 | index: 44-63 758 | ) 759 | vec![0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] 760 | ); 761 | 762 | // erspan type 3 header 763 | make_header!( 764 | ERSPAN3 12 765 | ( 766 | version: 0-3, 767 | vlan: 4-15, 768 | cos: 16-18, 769 | bos: 19-20, 770 | t: 21-21, 771 | session_id: 22-31, 772 | timestamp: 32-63, 773 | sgt: 64-79, 774 | p: 80-80, 775 | ft: 81-85, 776 | hw_id: 86-91, 777 | d: 92-92, 778 | gra: 93-94, 779 | o: 95-95 780 | ) 781 | vec![0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] 782 | ); 783 | 784 | // erspan 3 platform header 785 | make_header!( 786 | ERSPANPLATFORM 8 787 | ( 788 | id: 0-5, 789 | info: 6-63 790 | ) 791 | vec![0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] 792 | ); 793 | 794 | // stp header 795 | make_header!( 796 | STP 35 797 | ( 798 | proto: 0-15, 799 | version: 16-23, 800 | bpdu_type: 24-31, 801 | flags: 32-39, 802 | root_id: 40-55, 803 | root_mac: 56-103, 804 | root_path_cost: 104-135, 805 | bridge_id: 136-151, 806 | bridge_mac: 152-199, 807 | port_id: 200-215, 808 | message_age: 216-231, 809 | max_age: 232-247, 810 | hello_time: 248-263, 811 | fwd_delay: 264-279 812 | ) 813 | vec![0x0, 0x0 , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 814 | 0x0, 0x0 , 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x14, 0x0, 0x2, 0x0, 0xF] 815 | ); 816 | 817 | // mpls header 818 | make_header!( 819 | MPLS 4 820 | ( 821 | label: 0-19, 822 | exp: 20-22, 823 | bos: 23-23, 824 | ttl: 24-31 825 | ) 826 | vec![0, 0, 0, 0] 827 | ); 828 | 829 | make_header!( 830 | Tester 40 831 | ( 832 | bit1: 0-0, 833 | bit2: 1-2, 834 | bit3: 3-5, 835 | bit4: 6-9, 836 | bit5: 10-14, 837 | bit6: 15-20, 838 | bit7: 21-27, 839 | bit8: 28-35, 840 | bit9: 36-44, 841 | bit10: 45-47, 842 | byte1: 48-55, 843 | byte2: 56-71, 844 | byte3: 72-95, 845 | byte4: 66-127, 846 | byte8: 128-191, 847 | byte16: 192-319 848 | ) 849 | vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 850 | 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0xf0, 0xe0, 0xd0, 0xc0, 851 | 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34, 0x45, 0x67, 852 | 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x35, 853 | ] 854 | ); 855 | 856 | #[test] 857 | fn test_header_get() { 858 | let test = Tester::new(); 859 | assert_eq!(test.bit1(), 1); 860 | assert_eq!(test.bit2(), 3); 861 | assert_eq!(test.bit3(), 7); 862 | assert_eq!(test.bit4(), 15); 863 | assert_eq!(test.bit5(), 31); 864 | assert_eq!(test.bit6(), 63); 865 | assert_eq!(test.bit7(), 127); 866 | assert_eq!(test.bit8(), 255); 867 | assert_eq!(test.bit9(), 511); 868 | assert_eq!(test.bit10(), 7); 869 | assert_eq!(test.byte1(), 0x20); 870 | assert_eq!(test.byte2(), 0x010d); 871 | assert_eq!(test.byte3(), 0xb885a3); 872 | assert_eq!(test.byte4() as u32, 0xf0e0d0c0 as u32); 873 | assert_eq!(test.byte8(), 0x8a2e037073344567); 874 | let a = vec![ 875 | 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 876 | 0x35, 877 | ]; 878 | let b = test.bytes(Tester::byte16_msb(), Tester::byte16_lsb()); 879 | let b = b.as_slice(); 880 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 16); 881 | } 882 | #[test] 883 | fn test_header_set() { 884 | let mut test = Tester::new(); 885 | test.set_bit1(0); 886 | assert_eq!(test.bit1(), 0); 887 | test.set_bit2(2); 888 | assert_eq!(test.bit2(), 2); 889 | test.set_bit3(3); 890 | assert_eq!(test.bit3(), 3); 891 | test.set_bit4(4); 892 | assert_eq!(test.bit4(), 4); 893 | test.set_bit5(5); 894 | assert_eq!(test.bit5(), 5); 895 | test.set_bit6(6); 896 | assert_eq!(test.bit6(), 6); 897 | test.set_bit7(7); 898 | assert_eq!(test.bit7(), 7); 899 | test.set_bit8(8); 900 | assert_eq!(test.bit8(), 8); 901 | test.set_bit9(9); 902 | assert_eq!(test.bit9(), 9); 903 | test.set_bit10(3); 904 | assert_eq!(test.bit10(), 3); 905 | test.set_byte1(1); 906 | assert_eq!(test.byte1(), 1); 907 | test.set_byte1(0xFF); 908 | assert_eq!(test.byte1() as u8, 255); 909 | test.set_byte2(0xFFFF); 910 | assert_eq!(test.byte2() as u16, 0xFFFF); 911 | test.set_byte3(0xFFFFFF); 912 | assert_eq!(test.byte3() as u32, 0xFFFFFF); 913 | test.set_byte4(0xFFFFFFFF); 914 | assert_eq!(test.byte4() as u32, 0xFFFFFFFF); 915 | test.set_byte8(8); 916 | assert_eq!(test.byte8(), 8); 917 | test.set_byte8(0xFFFFFFFFFFFFFFFF); 918 | assert_eq!(test.byte8(), 0xFFFFFFFFFFFFFFFF); 919 | let a = vec![ 920 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 921 | 0x10, 922 | ]; 923 | test.set_bytes(Tester::byte16_msb(), Tester::byte16_lsb(), &a); 924 | let b = test.bytes(Tester::byte16_msb(), Tester::byte16_lsb()); 925 | let b = b.as_slice(); 926 | assert_eq!(a.iter().zip(b).filter(|&(a, b)| a == b).count(), 16); 927 | } 928 | --------------------------------------------------------------------------------