1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
/// "Destination Unreachable" ICMP header for IPv4 (without the invoking packet).
///
/// # Description in RFC 792:
///
/// If, according to the information in the gateway's routing tables,
/// the network specified in the internet destination field of a
/// datagram is unreachable, e.g., the distance to the network is
/// infinity, the gateway may send a destination unreachable message
/// to the internet source host of the datagram. In addition, in some
/// networks, the gateway may be able to determine if the internet
/// destination host is unreachable. Gateways in these networks may
/// send destination unreachable messages to the source host when the
/// destination host is unreachable.
///
/// If, in the destination host, the IP module cannot deliver the
/// datagram because the indicated protocol module or process port is
/// not active, the destination host may send a destination
/// unreachable message to the source host.
///
/// Another case is when a datagram must be fragmented to be forwarded
/// by a gateway yet the Don't Fragment flag is on. In this case the
/// gateway must discard the datagram and may return a destination
/// unreachable message.
///
/// Codes 0, 1, 4, and 5 may be received from a gateway. Codes 2 and
/// 3 may be received from a host.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DestUnreachableHeader {
/// Network unreachable error.
Network,
/// Host unreachable error.
Host,
/// Transport protocol not supported error.
Protocol,
/// Port unreachable error.
Port,
/// Fragmentation would be needed but the don't fragment bit is set.
FragmentationNeeded { next_hop_mtu: u16 },
/// Source Route Failed
SourceRouteFailed,
/// Destination Network Unknown (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
NetworkUnknown,
/// Destination Host Unknown (no route to host known) (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
HostUnknown,
/// Source Host Isolated - obsolete (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
Isolated,
/// Communication with Destination Network is Administratively Prohibited (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
NetworkProhibited,
/// Communication with Destination Host is Administratively Prohibited (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
HostProhibited,
/// Destination Network Unreachable for Type of Service (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
TosNetwork,
/// Destination Host Unreachable for Type of Service (from [RFC 1122](https://tools.ietf.org/html/rfc1122))
TosHost,
/// Cannot forward because packet administratively filtered (from [RFC 1812](https://tools.ietf.org/html/rfc1812))
FilterProhibited,
/// Required level of precidence not supported (from [RFC 1812](https://tools.ietf.org/html/rfc1812))
HostPrecedenceViolation,
/// Packet was below minimum precidence (from [RFC 1812](https://tools.ietf.org/html/rfc1812))
PrecedenceCutoff,
}
impl DestUnreachableHeader {
/// Tries to convert the code [`u8`] value and next_hop_mtu to a [`DestUnreachableHeader`] value.
///
/// Returns [`None`] in case the code value is not known as a destination unreachable code.
pub fn from_values(code_u8: u8, next_hop_mtu: u16) -> Option<DestUnreachableHeader> {
use crate::icmpv4::{DestUnreachableHeader::*, *};
match code_u8 {
CODE_DST_UNREACH_NET => Some(Network),
CODE_DST_UNREACH_HOST => Some(Host),
CODE_DST_UNREACH_PROTOCOL => Some(Protocol),
CODE_DST_UNREACH_PORT => Some(Port),
CODE_DST_UNREACH_NEED_FRAG => Some(FragmentationNeeded { next_hop_mtu }),
CODE_DST_UNREACH_SOURCE_ROUTE_FAILED => Some(SourceRouteFailed),
CODE_DST_UNREACH_NET_UNKNOWN => Some(NetworkUnknown),
CODE_DST_UNREACH_HOST_UNKNOWN => Some(HostUnknown),
CODE_DST_UNREACH_ISOLATED => Some(Isolated),
CODE_DST_UNREACH_NET_PROHIB => Some(NetworkProhibited),
CODE_DST_UNREACH_HOST_PROHIB => Some(HostProhibited),
CODE_DST_UNREACH_TOS_NET => Some(TosNetwork),
CODE_DST_UNREACH_TOS_HOST => Some(TosHost),
CODE_DST_UNREACH_FILTER_PROHIB => Some(FilterProhibited),
CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION => Some(HostPrecedenceViolation),
CODE_DST_UNREACH_PRECEDENCE_CUTOFF => Some(PrecedenceCutoff),
_ => None,
}
}
/// Returns the icmp code value of the destination unreachable packet.
#[inline]
pub fn code_u8(&self) -> u8 {
use crate::icmpv4::{DestUnreachableHeader::*, *};
match self {
Network => CODE_DST_UNREACH_NET,
Host => CODE_DST_UNREACH_HOST,
Protocol => CODE_DST_UNREACH_PROTOCOL,
Port => CODE_DST_UNREACH_PORT,
FragmentationNeeded { next_hop_mtu: _ } => CODE_DST_UNREACH_NEED_FRAG,
SourceRouteFailed => CODE_DST_UNREACH_SOURCE_ROUTE_FAILED,
NetworkUnknown => CODE_DST_UNREACH_NET_UNKNOWN,
HostUnknown => CODE_DST_UNREACH_HOST_UNKNOWN,
Isolated => CODE_DST_UNREACH_ISOLATED,
NetworkProhibited => CODE_DST_UNREACH_NET_PROHIB,
HostProhibited => CODE_DST_UNREACH_HOST_PROHIB,
TosNetwork => CODE_DST_UNREACH_TOS_NET,
TosHost => CODE_DST_UNREACH_TOS_HOST,
FilterProhibited => CODE_DST_UNREACH_FILTER_PROHIB,
HostPrecedenceViolation => CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION,
PrecedenceCutoff => CODE_DST_UNREACH_PRECEDENCE_CUTOFF,
}
}
}
#[cfg(test)]
mod test {
use crate::icmpv4::*;
use alloc::format;
use proptest::prelude::*;
fn conversion_values(next_hop_mtu: u16) -> [(u8, DestUnreachableHeader); 16] {
use DestUnreachableHeader::*;
[
(CODE_DST_UNREACH_NET, Network),
(CODE_DST_UNREACH_HOST, Host),
(CODE_DST_UNREACH_PROTOCOL, Protocol),
(CODE_DST_UNREACH_PORT, Port),
(
CODE_DST_UNREACH_NEED_FRAG,
FragmentationNeeded { next_hop_mtu },
),
(CODE_DST_UNREACH_SOURCE_ROUTE_FAILED, SourceRouteFailed),
(CODE_DST_UNREACH_NET_UNKNOWN, NetworkUnknown),
(CODE_DST_UNREACH_HOST_UNKNOWN, HostUnknown),
(CODE_DST_UNREACH_ISOLATED, Isolated),
(CODE_DST_UNREACH_NET_PROHIB, NetworkProhibited),
(CODE_DST_UNREACH_HOST_PROHIB, HostProhibited),
(CODE_DST_UNREACH_TOS_NET, TosNetwork),
(CODE_DST_UNREACH_TOS_HOST, TosHost),
(CODE_DST_UNREACH_FILTER_PROHIB, FilterProhibited),
(
CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION,
HostPrecedenceViolation,
),
(CODE_DST_UNREACH_PRECEDENCE_CUTOFF, PrecedenceCutoff),
]
}
proptest! {
#[test]
fn from_values(
next_hop_mtu in any::<u16>(),
) {
// valid values
{
let valid_values = conversion_values(next_hop_mtu);
for t in valid_values {
assert_eq!(Some(t.1), DestUnreachableHeader::from_values(t.0, next_hop_mtu));
}
}
// invalid values
for code_u8 in 16u8..=u8::MAX {
assert_eq!(None, DestUnreachableHeader::from_values(code_u8, next_hop_mtu));
}
}
}
proptest! {
#[test]
fn code_u8(
next_hop_mtu in any::<u16>(),
) {
let valid_values = conversion_values(next_hop_mtu);
for t in valid_values {
assert_eq!(t.0, t.1.code_u8());
}
}
}
#[test]
fn clone_eq() {
use DestUnreachableHeader::*;
let values = [
Network,
Host,
Protocol,
Port,
FragmentationNeeded { next_hop_mtu: 0 },
SourceRouteFailed,
NetworkUnknown,
HostUnknown,
Isolated,
NetworkProhibited,
HostProhibited,
TosNetwork,
TosHost,
FilterProhibited,
HostPrecedenceViolation,
PrecedenceCutoff,
];
for value in values {
assert_eq!(value.clone(), value);
}
}
#[test]
fn debug() {
use DestUnreachableHeader::*;
let tests = [
("Network", Network),
("Host", Host),
("Protocol", Protocol),
("Port", Port),
(
"FragmentationNeeded { next_hop_mtu: 0 }",
FragmentationNeeded { next_hop_mtu: 0 },
),
("SourceRouteFailed", SourceRouteFailed),
("NetworkUnknown", NetworkUnknown),
("HostUnknown", HostUnknown),
("Isolated", Isolated),
("NetworkProhibited", NetworkProhibited),
("HostProhibited", HostProhibited),
("TosNetwork", TosNetwork),
("TosHost", TosHost),
("FilterProhibited", FilterProhibited),
("HostPrecedenceViolation", HostPrecedenceViolation),
("PrecedenceCutoff", PrecedenceCutoff),
];
for t in tests {
assert_eq!(t.0, format!("{:?}", t.1));
}
}
}