Initial commit.
This commit is contained in:
commit
0aa92d8021
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
113
Cargo.lock
generated
Normal file
113
Cargo.lock
generated
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dhcprs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eui48",
|
||||||
|
"libc",
|
||||||
|
"nix",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eui48"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "887418ac5e8d57c2e66e04bdc2fe15f9a5407be20b54a82c86bd0e368b709701"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
"rustc-serialize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.133"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-serialize"
|
||||||
|
version = "0.3.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "dhcprs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "A library for encoding and decoding DHCP/BOOTP packets"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "dhcprs"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nix = "0.25.0"
|
||||||
|
eui48 = "1.1.0"
|
||||||
|
libc = "0.2.133"
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2022 xnoe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# dhcprs
|
||||||
|
|
||||||
|
DHCP/BOOTP packet encode/decode library.
|
||||||
|
|
||||||
|
The purpose of this library is to provide an easy to use interface over
|
||||||
|
DHCP, BOOTP and UDP packets to enable the creation of programs that
|
||||||
|
make use of DHCP.
|
||||||
|
|
||||||
|
BOOTP specific functionality is provided by the `dhcprs::bootp` module.
|
||||||
|
DHCP specific functionality is provided by the `dhcprs::dhcp` module.
|
||||||
|
There is additionally simple UDP packet encode/decode provided by the `dhcprs::udpbuilder`.
|
192
src/bootp.rs
Normal file
192
src/bootp.rs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
use eui48::MacAddress;
|
||||||
|
|
||||||
|
// Raw BOOTP Packet.
|
||||||
|
// Total size: 546 bytes
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct RawBOOTPPacket {
|
||||||
|
// RFC951
|
||||||
|
op: u8, // OpCode
|
||||||
|
htype: u8, // Host Type
|
||||||
|
hlen: u8, // Host Length
|
||||||
|
hops: u8, // Hops
|
||||||
|
xid: u32, // Transaction ID
|
||||||
|
secs: u16, // Seconds since boot
|
||||||
|
flags: u16, // Unused in BOOTP, flags in DHCP
|
||||||
|
ciaddr: u32, // Client Address (provided by client)
|
||||||
|
yiaddr: u32, // Client Address (provided by server)
|
||||||
|
siaddr: u32, // Server Address
|
||||||
|
giaddr: u32, // Gateway Address
|
||||||
|
chaddr: [u8; 16], // Client Hardware (MAC) Address
|
||||||
|
sname: [u8; 64], // Server hostname, null terminated string
|
||||||
|
file: [u8; 128], // Boot file name, null terminated string
|
||||||
|
vend: [u8; 312], // Vendor specific data. In RFC2131, this is required to be 312 octets for DHCP.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawBOOTPPacket {
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts(self as *const Self as *const u8, 546) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum OpCode {
|
||||||
|
BOOTREQUEST,
|
||||||
|
BOOTREPLY,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for OpCode {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(item: u8) -> Result<Self, Self::Error> {
|
||||||
|
match item {
|
||||||
|
1 => Ok(Self::BOOTREQUEST),
|
||||||
|
2 => Ok(Self::BOOTREPLY),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<OpCode> for u8 {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(item: OpCode) -> Result<Self, Self::Error> {
|
||||||
|
match item {
|
||||||
|
OpCode::BOOTREQUEST => Ok(1),
|
||||||
|
OpCode::BOOTREPLY => Ok(2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Higher level BOOTP Packet representation
|
||||||
|
pub struct BOOTPPacket {
|
||||||
|
pub op: OpCode,
|
||||||
|
pub hops: u8,
|
||||||
|
pub xid: u32,
|
||||||
|
pub secs: u16,
|
||||||
|
pub flags: u16,
|
||||||
|
pub ciaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
pub yiaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
pub siaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
pub giaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
pub chaddr: MacAddress,
|
||||||
|
pub sname: [u8; 64],
|
||||||
|
pub file: [u8; 128],
|
||||||
|
vend: [u8; 312],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BOOTPPacket> for RawBOOTPPacket {
|
||||||
|
fn from(item: BOOTPPacket) -> Self {
|
||||||
|
let mut chaddr: [u8; 16] = [0; 16];
|
||||||
|
chaddr[..6].copy_from_slice(item.chaddr.as_bytes());
|
||||||
|
Self {
|
||||||
|
op: item.op.try_into().unwrap(),
|
||||||
|
htype: 1,
|
||||||
|
hlen: 6,
|
||||||
|
hops: item.hops,
|
||||||
|
xid: item.xid,
|
||||||
|
secs: item.secs,
|
||||||
|
flags: item.flags,
|
||||||
|
ciaddr: if item.ciaddr.is_some() {
|
||||||
|
item.ciaddr.unwrap().into()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
yiaddr: if item.yiaddr.is_some() {
|
||||||
|
item.yiaddr.unwrap().into()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
siaddr: if item.siaddr.is_some() {
|
||||||
|
item.siaddr.unwrap().into()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
giaddr: if item.giaddr.is_some() {
|
||||||
|
item.giaddr.unwrap().into()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
chaddr: chaddr,
|
||||||
|
sname: item.sname,
|
||||||
|
file: item.file,
|
||||||
|
vend: item.vend,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RawBOOTPPacket> for BOOTPPacket {
|
||||||
|
fn from(item: RawBOOTPPacket) -> Self {
|
||||||
|
Self {
|
||||||
|
op: item.op.try_into().unwrap(),
|
||||||
|
hops: item.hops,
|
||||||
|
xid: item.xid,
|
||||||
|
secs: item.secs,
|
||||||
|
flags: item.flags,
|
||||||
|
ciaddr: if item.ciaddr == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(std::net::Ipv4Addr::from(item.ciaddr))
|
||||||
|
},
|
||||||
|
yiaddr: if item.yiaddr == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(std::net::Ipv4Addr::from(item.yiaddr))
|
||||||
|
},
|
||||||
|
siaddr: if item.siaddr == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(std::net::Ipv4Addr::from(item.siaddr))
|
||||||
|
},
|
||||||
|
giaddr: if item.giaddr == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(std::net::Ipv4Addr::from(item.giaddr))
|
||||||
|
},
|
||||||
|
chaddr: MacAddress::from_bytes(&item.chaddr[0..6]).unwrap(),
|
||||||
|
sname: item.sname,
|
||||||
|
file: item.file,
|
||||||
|
vend: item.vend,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BOOTPPacket {
|
||||||
|
/// Create a new BOOTP packet.
|
||||||
|
///
|
||||||
|
/// dhcprs encourages the use of higher level interfaces which are then
|
||||||
|
/// converted to lower level (packed) structures that can be serialised
|
||||||
|
/// in to bytes and then sent down a socket.
|
||||||
|
pub fn new(
|
||||||
|
op: OpCode,
|
||||||
|
hops: u8,
|
||||||
|
xid: u32,
|
||||||
|
secs: u16,
|
||||||
|
flags: u16,
|
||||||
|
ciaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
yiaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
siaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
giaddr: Option<std::net::Ipv4Addr>,
|
||||||
|
chaddr: MacAddress,
|
||||||
|
sname: [u8; 64],
|
||||||
|
file: [u8; 128],
|
||||||
|
vend: [u8; 312],
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
op: op,
|
||||||
|
hops: hops,
|
||||||
|
xid: xid,
|
||||||
|
secs: secs,
|
||||||
|
flags: flags,
|
||||||
|
ciaddr: ciaddr,
|
||||||
|
yiaddr: yiaddr,
|
||||||
|
siaddr: siaddr,
|
||||||
|
giaddr: giaddr,
|
||||||
|
chaddr: chaddr,
|
||||||
|
sname: sname,
|
||||||
|
file: file,
|
||||||
|
vend: vend,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_vend(&self) -> &[u8] {
|
||||||
|
return &self.vend;
|
||||||
|
}
|
||||||
|
}
|
1809
src/dhcp.rs
Normal file
1809
src/dhcp.rs
Normal file
File diff suppressed because it is too large
Load Diff
15
src/lib.rs
Normal file
15
src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//! DHCP/BOOTP packet encode/decode library.
|
||||||
|
//!
|
||||||
|
//! The purpose of this library is to provide an easy to use interface over
|
||||||
|
//! DHCP, BOOTP and UDP packets to enable the creation of programs that
|
||||||
|
//! make use of DHCP.
|
||||||
|
//!
|
||||||
|
//! BOOTP specific functionality is provided by the `dhcprs::bootp` module
|
||||||
|
//! DHCP specific functionality is provided by the `dhcprs::dhcp` module
|
||||||
|
//!
|
||||||
|
//! There is additionally simple UDP packet encode/decode provided by the
|
||||||
|
//! `dhcprs::udpbuilder`.
|
||||||
|
|
||||||
|
pub mod bootp;
|
||||||
|
pub mod dhcp;
|
||||||
|
pub mod udpbuilder;
|
175
src/udpbuilder.rs
Normal file
175
src/udpbuilder.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct RawUDPPacket {
|
||||||
|
// IP Header
|
||||||
|
version_ihl: u8, // First 4 bits: Version (always 4), next 4 bits: Internet Header Length (Header size in u32s)
|
||||||
|
dscp_ecn: u8, // Differentiated Services Code Point / Explicit Congestion Notification, zero for our purposes
|
||||||
|
total_length: u16, // Total length of the IP header + UDP header + data
|
||||||
|
identification: u16, // Identification (for fragmentation purposes)
|
||||||
|
flags_fragment_offset: u16, // Flags and the fragment offset (0x4000 for DF)
|
||||||
|
ttl: u8, // Time to live
|
||||||
|
protocol: u8, // Proto (UDP is 0x11 / dec 17)
|
||||||
|
ip_checksum: u16, // Ones' complement of the ones' complement sum of all 16 bit words of the header
|
||||||
|
source_addr: u32, // Source address
|
||||||
|
dest_addr: u32, // Destination address
|
||||||
|
|
||||||
|
// UDP Header
|
||||||
|
source_port: u16, // Source port
|
||||||
|
dest_port: u16, // Destination port
|
||||||
|
length: u16, // Length of UDP Header + data
|
||||||
|
udp_checksum: u16, // Ones' complement of the ones' complement sum of all 16 bit words of the pseudoheader + udp header + data
|
||||||
|
|
||||||
|
// UDP Data
|
||||||
|
data: [u8; 546], // 546 byte array to store a RawBOOTPPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawUDPPacket {
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts(self as *const Self as *const u8, 574) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UDPPacket> for RawUDPPacket {
|
||||||
|
fn from(item: UDPPacket) -> Self {
|
||||||
|
let ph: PseudoHeader = item.clone().into();
|
||||||
|
let udp_checksum = ph.checksum();
|
||||||
|
|
||||||
|
let source_addr: u32 = item.source_addr.into();
|
||||||
|
let dest_addr: u32 = item.dest_addr.into();
|
||||||
|
|
||||||
|
let mut packet = Self {
|
||||||
|
version_ihl: 0x45, // Version 4, IHL of 5 (20 bytes)
|
||||||
|
dscp_ecn: 0, // No need for either DSCP or ECN
|
||||||
|
total_length: 574_u16.to_be(), // Will always be 576 bytes
|
||||||
|
identification: 0x1337, // No need (no fragmentation)
|
||||||
|
flags_fragment_offset: 0,
|
||||||
|
ttl: 64, // Set TTL to 255 because why not
|
||||||
|
protocol: 17, // UDP
|
||||||
|
ip_checksum: 0, // Zero for now, will be set later
|
||||||
|
source_addr: source_addr.to_be(),
|
||||||
|
dest_addr: dest_addr.to_be(),
|
||||||
|
source_port: item.source_port.to_be(),
|
||||||
|
dest_port: item.dest_port.to_be(),
|
||||||
|
length: ((item.data.len() + 8) as u16).to_be(),
|
||||||
|
udp_checksum: udp_checksum,
|
||||||
|
data: item.data,
|
||||||
|
};
|
||||||
|
|
||||||
|
let header_u16 =
|
||||||
|
unsafe { std::slice::from_raw_parts(&packet as *const Self as *const u16, 10) };
|
||||||
|
let mut total: u16 = 0;
|
||||||
|
for &word in header_u16 {
|
||||||
|
let (value, carry) = total.overflowing_add(word);
|
||||||
|
if carry {
|
||||||
|
total = value + 1;
|
||||||
|
} else {
|
||||||
|
total = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packet.ip_checksum = !total;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(packed)]
|
||||||
|
struct PseudoHeader {
|
||||||
|
source_addr: u32,
|
||||||
|
dest_addr: u32,
|
||||||
|
zero: u8,
|
||||||
|
protocol: u8,
|
||||||
|
udp_length: u16,
|
||||||
|
source_port: u16,
|
||||||
|
dest_port: u16,
|
||||||
|
udp_length2: u16,
|
||||||
|
udp_checksum: u16,
|
||||||
|
data: [u8; 546],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UDPPacket> for PseudoHeader {
|
||||||
|
fn from(item: UDPPacket) -> Self {
|
||||||
|
let source_addr: u32 = item.source_addr.into();
|
||||||
|
let dest_addr: u32 = item.dest_addr.into();
|
||||||
|
Self {
|
||||||
|
source_addr: source_addr.to_be(),
|
||||||
|
dest_addr: dest_addr.to_be(),
|
||||||
|
zero: 0,
|
||||||
|
protocol: 17,
|
||||||
|
udp_length: ((item.data.len() + 8) as u16).to_be(),
|
||||||
|
source_port: item.source_port.to_be(),
|
||||||
|
dest_port: item.dest_port.to_be(),
|
||||||
|
udp_length2: ((item.data.len() + 8) as u16).to_be(),
|
||||||
|
udp_checksum: 0,
|
||||||
|
data: item.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PseudoHeader {
|
||||||
|
pub fn checksum(&self) -> u16 {
|
||||||
|
let as_u16 = unsafe {
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
self as *const Self as *const u16,
|
||||||
|
(self.data.len() + 20) / 2,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut total: u16 = 0;
|
||||||
|
for &word in as_u16 {
|
||||||
|
let (value, carry) = total.overflowing_add(word);
|
||||||
|
if carry {
|
||||||
|
total = value + 1;
|
||||||
|
} else {
|
||||||
|
total = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UDPPacket {
|
||||||
|
pub source_addr: std::net::Ipv4Addr,
|
||||||
|
pub dest_addr: std::net::Ipv4Addr,
|
||||||
|
pub source_port: u16,
|
||||||
|
pub dest_port: u16,
|
||||||
|
data: [u8; 546],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RawUDPPacket> for UDPPacket {
|
||||||
|
fn from(item: RawUDPPacket) -> Self {
|
||||||
|
Self {
|
||||||
|
source_addr: std::net::Ipv4Addr::from(item.source_addr.to_be_bytes()),
|
||||||
|
dest_addr: std::net::Ipv4Addr::from(item.source_addr.to_be_bytes()),
|
||||||
|
source_port: u16::from_be(item.source_port),
|
||||||
|
dest_port: u16::from_be(item.dest_port),
|
||||||
|
data: item.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UDPPacket {
|
||||||
|
/// Creates a new UDPPacket
|
||||||
|
///
|
||||||
|
/// Should be converted to a `dhcprs::udpbuilder::RawUDPPacket` to send.
|
||||||
|
pub fn new(
|
||||||
|
source_addr: std::net::Ipv4Addr,
|
||||||
|
dest_addr: std::net::Ipv4Addr,
|
||||||
|
source_port: u16,
|
||||||
|
dest_port: u16,
|
||||||
|
data: [u8; 546],
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
source_addr: source_addr,
|
||||||
|
dest_addr: dest_addr,
|
||||||
|
source_port: source_port,
|
||||||
|
dest_port: dest_port,
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the payload of the UDP packet.
|
||||||
|
pub fn get_data(&self) -> &[u8] {
|
||||||
|
return &self.data;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user