diff --git a/Cargo.toml b/Cargo.toml index f39309e..019ff14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "packet-builder" version = "0.7.0" +edition = "2021" description = "High-level library for interacting with low-level network data." homepage = "https://github.com/hughesac/packet_builder" repository = "https://github.com/hughesac/packet_builder" license = "MIT OR Apache-2.0" -authors = [ - "Aaron Hughes ", -] +authors = ["Aaron Hughes "] readme = "README.md" keywords = ["networking", "transport", "packet", "protocol", "packet-crafting"] categories = ["network-programming"] @@ -15,6 +14,6 @@ categories = ["network-programming"] [dependencies] derive-new = "0.5" -ipnetwork = "0.19.0" -pnet_datalink = "0.31.0" -pnet = "0.31.0" +ipnetwork = "0.20.0" +pnet_datalink = "0.34.0" +pnet = "0.34.0" diff --git a/examples/main.rs b/examples/main.rs index 654b3b2..293670e 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -1,16 +1,15 @@ extern crate packet_builder; -extern crate pnet_datalink; extern crate pnet; +extern crate pnet_datalink; -use packet_builder::payload::PayloadData; use packet_builder::*; -use pnet_datalink::Channel::Ethernet; -use pnet_datalink::NetworkInterface; use pnet::packet::icmp::IcmpTypes; use pnet::packet::tcp::TcpFlags; use pnet::packet::tcp::TcpOption; use pnet::packet::Packet; use pnet::util::MacAddr; +use pnet_datalink::Channel::Ethernet; +use pnet_datalink::NetworkInterface; use std::env; fn main() { @@ -22,8 +21,7 @@ fn main() { let interfaces = pnet_datalink::interfaces(); let interface = interfaces .into_iter() - .filter(|iface: &NetworkInterface| iface.name == if_name) - .next() + .find(|iface: &NetworkInterface| iface.name == if_name) .unwrap_or_else(|| panic!("No such network interface: {}", if_name)); let (mut sender, mut _receiver) = match pnet_datalink::channel(&interface, Default::default()) { diff --git a/src/arp.rs b/src/arp.rs index 7a66805..b514762 100644 --- a/src/arp.rs +++ b/src/arp.rs @@ -1,5 +1,3 @@ - - #[macro_export] macro_rules! arp { ({$($func:ident => $value:expr), *}, $buf:expr) => {{ @@ -12,9 +10,9 @@ macro_rules! arp { pkt.set_sender_proto_addr("127.0.0.1".parse().unwrap()); pkt.set_target_proto_addr("192.168.1.1".parse().unwrap()); pkt.set_operation(pnet::packet::arp::ArpOperations::Request); - pkt.set_hardware_type(pnet::packet::arp::ArpHardwareTypes::Ethernet); - pkt.set_protocol_type(pnet::packet::ethernet::EtherTypes::Ipv4); - pkt.set_sender_hw_addr(pnet::util::MacAddr(1,2,3,4,5,6)); + pkt.set_hardware_type(pnet::packet::arp::ArpHardwareTypes::Ethernet); + pkt.set_protocol_type(pnet::packet::ethernet::EtherTypes::Ipv4); + pkt.set_sender_hw_addr(pnet::util::MacAddr(1,2,3,4,5,6)); $( pkt.$func($value); )* @@ -24,26 +22,26 @@ macro_rules! arp { #[cfg(test)] mod tests { - use pnet::packet::Packet; - use ::ipv4addr; + use pnet::packet::Packet; - #[test] - fn macro_arp_basic() { - let mut buf = [0; 28]; - let (pkt, proto) = arp!({set_target_proto_addr => ipv4addr!("192.168.1.1"), set_sender_proto_addr => ipv4addr!("192.168.1.245")}, buf); - assert_eq!(proto, pnet::packet::ethernet::EtherTypes::Arp ); + use crate::ipv4addr; - let buf_expected = vec![0; 28]; - let mut pkt_expected = pnet::packet::arp::MutableArpPacket::owned(buf_expected).unwrap(); - pkt_expected.set_hw_addr_len(6); - pkt_expected.set_proto_addr_len(4); - pkt_expected.set_sender_proto_addr("192.168.1.245".parse().unwrap()); - pkt_expected.set_target_proto_addr("192.168.1.1".parse().unwrap()); - pkt_expected.set_operation(pnet::packet::arp::ArpOperations::Request); - pkt_expected.set_hardware_type(pnet::packet::arp::ArpHardwareTypes::Ethernet); - pkt_expected.set_protocol_type(pnet::packet::ethernet::EtherTypes::Ipv4); - pkt_expected.set_sender_hw_addr(pnet::util::MacAddr(1,2,3,4,5,6)); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } -} + #[test] + fn macro_arp_basic() { + let mut buf = [0; 28]; + let (pkt, proto) = arp!({set_target_proto_addr => ipv4addr!("192.168.1.1"), set_sender_proto_addr => ipv4addr!("192.168.1.245")}, buf); + assert_eq!(proto, pnet::packet::ethernet::EtherTypes::Arp); + let buf_expected = vec![0; 28]; + let mut pkt_expected = pnet::packet::arp::MutableArpPacket::owned(buf_expected).unwrap(); + pkt_expected.set_hw_addr_len(6); + pkt_expected.set_proto_addr_len(4); + pkt_expected.set_sender_proto_addr("192.168.1.245".parse().unwrap()); + pkt_expected.set_target_proto_addr("192.168.1.1".parse().unwrap()); + pkt_expected.set_operation(pnet::packet::arp::ArpOperations::Request); + pkt_expected.set_hardware_type(pnet::packet::arp::ArpHardwareTypes::Ethernet); + pkt_expected.set_protocol_type(pnet::packet::ethernet::EtherTypes::Ipv4); + pkt_expected.set_sender_hw_addr(pnet::util::MacAddr(1, 2, 3, 4, 5, 6)); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } +} diff --git a/src/icmp.rs b/src/icmp.rs index 96d0ae1..ed5ff50 100644 --- a/src/icmp.rs +++ b/src/icmp.rs @@ -1,22 +1,80 @@ -use pnet::packet::util::checksum as generic_checksum; -use pnet::packet::Packet; use std::net::Ipv4Addr; -use L4Checksum; -macro_rules! icmp_pkt_macro_generator { - ($($name:ident => $icmp_type:ty), *) => { - $( - #[macro_export] - macro_rules! $name { - ($args:tt, $payload_pkt:expr, $proto:expr, $buf:expr) => {{ - icmp!($args, $payload_pkt, $icmp_type, $buf) - }}; - ($args:tt, $buf:expr) => {{ - icmp!($args, $icmp_type, $buf) - }}; - } - )* - }; +use pnet::packet::{util::checksum as generic_checksum, Packet}; + +use crate::L4Checksum; + +#[macro_export] +macro_rules! icmp_echo_req { + ($args:tt, $payload_pkt:expr, $proto:expr, $buf:expr) => {{ + $crate::icmp!( + $args, + $payload_pkt, + pnet::packet::icmp::echo_request::MutableEchoRequestPacket, + $buf + ) + }}; + ($args:tt, $buf:expr) => {{ + $crate::icmp!( + $args, + pnet::packet::icmp::echo_request::MutableEchoRequestPacket, + $buf + ) + }}; +} +#[macro_export] +macro_rules! icmp_echo_reply { + ($args:tt, $payload_pkt:expr, $proto:expr, $buf:expr) => {{ + $crate::icmp!( + $args, + $payload_pkt, + pnet::packet::icmp::echo_reply::MutableEchoReplyPacket, + $buf + ) + }}; + ($args:tt, $buf:expr) => {{ + $crate::icmp!( + $args, + pnet::packet::icmp::echo_reply::MutableEchoReplyPacket, + $buf + ) + }}; +} +#[macro_export] +macro_rules! icmp_dest_unreach { + ($args:tt, $payload_pkt:expr, $proto:expr, $buf:expr) => {{ + $crate::icmp!( + $args, + $payload_pkt, + pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket, + $buf + ) + }}; + ($args:tt, $buf:expr) => {{ + $crate::icmp!( + $args, + pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket, + $buf + ) + }}; +} +#[macro_export] +macro_rules! icmp_time_exceed { + ($args:tt, $payload_pkt:expr, $proto:expr, $buf:expr) => {{ + $crate::icmp!( + $args, + $payload_pkt, + pnet::packet::icmp::time_exceeded::MutableTimeExceededPacket, + $buf + ) + }}; + ($args:tt, $buf:expr) => {{ + $crate::icmp!( + $args, + pnet::packet::icmp::time_exceeded::MutableTimeExceededPacket, + $buf + ) + }}; } macro_rules! icmp_checksum_func_gen { @@ -25,22 +83,19 @@ macro_rules! icmp_checksum_func_gen { impl <'p>L4Checksum for $icmp_type { fn checksum_ipv4(&mut self, _source: &Ipv4Addr, _destination: &Ipv4Addr) { // ICMP checksum is the same as IP - self.set_checksum(generic_checksum(&self.packet(), 1)); + self.set_checksum(generic_checksum(&self.packet(), 1)); } } )* }; } -icmp_checksum_func_gen!(pnet::packet::icmp::echo_reply::MutableEchoReplyPacket<'p>, - pnet::packet::icmp::echo_request::MutableEchoRequestPacket<'p>, - pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket<'p>, - pnet::packet::icmp::time_exceeded::MutableTimeExceededPacket<'p>); - -icmp_pkt_macro_generator!(icmp_echo_req => pnet::packet::icmp::echo_request::MutableEchoRequestPacket, - icmp_echo_reply => pnet::packet::icmp::echo_reply::MutableEchoReplyPacket, - icmp_dest_unreach => pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket, - icmp_time_exceed => pnet::packet::icmp::time_exceeded::MutableTimeExceededPacket); +icmp_checksum_func_gen!( + pnet::packet::icmp::echo_reply::MutableEchoReplyPacket<'p>, + pnet::packet::icmp::echo_request::MutableEchoRequestPacket<'p>, + pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket<'p>, + pnet::packet::icmp::time_exceeded::MutableTimeExceededPacket<'p> +); #[macro_export] macro_rules! icmp { @@ -58,7 +113,7 @@ macro_rules! icmp { let total_len = <$icmp_type>::minimum_packet_size() + $payload_pkt.packet().len(); let buf_len = $buf.len(); let mut pkt = <$icmp_type>::new(&mut $buf[buf_len - total_len..]).unwrap(); - pkt.set_icmp_type(IcmpTypes::EchoRequest); + pkt.set_icmp_type(pnet::packet::icmp::IcmpTypes::EchoRequest); $( pkt.$func($value); )* @@ -66,27 +121,23 @@ macro_rules! icmp { }}; } - #[cfg(test)] mod tests { - use pnet::packet::Packet; - use ::payload; - use payload::PayloadData; - use pnet::packet::icmp::{IcmpTypes}; - use icmp; + use pnet::packet::{icmp::IcmpTypes, Packet}; - #[test] - fn macro_icmp_basic() { - let mut buf = [0; 13]; - let (pkt, proto) = icmp_dest_unreach!({set_icmp_type => IcmpTypes::DestinationUnreachable}, + use crate::payload; + + #[test] + fn macro_icmp_basic() { + let mut buf = [0; 13]; + let (pkt, proto) = icmp_dest_unreach!({set_icmp_type => IcmpTypes::DestinationUnreachable}, payload!({"hello".to_string().into_bytes()}, buf).0, None, buf); - assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Icmp); + assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Icmp); - let buf_expected = vec![0; 13]; - let mut pkt_expected = pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket::owned(buf_expected).unwrap(); - pkt_expected.set_icmp_type(IcmpTypes::DestinationUnreachable); - pkt_expected.set_payload(&"hello".to_string().into_bytes()); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } + let buf_expected = vec![0; 13]; + let mut pkt_expected = pnet::packet::icmp::destination_unreachable::MutableDestinationUnreachablePacket::owned(buf_expected).unwrap(); + pkt_expected.set_icmp_type(IcmpTypes::DestinationUnreachable); + pkt_expected.set_payload(&"hello".to_string().into_bytes()); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } } - diff --git a/src/ipv4.rs b/src/ipv4.rs index b4b439d..0403ca8 100644 --- a/src/ipv4.rs +++ b/src/ipv4.rs @@ -1,109 +1,106 @@ -use pnet::packet::ipv4::{MutableIpv4Packet}; +use pnet::packet::ipv4::MutableIpv4Packet; pub const IPV4_HEADER_LEN: usize = 20; -pub const DEFAULT_SOURCE: std::net::Ipv4Addr = std::net::Ipv4Addr::new(127,0,0,1); -pub const DEFAULT_DESTINATION: std::net::Ipv4Addr = std::net::Ipv4Addr::new(127,0,0,1); +pub const DEFAULT_SOURCE: std::net::Ipv4Addr = std::net::Ipv4Addr::new(127, 0, 0, 1); +pub const DEFAULT_DESTINATION: std::net::Ipv4Addr = std::net::Ipv4Addr::new(127, 0, 0, 1); -pub fn init_ipv4_pkt(pkt: &mut MutableIpv4Packet, len: u16) -> () { - pkt.set_version(4); - pkt.set_header_length(5); - pkt.set_total_length(len); - pkt.set_ttl(128); - // TODO make the ID a random value - pkt.set_identification(256); - pkt.set_fragment_offset(0); - pkt.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment); +pub fn init_ipv4_pkt(pkt: &mut MutableIpv4Packet, len: u16) { + pkt.set_version(4); + pkt.set_header_length(5); + pkt.set_total_length(len); + pkt.set_ttl(128); + // TODO make the ID a random value + pkt.set_identification(256); + pkt.set_fragment_offset(0); + pkt.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment); } #[macro_export] macro_rules! extract_address { - (set_source, $value:expr) => {{ - $value - }}; - (set_destination, $value:expr) => {{ - $value - }}; - ($func:ident, $value:expr) => {{ - println!("Unexpected case matched in extract_address: {} {}", stringify!($func), stringify!($value)); - ipv4::DEFAULT_SOURCE - }}; + (set_source, $value:expr) => {{ + $value + }}; + (set_destination, $value:expr) => {{ + $value + }}; + ($func:ident, $value:expr) => {{ + println!( + "Unexpected case matched in extract_address: {} {}", + stringify!($func), + stringify!($value) + ); + $crate::ipv4::DEFAULT_SOURCE + }}; } - #[macro_export] macro_rules! ipv4 { - ({$($func:ident => $value:expr), *}, $l4_pkt:expr, $protocol:expr, $buf:expr) => {{ - - let total_len = ipv4::IPV4_HEADER_LEN + $l4_pkt.packet().len(); - let mut source = ipv4::DEFAULT_SOURCE; - let mut dest = ipv4::DEFAULT_DESTINATION; - // Get the source/destination IP addresses so we can set the L4 checksum before - // creating the MutableIpv4Packet which is another mutable reference to the packet buffer. - // Once the MutableIpv4Packet is created we can't use $l4_pkt or we will get borrow errors. - $( + ({$($func:ident => $value:expr), *}, $l4_pkt:expr, $protocol:expr, $buf:expr) => {{ + let total_len = $crate::ipv4::IPV4_HEADER_LEN + $l4_pkt.packet().len(); + let mut source = $crate::ipv4::DEFAULT_SOURCE; + let mut dest = $crate::ipv4::DEFAULT_DESTINATION; + // Get the source/destination IP addresses so we can set the L4 checksum before + // creating the MutableIpv4Packet which is another mutable reference to the packet buffer. + // Once the MutableIpv4Packet is created we can't use $l4_pkt or we will get borrow errors. + $( // If we only used this match without calling the extract_address macro, the compiler can't // determine which func/value combos apply to which branch of the match and it assume they // can all match which will cause type errors. The extract_address macro avoids this // problem. match stringify!($func) { - "set_source" => source = extract_address!($func, $value), - "set_destination" => dest = extract_address!($func, $value), - _ => (), + "set_source" => source = $crate::extract_address!($func, $value), + "set_destination" => dest = $crate::extract_address!($func, $value), + _ => (), } - )* + )* - $l4_pkt.checksum_ipv4(&source, &dest); - let buf_len = $buf.len(); - let mut pkt = pnet::packet::ipv4::MutableIpv4Packet::new(&mut $buf[buf_len - total_len..]).unwrap(); - pkt.set_next_level_protocol($protocol); - ipv4::init_ipv4_pkt(&mut pkt, total_len as u16); - $( - pkt.$func($value); - )* - pkt.set_checksum(pnet::packet::ipv4::checksum(&pkt.to_immutable())); + $crate::L4Checksum::checksum_ipv4(&mut $l4_pkt, &source, &dest); + let buf_len = $buf.len(); + let mut pkt = pnet::packet::ipv4::MutableIpv4Packet::new(&mut $buf[buf_len - total_len..]).unwrap(); + pkt.set_next_level_protocol($protocol); + $crate::ipv4::init_ipv4_pkt(&mut pkt, total_len as u16); + $( + pkt.$func($value); + )* + pkt.set_checksum(pnet::packet::ipv4::checksum(&pkt.to_immutable())); - (pkt, pnet::packet::ethernet::EtherTypes::Ipv4) - }}; + (pkt, pnet::packet::ethernet::EtherTypes::Ipv4) + }}; } - #[macro_export] macro_rules! ipv4addr { - ($addr_str:expr) => {{ - $addr_str.parse().unwrap() - }}; + ($addr_str:expr) => {{ + $addr_str.parse().unwrap() + }}; } #[cfg(test)] mod tests { - use pnet::packet::Packet; - use pnet::packet::ethernet::EtherTypes::Ipv4; - use L4Checksum; - use ::payload; - use payload::PayloadData; - use ipv4; + use pnet::packet::{ethernet::EtherTypes::Ipv4, Packet}; - #[test] - fn macro_ipv4_basic() { - let mut buf = [0; 25]; - let (pkt, proto) = ipv4!({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("192.168.1.1"), set_version => 4}, + use crate::payload; + + #[test] + fn macro_ipv4_basic() { + let mut buf = [0; 25]; + let (pkt, proto) = ipv4!({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("192.168.1.1"), set_version => 4}, payload!({"hello".to_string().into_bytes()}, buf).0, pnet::packet::ip::IpNextHeaderProtocols::Udp, buf); - assert_eq!(proto, Ipv4); + assert_eq!(proto, Ipv4); - let buf_expected = vec![0; 25]; - let mut pkt_expected = pnet::packet::ipv4::MutableIpv4Packet::owned(buf_expected).unwrap(); - pkt_expected.set_destination(ipv4addr!("192.168.1.1")); - pkt_expected.set_source(ipv4addr!("127.0.0.1")); - pkt_expected.set_version(4); - pkt_expected.set_header_length(5); - pkt_expected.set_total_length(25); - pkt_expected.set_payload(&"hello".to_string().into_bytes()); - pkt_expected.set_ttl(128); - pkt_expected.set_identification(256); - pkt_expected.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment); - pkt_expected.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Udp); - pkt_expected.set_checksum(pnet::packet::ipv4::checksum(&pkt_expected.to_immutable())); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } + let buf_expected = vec![0; 25]; + let mut pkt_expected = pnet::packet::ipv4::MutableIpv4Packet::owned(buf_expected).unwrap(); + pkt_expected.set_destination(ipv4addr!("192.168.1.1")); + pkt_expected.set_source(ipv4addr!("127.0.0.1")); + pkt_expected.set_version(4); + pkt_expected.set_header_length(5); + pkt_expected.set_total_length(25); + pkt_expected.set_payload(&"hello".to_string().into_bytes()); + pkt_expected.set_ttl(128); + pkt_expected.set_identification(256); + pkt_expected.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment); + pkt_expected.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Udp); + pkt_expected.set_checksum(pnet::packet::ipv4::checksum(&pkt_expected.to_immutable())); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } } - diff --git a/src/lib.rs b/src/lib.rs index 475a7bc..dce260f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,63 +1,130 @@ -#![macro_use] -#![allow(unused_macros)] - -extern crate derive_new; -extern crate ipnetwork; -extern crate pnet; - +pub mod arp; +pub mod ethernet; pub mod icmp; +pub mod ipv4; +pub mod payload; pub mod tcp; pub mod udp; -pub mod ethernet; -pub mod arp; pub mod vlan; -pub mod ipv4; -pub mod payload; use std::net::Ipv4Addr; pub trait L4Checksum { - fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) -> (); + fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr); } #[macro_export] macro_rules! build_channel { - ($ifname:expr) => {{ - let interfaces = pnet_datalink::interfaces(); - let interface = interfaces - .into_iter() - .find(|iface| iface.name == $ifname) - .unwrap(); - - let (sender, receiver) = match pnet_datalink::channel(&interface, Default::default()) { - Ok(pnet_datalink::Channel::Ethernet(tx, rx)) => (tx, rx), - Ok(_) => panic!("Unknown channel type"), - Err(e) => panic!("Error happened {}", e), - }; - (sender, receiver) - }}; -} + ($ifname:expr) => {{ + let interfaces = pnet_datalink::interfaces(); + let interface = interfaces + .into_iter() + .find(|iface| iface.name == $ifname) + .unwrap(); + let (sender, receiver) = match pnet_datalink::channel(&interface, Default::default()) { + Ok(pnet_datalink::Channel::Ethernet(tx, rx)) => (tx, rx), + Ok(_) => panic!("Unknown channel type"), + Err(e) => panic!("Error happened {}", e), + }; + (sender, receiver) + }}; +} #[macro_export] macro_rules! sub_builder { ($pkt_buf:expr, $build_macro:ident($args:tt) $(/ $rem_macros:ident($rem_args:tt))+) => {{ - let (mut payload_pkt, _payload_proto) = sub_builder!($pkt_buf, $($rem_macros($rem_args) )/ *); - let (pkt, proto) = $build_macro!($args, payload_pkt, _payload_proto, $pkt_buf); - (pkt, proto) - }}; - ($pkt_buf:expr, $build_macro:ident($args:tt)) => {{ - $build_macro!($args, $pkt_buf) - }}; + #[allow(unused_mut)] + let (mut payload_pkt, _payload_proto) = sub_builder!($pkt_buf, $($rem_macros($rem_args) )/ *); + let (pkt, proto) = $build_macro!($args, payload_pkt, _payload_proto, $pkt_buf); + (pkt, proto) + }}; + ($pkt_buf:expr, $build_macro:ident($args:tt)) => {{ + $build_macro!($args, $pkt_buf) + }}; } // Call the sub builder so we can return just the packet rather than the tuple that gets returned // by the sub builder for use during the recursion. #[macro_export] macro_rules! packet_builder { - ($pkt_buf:expr, $( $rem_macros:ident($rem_args:tt))/ * ) => {{ - let (pkt, _proto) = sub_builder!($pkt_buf, $( $rem_macros($rem_args) )/ *); - pkt - }}; + ($pkt_buf:expr, $( $rem_macros:ident($rem_args:tt))/ * ) => {{ + let (pkt, _proto) = sub_builder!($pkt_buf, $( $rem_macros($rem_args) )/ *); + pkt + }}; } +#[cfg(test)] +mod test { + use pnet::packet::{ + icmp::IcmpTypes, + tcp::{TcpFlags, TcpOption}, + Packet, + }; + use pnet_datalink::MacAddr; + + use crate::{ether, icmp_dest_unreach, icmp_echo_req, ipv4, ipv4addr, payload, tcp, udp, vlan}; + + #[test] + fn can_build_example_1() { + let mut pkt_buf = [0u8; 1500]; + let _pkt = packet_builder!( + pkt_buf, + ether({set_source => MacAddr(10,1,1,1,1,1)}) / + ipv4({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("127.0.0.1") }) / + icmp_dest_unreach({set_icmp_type => IcmpTypes::DestinationUnreachable}) / + ipv4({set_source => ipv4addr!("10.8.0.1"), set_destination => ipv4addr!("127.0.0.1") }) / + udp({set_source => 53, set_destination => 5353}) / + payload({"hello".to_string().into_bytes()}) + ); + } + + #[test] + fn can_build_example_2() { + let mut pkt_buf = [0u8; 1500]; + let _pkt = packet_builder!( + pkt_buf, + ether({set_destination => MacAddr(1,2,3,4,5,6), set_source => MacAddr(10,1,1,1,1,1)}) / + ipv4({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("127.0.0.1") }) / + tcp({set_source => 43455, set_destination => 80, set_flags => (TcpFlags::PSH | TcpFlags::ACK)}) / + payload({"hello".to_string().into_bytes()}) + ); + } + + #[test] + fn can_build_example_3() { + let mut pkt_buf = [0u8; 1500]; + let _pkt = packet_builder!( + pkt_buf, + ether({set_destination => MacAddr(1,2,3,4,5,6), set_source => MacAddr(10,1,1,1,1,1)}) / + vlan({set_vlan_identifier => 10}) / + ipv4({set_source => ipv4addr!("192.168.1.1"), set_destination => ipv4addr!("127.0.0.1") }) / + tcp({set_source => 43455, set_destination => 80, set_options => &[TcpOption::mss(1200), TcpOption::wscale(2)]}) / + payload({[0; 0]}) + ); + } + + #[test] + fn can_build_example_4() { + let mut pkt_buf = [0u8; 1500]; + let _pkt = packet_builder!( + pkt_buf, + ether({set_destination => MacAddr(1,2,3,4,5,6), set_source => MacAddr(10,1,1,1,1,1)}) / + ipv4({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("127.0.0.1") }) / + udp({set_source => 12312, set_destination => 143}) / + payload({"hello".to_string().into_bytes()}) + ); + } + + #[test] + fn can_build_example_5() { + let mut pkt_buf = [0u8; 1500]; + let _pkt = packet_builder!( + pkt_buf, + ether({set_destination => MacAddr(1,2,3,4,5,6), set_source => MacAddr(10,1,1,1,1,1)}) / + ipv4({set_source => ipv4addr!("127.0.0.1"), set_destination => ipv4addr!("127.0.0.1") }) / + icmp_echo_req({set_icmp_type => IcmpTypes::EchoRequest}) / + payload({"hello".to_string().into_bytes()}) + ); + } +} diff --git a/src/payload.rs b/src/payload.rs index ea63f27..9ac45e9 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -1,34 +1,36 @@ use std::net::Ipv4Addr; -use L4Checksum; -impl <'p>L4Checksum for PayloadData<'p> { - fn checksum_ipv4(&mut self, _source: &Ipv4Addr, _destination: &Ipv4Addr) -> () { - // The payload has no checksum we just need to implement the trait. - } +use crate::L4Checksum; + +impl<'p> L4Checksum for PayloadData<'p> { + fn checksum_ipv4(&mut self, _source: &Ipv4Addr, _destination: &Ipv4Addr) { + // The payload has no checksum we just need to implement the trait. + } } pub struct PayloadData<'p> { - pub data: &'p mut[u8], + pub data: &'p mut [u8], } // Implement the pnet Packet trait so we can use the same interface in the macro for getting the // data. -impl <'p>pnet::packet::Packet for PayloadData<'p> { - fn packet(& self) -> & [u8] { &self.data[..] } - fn payload(& self) -> & [u8] { &self.data[..] } +impl<'p> pnet::packet::Packet for PayloadData<'p> { + fn packet(&self) -> &[u8] { + self.data + } + fn payload(&self) -> &[u8] { + self.data + } } #[macro_export] macro_rules! payload { - ($value:expr, $buf:expr) => {{ - let buf_len = $buf.len(); - let pdata = PayloadData { - data : &mut$buf[buf_len - $value.len()..], - }; - for i in 0..$value.len() { - pdata.data[i] = $value[i]; - } - (pdata, None as Option<&u16>) - }}; + ($value:expr, $buf:expr) => {{ + let buf_len = $buf.len(); + let pdata = $crate::payload::PayloadData { data: &mut$buf[buf_len - $value.len()..] }; + for i in 0..$value.len() { + pdata.data[i] = $value[i]; + } + (pdata, None as Option<&u16>) + }}; } - diff --git a/src/tcp.rs b/src/tcp.rs index 68e2051..0266cc4 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -1,44 +1,49 @@ -use pnet::packet::tcp::{MutableTcpPacket}; -use pnet::packet::tcp::ipv4_checksum as ipv4_tcp_checksum; use std::net::Ipv4Addr; -use pnet::packet::tcp::{TcpOption, TcpOptionPacket}; -use L4Checksum; -impl <'p>L4Checksum for MutableTcpPacket<'p> { - fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) -> () { - self.set_checksum(ipv4_tcp_checksum(&self.to_immutable(), source, destination)); - } +use pnet::packet::tcp::{ + ipv4_checksum as ipv4_tcp_checksum, MutableTcpPacket, TcpOption, TcpOptionPacket, +}; + +use crate::L4Checksum; + +impl<'p> L4Checksum for MutableTcpPacket<'p> { + fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) { + self.set_checksum(ipv4_tcp_checksum(&self.to_immutable(), source, destination)); + } } -/// Calculate the length (in double words) of an array of TcpOption structs +/// Calculate the length (in double words) of an array of TcpOption structs pub fn get_options_len(vals: &[TcpOption]) -> u8 { - let mut len = 0; - for opt in vals.iter() { - len += TcpOptionPacket::packet_size(&opt); - } + let mut len = 0; + for opt in vals.iter() { + len += TcpOptionPacket::packet_size(opt); + } - match len { - 0 => 0, - _ => { - let mut ret = len / 4; - ret += 1; - ret as u8 + match len { + 0 => 0, + _ => { + let mut ret = len / 4; + ret += 1; + ret as u8 + } } - } } #[macro_export] macro_rules! extract_options_len { - (set_options, $value:expr) => {{ - tcp::get_options_len($value) - }}; - ($func:ident, $value:expr) => {{ - println!("Unexpected case matched in extract_set_options: {} {}", stringify!($func), stringify!($value)); - 0 - }}; + (set_options, $value:expr) => {{ + tcp::get_options_len($value) + }}; + ($func:ident, $value:expr) => {{ + println!( + "Unexpected case matched in extract_set_options: {} {}", + stringify!($func), + stringify!($value) + ); + 0 + }}; } - #[macro_export] macro_rules! tcp { ({$($func:ident => $value:expr), *}, $payload_pkt:expr, $protocol:expr, $buf:expr) => {{ @@ -48,7 +53,7 @@ macro_rules! tcp { $( match stringify!($func) { "set_options" => { - opts_len = extract_options_len!($func, $value); + opts_len = $crate::extract_options_len!($func, $value); } _ => (), } @@ -72,32 +77,29 @@ macro_rules! tcp { #[cfg(test)] mod tests { - use pnet::packet::Packet; - use ::payload; - use payload::PayloadData; - use tcp; - use pnet::packet::tcp::TcpOption; + use pnet::packet::{tcp::TcpOption, Packet}; + + use crate::{payload, tcp}; - #[test] - fn macro_tcp_basic() { - let mut buf = [0; 33]; - let (pkt, proto) = tcp!({set_source => 53, set_destination => 5353, set_options => &vec!(TcpOption::mss(1200), TcpOption::wscale(2))}, + #[test] + fn macro_tcp_basic() { + let mut buf = [0; 33]; + let (pkt, proto) = tcp!({set_source => 53, set_destination => 5353, set_options => &[TcpOption::mss(1200), TcpOption::wscale(2)]}, payload!({"hello".to_string().into_bytes()}, buf).0, None, buf); - assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Tcp); + assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Tcp); - let buf_expected = vec![0; 33]; - let mut pkt_expected = pnet::packet::tcp::MutableTcpPacket::owned(buf_expected).unwrap(); - pkt_expected.set_destination(5353); - pkt_expected.set_source(53); - pkt_expected.set_data_offset(7); - pkt_expected.set_payload(&"hello".to_string().into_bytes()); - pkt_expected.set_options(&vec!(TcpOption::mss(1200), TcpOption::wscale(2))); - pkt_expected.set_flags(pnet::packet::tcp::TcpFlags::SYN); - pkt_expected.set_sequence(0); - pkt_expected.set_acknowledgement(0); - pkt_expected.set_urgent_ptr(0); - pkt_expected.set_window(65535); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } + let buf_expected = vec![0; 33]; + let mut pkt_expected = pnet::packet::tcp::MutableTcpPacket::owned(buf_expected).unwrap(); + pkt_expected.set_destination(5353); + pkt_expected.set_source(53); + pkt_expected.set_data_offset(7); + pkt_expected.set_payload(&"hello".to_string().into_bytes()); + pkt_expected.set_options(&[TcpOption::mss(1200), TcpOption::wscale(2)]); + pkt_expected.set_flags(pnet::packet::tcp::TcpFlags::SYN); + pkt_expected.set_sequence(0); + pkt_expected.set_acknowledgement(0); + pkt_expected.set_urgent_ptr(0); + pkt_expected.set_window(65535); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } } - diff --git a/src/udp.rs b/src/udp.rs index 45dcd5a..f09d410 100644 --- a/src/udp.rs +++ b/src/udp.rs @@ -1,12 +1,13 @@ -use pnet::packet::udp::{MutableUdpPacket}; -use pnet::packet::udp::ipv4_checksum as ipv4_udp_checksum; use std::net::Ipv4Addr; -use L4Checksum; -impl <'p>L4Checksum for MutableUdpPacket<'p> { - fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) -> () { - self.set_checksum(ipv4_udp_checksum(&self.to_immutable(), source, destination)); - } +use pnet::packet::udp::{ipv4_checksum as ipv4_udp_checksum, MutableUdpPacket}; + +use crate::L4Checksum; + +impl<'p> L4Checksum for MutableUdpPacket<'p> { + fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) { + self.set_checksum(ipv4_udp_checksum(&self.to_immutable(), source, destination)); + } } #[macro_export] @@ -28,25 +29,23 @@ macro_rules! udp { #[cfg(test)] mod tests { - use pnet::packet::Packet; - use ::payload; - use payload::PayloadData; - use udp; - - #[test] - fn macro_udp_basic() { - let mut buf = [0; 13]; - let (pkt, proto) = udp!({set_source => 53, set_destination => 5353}, + use pnet::packet::Packet; + + use crate::{payload, udp}; + + #[test] + fn macro_udp_basic() { + let mut buf = [0; 13]; + let (pkt, proto) = udp!({set_source => 53, set_destination => 5353}, payload!({"hello".to_string().into_bytes()}, buf).0, None, buf); - assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Udp); - - let buf_expected = vec![0; 13]; - let mut pkt_expected = pnet::packet::udp::MutableUdpPacket::owned(buf_expected).unwrap(); - pkt_expected.set_destination(5353); - pkt_expected.set_source(53); - pkt_expected.set_length(13 as u16); - pkt_expected.set_payload(&"hello".to_string().into_bytes()); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } -} + assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Udp); + let buf_expected = vec![0; 13]; + let mut pkt_expected = pnet::packet::udp::MutableUdpPacket::owned(buf_expected).unwrap(); + pkt_expected.set_destination(5353); + pkt_expected.set_source(53); + pkt_expected.set_length(13); + pkt_expected.set_payload(&"hello".to_string().into_bytes()); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } +} diff --git a/src/vlan.rs b/src/vlan.rs index bde4e6d..e9f91cd 100644 --- a/src/vlan.rs +++ b/src/vlan.rs @@ -1,5 +1,3 @@ - - #[macro_export] macro_rules! vlan { ({$($func:ident => $value:expr), *}, $payload_pkt:expr, $protocol:expr, $buf:expr) => {{ @@ -7,7 +5,7 @@ macro_rules! vlan { let total_len = VLAN_HEADER_LEN + $payload_pkt.packet().len(); let buf_len = $buf.len(); let mut pkt = pnet::packet::vlan::MutableVlanPacket::new(&mut $buf[buf_len - total_len..]).unwrap(); - pkt.set_ethertype($protocol); + pkt.set_ethertype($protocol); pkt.set_vlan_identifier(0); pkt.set_priority_code_point(pnet::packet::vlan::ClassesOfService::BE); pkt.set_drop_eligible_indicator(0); @@ -20,24 +18,23 @@ macro_rules! vlan { #[cfg(test)] mod tests { - use pnet::packet::Packet; - use ::payload; - use payload::PayloadData; + use pnet::packet::Packet; - #[test] - fn macro_vlan_basic() { - let mut buf = [0; 4]; - let (pkt, proto) = vlan!({set_vlan_identifier => 10, set_drop_eligible_indicator => 2}, + use crate::payload; + + #[test] + fn macro_vlan_basic() { + let mut buf = [0; 4]; + let (pkt, proto) = vlan!({set_vlan_identifier => 10, set_drop_eligible_indicator => 2}, payload!({[0; 0]}, buf).0, pnet::packet::ethernet::EtherTypes::Ipv4, buf); - assert_eq!(proto, pnet::packet::ethernet::EtherTypes::Vlan); + assert_eq!(proto, pnet::packet::ethernet::EtherTypes::Vlan); - let buf_expected = vec![0; 4]; - let mut pkt_expected = pnet::packet::vlan::MutableVlanPacket::owned(buf_expected).unwrap(); - pkt_expected.set_ethertype(pnet::packet::ethernet::EtherTypes::Ipv4); - pkt_expected.set_vlan_identifier(10); - pkt_expected.set_priority_code_point(pnet::packet::vlan::ClassesOfService::BE); - pkt_expected.set_drop_eligible_indicator(2); - assert_eq!(pkt_expected.packet(), pkt.packet()); - } + let buf_expected = vec![0; 4]; + let mut pkt_expected = pnet::packet::vlan::MutableVlanPacket::owned(buf_expected).unwrap(); + pkt_expected.set_ethertype(pnet::packet::ethernet::EtherTypes::Ipv4); + pkt_expected.set_vlan_identifier(10); + pkt_expected.set_priority_code_point(pnet::packet::vlan::ClassesOfService::BE); + pkt_expected.set_drop_eligible_indicator(2); + assert_eq!(pkt_expected.packet(), pkt.packet()); + } } -