use etherparse::PacketBuilder;
use std::io;
use std::net::Ipv4Addr;
pub fn write_udp_header_for(
data: &[u8],
src_addr: Ipv4Addr,
src_mac: [u8; 6],
src_port: u16,
dst_addr: Ipv4Addr,
dst_mac: [u8; 6],
dst_port: u16,
) -> io::Result<[u8; 42]> {
let mut hdr = [0u8; 42];
let builder = PacketBuilder::
ethernet2(src_mac, dst_mac)
.ipv4(src_addr.octets(), dst_addr.octets(), 64) .udp(src_port, dst_port);
match builder.write(&mut HdrWrite(&mut hdr, 0), data) {
Ok(_) => Ok(hdr),
Err(e) => Err(io::Error::other(format!(
"Error writing packet header: {e}",
))),
}
}
pub struct HdrWrite<'a>(
pub &'a mut [u8; 42],
pub usize,
);
impl io::Write for HdrWrite<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
if self.1 < 42 {
let len = buf.len().min(self.0.len() - self.1);
self.0[self.1..self.1 + len].copy_from_slice(&buf[..len]);
}
self.1 += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::HdrWrite;
use std::io::Write;
use std::net::Ipv4Addr;
#[test]
fn test_write_udp_header() {
let src_addr = Ipv4Addr::new(192, 168, 1, 1);
let dst_addr = Ipv4Addr::new(192, 168, 1, 2);
let src_mac = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
let dst_mac = [0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb];
let src_port = 12345;
let dst_port = 54321;
let data = b"Hello, XDP!";
let hdr = super::write_udp_header_for(
data, src_addr, src_mac, src_port, dst_addr, dst_mac, dst_port,
)
.unwrap();
assert_eq!(hdr.len(), 42);
let mut buf = [0u8; 42 + 11];
buf[..42].clone_from_slice(&hdr);
buf[42..].copy_from_slice(data);
match etherparse::SlicedPacket::from_ethernet(&buf) {
Ok(packet) => match packet.transport {
Some(etherparse::TransportSlice::Udp(_udp)) => {}
_ => panic!("Not udp packet"),
},
Err(e) => panic!("Failed to parse packet: {}", e),
};
}
#[test]
fn test_hdrwrite() {
let mut hdr = [0u8; 42];
let data = b"Test data";
let written = {
let mut writer = HdrWrite(&mut hdr, 0);
writer.write(data).unwrap()
};
assert_eq!(written, data.len());
assert_eq!(&hdr[..written], data);
let data = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTest data";
let written = {
let mut writer = HdrWrite(&mut hdr, 0);
writer.write(data).unwrap()
};
assert_eq!(written, data.len());
assert_eq!(&hdr[..], &data[..42]);
}
}