pub mod v4;
pub mod v6;
use crate::packets::checksum::PseudoHeader;
use crate::packets::Packet;
use anyhow::Result;
use std::fmt;
use std::net::{IpAddr, Ipv4Addr};
pub const DEFAULT_IP_TTL: u8 = 64;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(C, packed)]
pub struct ProtocolNumber(pub u8);
impl ProtocolNumber {
pub fn new(value: u8) -> Self {
ProtocolNumber(value)
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ProtocolNumbers {
use super::ProtocolNumber;
pub const Tcp: ProtocolNumber = ProtocolNumber(0x06);
pub const Udp: ProtocolNumber = ProtocolNumber(0x11);
pub const Ipv6Route: ProtocolNumber = ProtocolNumber(0x2B);
pub const Ipv6Frag: ProtocolNumber = ProtocolNumber(0x2C);
pub const Icmpv6: ProtocolNumber = ProtocolNumber(0x3A);
pub const Icmpv4: ProtocolNumber = ProtocolNumber(0x01);
}
impl fmt::Display for ProtocolNumber {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
ProtocolNumbers::Tcp => "TCP".to_string(),
ProtocolNumbers::Udp => "UDP".to_string(),
ProtocolNumbers::Ipv6Route => "IPv6 Route".to_string(),
ProtocolNumbers::Ipv6Frag => "IPv6 Frag".to_string(),
ProtocolNumbers::Icmpv6 => "ICMPv6".to_string(),
ProtocolNumbers::Icmpv4 => "ICMPv4".to_string(),
_ => format!("0x{:02x}", self.0),
}
)
}
}
pub trait IpPacket: Packet {
fn next_protocol(&self) -> ProtocolNumber;
fn set_next_protocol(&mut self, proto: ProtocolNumber);
fn src(&self) -> IpAddr;
fn set_src(&mut self, src: IpAddr) -> Result<()>;
fn dst(&self) -> IpAddr;
fn set_dst(&mut self, dst: IpAddr) -> Result<()>;
fn pseudo_header(&self, packet_len: u16, protocol: ProtocolNumber) -> PseudoHeader;
fn truncate(&mut self, mtu: usize) -> Result<()>;
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
#[repr(C, packed)]
pub struct Flow {
src_ip: IpAddr,
dst_ip: IpAddr,
src_port: u16,
dst_port: u16,
protocol: ProtocolNumber,
}
impl Default for Flow {
fn default() -> Flow {
Flow {
src_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
dst_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
src_port: 0,
dst_port: 0,
protocol: ProtocolNumber::default(),
}
}
}
impl Flow {
pub fn new(
src_ip: IpAddr,
dst_ip: IpAddr,
src_port: u16,
dst_port: u16,
protocol: ProtocolNumber,
) -> Self {
Flow {
src_ip,
dst_ip,
src_port,
dst_port,
protocol,
}
}
#[inline]
pub fn src_ip(&self) -> IpAddr {
self.src_ip
}
#[inline]
pub fn set_src_ip(&mut self, src_ip: IpAddr) {
self.src_ip = src_ip
}
#[inline]
pub fn dst_ip(&self) -> IpAddr {
self.dst_ip
}
#[inline]
pub fn set_dst_ip(&mut self, dst_ip: IpAddr) {
self.dst_ip = dst_ip
}
#[inline]
pub fn src_port(&self) -> u16 {
self.src_port
}
#[inline]
pub fn set_src_port(&mut self, src_port: u16) {
self.src_port = src_port
}
#[inline]
pub fn dst_port(&self) -> u16 {
self.dst_port
}
#[inline]
pub fn set_dst_port(&mut self, dst_port: u16) {
self.dst_port = dst_port
}
#[inline]
pub fn protocol(&self) -> ProtocolNumber {
self.protocol
}
#[inline]
pub fn set_protocol(&mut self, protocol: ProtocolNumber) {
self.protocol = protocol
}
#[inline]
pub fn reverse(&self) -> Self {
Flow {
src_ip: self.dst_ip,
dst_ip: self.src_ip,
src_port: self.dst_port,
dst_port: self.src_port,
protocol: self.protocol,
}
}
}
impl fmt::Debug for Flow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("flow")
.field("src_ip", &format!("{}", self.src_ip()))
.field("src_port", &self.src_port())
.field("dst_ip", &format!("{}", self.dst_ip()))
.field("dst_port", &self.dst_port())
.field("protocol", &format!("{}", self.protocol()))
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn protocol_number_to_string() {
assert_eq!("TCP", ProtocolNumbers::Tcp.to_string());
assert_eq!("UDP", ProtocolNumbers::Udp.to_string());
assert_eq!("IPv6 Route", ProtocolNumbers::Ipv6Route.to_string());
assert_eq!("ICMPv6", ProtocolNumbers::Icmpv6.to_string());
assert_eq!("0x00", ProtocolNumber::new(0).to_string());
}
}