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