2016-12-13 01:26:06 +08:00
|
|
|
use core::fmt;
|
2016-12-14 09:59:47 +08:00
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
use {Error, Result};
|
2016-12-26 19:20:20 +08:00
|
|
|
use super::{Ipv4Address, Ipv4Packet, Ipv4Repr};
|
2016-12-13 01:26:06 +08:00
|
|
|
|
2017-06-18 18:14:20 +08:00
|
|
|
/// Internet protocol version.
|
2017-06-26 14:06:08 +08:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub enum Version {
|
2017-07-30 10:00:23 +08:00
|
|
|
Unspecified,
|
2017-06-18 18:14:20 +08:00
|
|
|
Ipv4,
|
|
|
|
#[doc(hidden)]
|
|
|
|
__Nonexhaustive,
|
|
|
|
}
|
|
|
|
|
2017-07-30 10:00:23 +08:00
|
|
|
impl Version {
|
|
|
|
/// Return the version of an IP packet stored in the provided buffer.
|
|
|
|
///
|
|
|
|
/// This function never returns `Ok(IpVersion::Unspecified)`; instead,
|
|
|
|
/// unknown versions result in `Err(Error::Unrecognized)`.
|
|
|
|
pub fn of_packet(data: &[u8]) -> Result<Version> {
|
|
|
|
match data[0] >> 4 {
|
|
|
|
4 => Ok(Version::Ipv4),
|
|
|
|
_ => Err(Error::Unrecognized)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-18 18:14:20 +08:00
|
|
|
impl fmt::Display for Version {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2017-07-30 10:00:23 +08:00
|
|
|
&Version::Unspecified => write!(f, "IPv?"),
|
2017-06-18 18:14:20 +08:00
|
|
|
&Version::Ipv4 => write!(f, "IPv4"),
|
|
|
|
&Version::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 01:26:06 +08:00
|
|
|
enum_with_unknown! {
|
2017-06-18 18:14:20 +08:00
|
|
|
/// IP datagram encapsulated protocol.
|
2016-12-20 21:54:11 +08:00
|
|
|
pub enum Protocol(u8) {
|
2016-12-13 01:26:06 +08:00
|
|
|
Icmp = 0x01,
|
|
|
|
Tcp = 0x06,
|
|
|
|
Udp = 0x11
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 21:54:11 +08:00
|
|
|
impl fmt::Display for Protocol {
|
2016-12-13 01:26:06 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2016-12-20 21:54:11 +08:00
|
|
|
&Protocol::Icmp => write!(f, "ICMP"),
|
|
|
|
&Protocol::Tcp => write!(f, "TCP"),
|
|
|
|
&Protocol::Udp => write!(f, "UDP"),
|
|
|
|
&Protocol::Unknown(id) => write!(f, "0x{:02x}", id)
|
2016-12-13 01:26:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-13 06:11:52 +08:00
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
/// An internetworking address.
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
|
pub enum Address {
|
2016-12-21 03:51:52 +08:00
|
|
|
/// An unspecified address.
|
2016-12-14 09:59:47 +08:00
|
|
|
/// May be used as a placeholder for storage where the address is not assigned yet.
|
2016-12-21 03:51:52 +08:00
|
|
|
Unspecified,
|
2016-12-14 09:59:47 +08:00
|
|
|
/// An IPv4 address.
|
|
|
|
Ipv4(Ipv4Address)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Address {
|
|
|
|
/// Create an address wrapping an IPv4 address with the given octets.
|
2016-12-28 08:08:01 +08:00
|
|
|
pub fn v4(a0: u8, a1: u8, a2: u8, a3: u8) -> Address {
|
2016-12-31 19:44:51 +08:00
|
|
|
Address::Ipv4(Ipv4Address::new(a0, a1, a2, a3))
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Query whether the address is a valid unicast address.
|
|
|
|
pub fn is_unicast(&self) -> bool {
|
|
|
|
match self {
|
2016-12-21 03:51:52 +08:00
|
|
|
&Address::Unspecified => false,
|
|
|
|
&Address::Ipv4(addr) => addr.is_unicast()
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
}
|
2016-12-15 01:39:44 +08:00
|
|
|
|
2017-08-28 13:49:56 +08:00
|
|
|
/// Query whether the address is the broadcast address.
|
|
|
|
pub fn is_broadcast(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
&Address::Unspecified => false,
|
|
|
|
&Address::Ipv4(addr) => addr.is_broadcast()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-15 01:39:44 +08:00
|
|
|
/// Query whether the address falls into the "unspecified" range.
|
|
|
|
pub fn is_unspecified(&self) -> bool {
|
|
|
|
match self {
|
2016-12-21 03:51:52 +08:00
|
|
|
&Address::Unspecified => true,
|
|
|
|
&Address::Ipv4(addr) => addr.is_unspecified()
|
2016-12-15 01:39:44 +08:00
|
|
|
}
|
|
|
|
}
|
2017-07-24 07:07:55 +08:00
|
|
|
|
|
|
|
/// Return an unspecified address that has the same IP version as `self`.
|
2017-07-27 19:26:07 +08:00
|
|
|
pub fn to_unspecified(&self) -> Address {
|
2017-07-24 07:07:55 +08:00
|
|
|
match self {
|
|
|
|
&Address::Unspecified => Address::Unspecified,
|
|
|
|
// &Address::Ipv4 => Address::Ipv4(Ipv4Address::UNSPECIFIED),
|
|
|
|
&Address::Ipv4(_) => Address::Ipv4(Ipv4Address(/*FIXME*/[0x00; 4])),
|
|
|
|
}
|
|
|
|
}
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Address {
|
|
|
|
fn default() -> Address {
|
2016-12-21 03:51:52 +08:00
|
|
|
Address::Unspecified
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Ipv4Address> for Address {
|
|
|
|
fn from(addr: Ipv4Address) -> Self {
|
|
|
|
Address::Ipv4(addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Address {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2016-12-21 03:51:52 +08:00
|
|
|
&Address::Unspecified => write!(f, "*"),
|
|
|
|
&Address::Ipv4(addr) => write!(f, "{}", addr)
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-15 01:39:44 +08:00
|
|
|
/// An internet endpoint address.
|
2016-12-28 13:33:12 +08:00
|
|
|
///
|
|
|
|
/// An endpoint can be constructed from a port, in which case the address is unspecified.
|
2016-12-15 01:39:44 +08:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
|
|
|
pub struct Endpoint {
|
|
|
|
pub addr: Address,
|
|
|
|
pub port: u16
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Endpoint {
|
2016-12-28 08:12:15 +08:00
|
|
|
// pub const UNSPECIFIED: Endpoint = Endpoint { addr: Address::Unspecified, port: 0 };
|
2016-12-16 01:07:56 +08:00
|
|
|
|
2016-12-21 03:18:35 +08:00
|
|
|
/// Create an endpoint address from given address and port.
|
2016-12-28 08:08:01 +08:00
|
|
|
pub fn new(addr: Address, port: u16) -> Endpoint {
|
2016-12-15 01:39:44 +08:00
|
|
|
Endpoint { addr: addr, port: port }
|
|
|
|
}
|
2016-12-28 12:56:49 +08:00
|
|
|
|
2017-07-27 20:27:33 +08:00
|
|
|
/// Query whether the endpoint has a specified address and port.
|
|
|
|
pub fn is_specified(&self) -> bool {
|
|
|
|
!self.addr.is_unspecified() && self.port != 0
|
2016-12-28 12:56:49 +08:00
|
|
|
}
|
2016-12-15 01:39:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Endpoint {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}:{}", self.addr, self.port)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 13:33:12 +08:00
|
|
|
impl From<u16> for Endpoint {
|
|
|
|
fn from(port: u16) -> Endpoint {
|
|
|
|
Endpoint { addr: Address::Unspecified, port: port }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
impl<T: Into<Address>> From<(T, u16)> for Endpoint {
|
|
|
|
fn from((addr, port): (T, u16)) -> Endpoint {
|
|
|
|
Endpoint { addr: addr.into(), port: port }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
/// An IP packet representation.
|
|
|
|
///
|
|
|
|
/// This enum abstracts the various versions of IP packets. It either contains a concrete
|
|
|
|
/// high-level representation for some IP protocol version, or an unspecified representation,
|
|
|
|
/// which permits the `IpAddress::Unspecified` addresses.
|
2017-06-18 18:12:10 +08:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2016-12-26 19:20:20 +08:00
|
|
|
pub enum IpRepr {
|
|
|
|
Unspecified {
|
2017-01-14 19:07:06 +08:00
|
|
|
src_addr: Address,
|
|
|
|
dst_addr: Address,
|
|
|
|
protocol: Protocol,
|
|
|
|
payload_len: usize
|
2016-12-26 19:20:20 +08:00
|
|
|
},
|
|
|
|
Ipv4(Ipv4Repr),
|
|
|
|
#[doc(hidden)]
|
|
|
|
__Nonexhaustive
|
|
|
|
}
|
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
impl From<Ipv4Repr> for IpRepr {
|
|
|
|
fn from(repr: Ipv4Repr) -> IpRepr {
|
|
|
|
IpRepr::Ipv4(repr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
impl IpRepr {
|
2017-07-30 10:00:23 +08:00
|
|
|
/// Return the protocol version.
|
|
|
|
pub fn version(&self) -> Version {
|
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified { .. } => Version::Unspecified,
|
|
|
|
&IpRepr::Ipv4(_) => Version::Ipv4,
|
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
/// Return the source address.
|
|
|
|
pub fn src_addr(&self) -> Address {
|
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified { src_addr, .. } => src_addr,
|
|
|
|
&IpRepr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
|
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the destination address.
|
|
|
|
pub fn dst_addr(&self) -> Address {
|
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified { dst_addr, .. } => dst_addr,
|
|
|
|
&IpRepr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
|
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the protocol.
|
|
|
|
pub fn protocol(&self) -> Protocol {
|
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified { protocol, .. } => protocol,
|
|
|
|
&IpRepr::Ipv4(repr) => repr.protocol,
|
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-14 19:07:06 +08:00
|
|
|
/// Return the payload length.
|
|
|
|
pub fn payload_len(&self) -> usize {
|
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified { payload_len, .. } => payload_len,
|
|
|
|
&IpRepr::Ipv4(repr) => repr.payload_len,
|
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-22 18:14:26 +08:00
|
|
|
/// Set the payload length.
|
|
|
|
pub fn set_payload_len(&mut self, length: usize) {
|
|
|
|
match self {
|
|
|
|
&mut IpRepr::Unspecified { ref mut payload_len, .. } =>
|
|
|
|
*payload_len = length,
|
|
|
|
&mut IpRepr::Ipv4(Ipv4Repr { ref mut payload_len, .. }) =>
|
|
|
|
*payload_len = length,
|
|
|
|
&mut IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
/// Convert an unspecified representation into a concrete one, or return
|
|
|
|
/// `Err(Error::Unaddressable)` if not possible.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics if source and destination addresses belong to different families,
|
|
|
|
/// or the destination address is unspecified, since this indicates a logic error.
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn lower(&self, fallback_src_addrs: &[Address]) -> Result<IpRepr> {
|
2016-12-26 19:20:20 +08:00
|
|
|
match self {
|
|
|
|
&IpRepr::Unspecified {
|
|
|
|
src_addr: Address::Ipv4(src_addr),
|
|
|
|
dst_addr: Address::Ipv4(dst_addr),
|
2017-01-14 19:07:06 +08:00
|
|
|
protocol, payload_len
|
2016-12-26 19:20:20 +08:00
|
|
|
} => {
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr {
|
2017-01-14 19:07:06 +08:00
|
|
|
src_addr: src_addr,
|
|
|
|
dst_addr: dst_addr,
|
|
|
|
protocol: protocol,
|
|
|
|
payload_len: payload_len
|
2016-12-26 19:20:20 +08:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
&IpRepr::Unspecified {
|
|
|
|
src_addr: Address::Unspecified,
|
|
|
|
dst_addr: Address::Ipv4(dst_addr),
|
2017-01-14 19:07:06 +08:00
|
|
|
protocol, payload_len
|
2016-12-26 19:20:20 +08:00
|
|
|
} => {
|
|
|
|
let mut src_addr = None;
|
|
|
|
for addr in fallback_src_addrs {
|
|
|
|
match addr {
|
|
|
|
&Address::Ipv4(addr) => {
|
|
|
|
src_addr = Some(addr);
|
|
|
|
break
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr {
|
2017-06-25 00:34:32 +08:00
|
|
|
src_addr: src_addr.ok_or(Error::Unaddressable)?,
|
2017-01-14 19:07:06 +08:00
|
|
|
dst_addr: dst_addr,
|
|
|
|
protocol: protocol,
|
|
|
|
payload_len: payload_len
|
2016-12-26 19:20:20 +08:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
&IpRepr::Unspecified { dst_addr: Address::Unspecified, .. } =>
|
|
|
|
panic!("unspecified destination IP address"),
|
2017-06-18 18:12:10 +08:00
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
// &IpRepr::Unspecified { .. } =>
|
|
|
|
// panic!("source and destination IP address families do not match"),
|
|
|
|
|
2017-06-18 18:12:10 +08:00
|
|
|
&IpRepr::Ipv4(mut repr) => {
|
|
|
|
if repr.src_addr.is_unspecified() {
|
|
|
|
for addr in fallback_src_addrs {
|
|
|
|
match addr {
|
|
|
|
&Address::Ipv4(addr) => {
|
|
|
|
repr.src_addr = addr;
|
|
|
|
return Ok(IpRepr::Ipv4(repr));
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::Unaddressable)
|
|
|
|
} else {
|
|
|
|
Ok(IpRepr::Ipv4(repr))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-12-26 19:20:20 +08:00
|
|
|
&IpRepr::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the length of a header that will be emitted from this high-level representation.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics if invoked on an unspecified representation.
|
|
|
|
pub fn buffer_len(&self) -> usize {
|
|
|
|
match self {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
&IpRepr::Unspecified { .. } =>
|
|
|
|
panic!("unspecified IP representation"),
|
|
|
|
&IpRepr::Ipv4(repr) =>
|
|
|
|
repr.buffer_len(),
|
|
|
|
&IpRepr::__Nonexhaustive =>
|
|
|
|
unreachable!()
|
2016-12-26 19:20:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit this high-level representation into a buffer.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics if invoked on an unspecified representation.
|
2017-01-14 19:07:06 +08:00
|
|
|
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, buffer: T) {
|
2016-12-26 19:20:20 +08:00
|
|
|
match self {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
&IpRepr::Unspecified { .. } =>
|
|
|
|
panic!("unspecified IP representation"),
|
|
|
|
&IpRepr::Ipv4(repr) =>
|
|
|
|
repr.emit(&mut Ipv4Packet::new(buffer)),
|
|
|
|
&IpRepr::__Nonexhaustive =>
|
|
|
|
unreachable!()
|
2016-12-26 19:20:20 +08:00
|
|
|
}
|
|
|
|
}
|
2017-08-23 06:32:05 +08:00
|
|
|
|
|
|
|
/// Return the total length of a packet that will be emitted from this
|
|
|
|
/// high-level representation.
|
|
|
|
///
|
|
|
|
/// This is the same as `repr.buffer_len() + repr.payload_len()`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics if invoked on an unspecified representation.
|
|
|
|
pub fn total_len(&self) -> usize {
|
|
|
|
self.buffer_len() + self.payload_len()
|
|
|
|
}
|
2016-12-26 19:20:20 +08:00
|
|
|
}
|
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
pub mod checksum {
|
|
|
|
use byteorder::{ByteOrder, NetworkEndian};
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2016-12-28 02:43:49 +08:00
|
|
|
fn propagate_carries(word: u32) -> u16 {
|
|
|
|
let sum = (word >> 16) + (word & 0xffff);
|
|
|
|
((sum >> 16) as u16) + (sum as u16)
|
|
|
|
}
|
|
|
|
|
2016-12-14 09:59:47 +08:00
|
|
|
/// Compute an RFC 1071 compliant checksum (without the final complement).
|
|
|
|
pub fn data(data: &[u8]) -> u16 {
|
|
|
|
let mut accum: u32 = 0;
|
2016-12-28 08:05:31 +08:00
|
|
|
let mut i = 0;
|
|
|
|
while i < data.len() {
|
2016-12-20 08:17:29 +08:00
|
|
|
let word;
|
|
|
|
if i + 2 <= data.len() {
|
|
|
|
word = NetworkEndian::read_u16(&data[i..i + 2]) as u32
|
|
|
|
} else {
|
|
|
|
word = (data[i] as u32) << 8
|
|
|
|
}
|
2016-12-14 09:59:47 +08:00
|
|
|
accum += word;
|
2016-12-28 08:05:31 +08:00
|
|
|
i += 2;
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
2016-12-28 02:43:49 +08:00
|
|
|
propagate_carries(accum)
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Combine several RFC 1071 compliant checksums.
|
|
|
|
pub fn combine(checksums: &[u16]) -> u16 {
|
|
|
|
let mut accum: u32 = 0;
|
|
|
|
for &word in checksums {
|
|
|
|
accum += word as u32;
|
|
|
|
}
|
2016-12-28 02:43:49 +08:00
|
|
|
propagate_carries(accum)
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute an IP pseudo header checksum.
|
|
|
|
pub fn pseudo_header(src_addr: &Address, dst_addr: &Address,
|
2016-12-20 21:54:11 +08:00
|
|
|
protocol: Protocol, length: u32) -> u16 {
|
2016-12-14 09:59:47 +08:00
|
|
|
match (src_addr, dst_addr) {
|
|
|
|
(&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
|
|
|
|
let mut proto_len = [0u8; 4];
|
|
|
|
proto_len[1] = protocol.into();
|
|
|
|
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
|
|
|
|
|
|
|
|
combine(&[
|
|
|
|
data(src_addr.as_bytes()),
|
|
|
|
data(dst_addr.as_bytes()),
|
|
|
|
data(&proto_len[..])
|
|
|
|
])
|
|
|
|
},
|
|
|
|
|
2017-07-27 19:26:07 +08:00
|
|
|
_ => panic!("Unexpected pseudo header addresses: {}, {}",
|
|
|
|
src_addr, dst_addr)
|
2016-12-14 09:59:47 +08:00
|
|
|
}
|
2016-12-13 06:11:52 +08:00
|
|
|
}
|
|
|
|
}
|
2017-06-18 18:12:10 +08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
use wire::{Ipv4Address, IpProtocol, IpAddress, Ipv4Repr};
|
|
|
|
#[test]
|
|
|
|
fn ip_repr_lower() {
|
|
|
|
let ip_addr_a = Ipv4Address::new(1, 2, 3, 4);
|
|
|
|
let ip_addr_b = Ipv4Address::new(5, 6, 7, 8);
|
|
|
|
let proto = IpProtocol::Icmp;
|
|
|
|
let payload_len = 10;
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Unspecified{
|
|
|
|
src_addr: IpAddress::Ipv4(ip_addr_a),
|
|
|
|
dst_addr: IpAddress::Ipv4(ip_addr_b),
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}.lower(&[]),
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: ip_addr_a,
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}))
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Unspecified{
|
|
|
|
src_addr: IpAddress::Unspecified,
|
|
|
|
dst_addr: IpAddress::Ipv4(ip_addr_b),
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}.lower(&[]),
|
|
|
|
Err(Error::Unaddressable)
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Unspecified{
|
|
|
|
src_addr: IpAddress::Unspecified,
|
|
|
|
dst_addr: IpAddress::Ipv4(ip_addr_b),
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}.lower(&[IpAddress::Ipv4(ip_addr_a)]),
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: ip_addr_a,
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}))
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: ip_addr_a,
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}).lower(&[]),
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: ip_addr_a,
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}))
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: Ipv4Address::new(0, 0, 0, 0),
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}).lower(&[]),
|
|
|
|
Err(Error::Unaddressable)
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: Ipv4Address::new(0, 0, 0, 0),
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}).lower(&[IpAddress::Ipv4(ip_addr_a)]),
|
|
|
|
Ok(IpRepr::Ipv4(Ipv4Repr{
|
|
|
|
src_addr: ip_addr_a,
|
|
|
|
dst_addr: ip_addr_b,
|
|
|
|
protocol: proto,
|
|
|
|
payload_len
|
|
|
|
}))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|