pub use super::v4::constants::*;
pub use super::v6::constants::*;
pub(crate) fn is_echo_v4(icmp_type: u8) -> bool {
matches!(icmp_type, ICMP_ECHO_REQUEST | ICMP_ECHO_REPLY)
}
pub(crate) fn is_query_v4(icmp_type: u8) -> bool {
is_echo_v4(icmp_type)
|| matches!(
icmp_type,
ICMP_TIMESTAMP
| ICMP_TIMESTAMP_REPLY
| ICMP_INFORMATION_REQUEST
| ICMP_INFORMATION_REPLY
| ICMP_ADDRESS_MASK_REQUEST
| ICMP_ADDRESS_MASK_REPLY
)
}
pub(crate) fn is_echo_v6(icmp_type: u8) -> bool {
matches!(icmp_type, ICMPV6_ECHO_REQUEST | ICMPV6_ECHO_REPLY)
}
pub(crate) fn is_extended_echo_v6(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMPV6_EXTENDED_ECHO_REQUEST | ICMPV6_EXTENDED_ECHO_REPLY
)
}
pub(crate) fn is_extended_echo_v4(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMP_EXTENDED_ECHO_REQUEST | ICMP_EXTENDED_ECHO_REPLY
)
}
pub(crate) fn icmpv4_type_allows_extensions(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMP_DESTINATION_UNREACHABLE | ICMP_TIME_EXCEEDED | ICMP_PARAMETER_PROBLEM
)
}
pub(crate) fn interface_role_summary(role: u8) -> String {
match role {
ICMP_INTERFACE_ROLE_INCOMING => "incoming".to_string(),
ICMP_INTERFACE_ROLE_SUB_IP_INCOMING => "sub-ip-incoming".to_string(),
ICMP_INTERFACE_ROLE_OUTGOING => "outgoing".to_string(),
ICMP_INTERFACE_ROLE_NEXT_HOP => "next-hop".to_string(),
other => format!("role({other})"),
}
}
pub(crate) fn icmpv4_type_is_error(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMP_DESTINATION_UNREACHABLE
| ICMP_SOURCE_QUENCH
| ICMP_REDIRECT
| ICMP_TIME_EXCEEDED
| ICMP_PARAMETER_PROBLEM
)
}
pub(crate) fn icmpv6_type_allows_extensions(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMPV6_DESTINATION_UNREACHABLE | ICMPV6_TIME_EXCEEDED
)
}
pub(crate) fn icmpv4_type_summary(icmp_type: u8) -> String {
match icmpv4_type_name(icmp_type) {
Some(name) => format!("{name}({icmp_type})"),
None => icmp_type.to_string(),
}
}
pub(crate) fn icmpv4_type_name(icmp_type: u8) -> Option<&'static str> {
let name = match icmp_type {
ICMP_ECHO_REPLY => "echo-reply",
ICMP_DESTINATION_UNREACHABLE => "destination-unreachable",
ICMP_SOURCE_QUENCH => "source-quench",
ICMP_REDIRECT => "redirect",
ICMP_ALTERNATE_HOST_ADDRESS => "alternate-host-address",
ICMP_ECHO_REQUEST => "echo-request",
ICMP_ROUTER_ADVERTISEMENT => "router-advertisement",
ICMP_ROUTER_SOLICITATION => "router-solicitation",
ICMP_TIME_EXCEEDED => "time-exceeded",
ICMP_PARAMETER_PROBLEM => "parameter-problem",
ICMP_TIMESTAMP => "timestamp",
ICMP_TIMESTAMP_REPLY => "timestamp-reply",
ICMP_INFORMATION_REQUEST => "information-request",
ICMP_INFORMATION_REPLY => "information-reply",
ICMP_ADDRESS_MASK_REQUEST => "address-mask-request",
ICMP_ADDRESS_MASK_REPLY => "address-mask-reply",
ICMP_RESERVED_SECURITY => "reserved-security",
ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_FIRST..=ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_LAST => {
"reserved-robustness-experiment"
}
ICMP_TRACEROUTE => "traceroute",
ICMP_DATAGRAM_CONVERSION_ERROR => "datagram-conversion-error",
ICMP_MOBILE_HOST_REDIRECT => "mobile-host-redirect",
ICMP_IPV6_WHERE_ARE_YOU => "ipv6-where-are-you",
ICMP_IPV6_I_AM_HERE => "ipv6-i-am-here",
ICMP_MOBILE_REGISTRATION_REQUEST => "mobile-registration-request",
ICMP_MOBILE_REGISTRATION_REPLY => "mobile-registration-reply",
ICMP_DOMAIN_NAME_REQUEST => "domain-name-request",
ICMP_DOMAIN_NAME_REPLY => "domain-name-reply",
ICMP_SKIP => "skip",
ICMP_PHOTURIS => "photuris",
ICMP_SEAMOBY_EXPERIMENTAL => "seamoby-experimental",
ICMP_EXTENDED_ECHO_REQUEST => "extended-echo-request",
ICMP_EXTENDED_ECHO_REPLY => "extended-echo-reply",
ICMP_EXPERIMENTAL_253 => "experiment-1",
ICMP_EXPERIMENTAL_254 => "experiment-2",
ICMP_RESERVED_255 => "reserved",
_ => return None,
};
Some(name)
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn icmpv4_type_is_deprecated(icmp_type: u8) -> bool {
matches!(
icmp_type,
ICMP_SOURCE_QUENCH
| ICMP_ALTERNATE_HOST_ADDRESS
| ICMP_INFORMATION_REQUEST
| ICMP_INFORMATION_REPLY
| ICMP_ADDRESS_MASK_REQUEST
| ICMP_ADDRESS_MASK_REPLY
| ICMP_TRACEROUTE
| ICMP_DATAGRAM_CONVERSION_ERROR
| ICMP_MOBILE_HOST_REDIRECT
| ICMP_IPV6_WHERE_ARE_YOU
| ICMP_IPV6_I_AM_HERE
| ICMP_MOBILE_REGISTRATION_REQUEST
| ICMP_MOBILE_REGISTRATION_REPLY
| ICMP_DOMAIN_NAME_REQUEST
| ICMP_DOMAIN_NAME_REPLY
| ICMP_SKIP
)
}
pub(crate) fn icmpv4_code_name(icmp_type: u8, code: u8) -> Option<&'static str> {
let name = match (icmp_type, code) {
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_NET_UNREACHABLE) => "net-unreachable",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_HOST_UNREACHABLE) => "host-unreachable",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_PROTOCOL_UNREACHABLE) => "protocol-unreachable",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_PORT_UNREACHABLE) => "port-unreachable",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_FRAGMENTATION_NEEDED) => "fragmentation-needed",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_SOURCE_ROUTE_FAILED) => "source-route-failed",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_DEST_NETWORK_UNKNOWN) => "dest-network-unknown",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_DEST_HOST_UNKNOWN) => "dest-host-unknown",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_SOURCE_HOST_ISOLATED) => "source-host-isolated",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_NETWORK_ADMIN_PROHIBITED) => {
"network-admin-prohibited"
}
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_HOST_ADMIN_PROHIBITED) => {
"host-admin-prohibited"
}
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_NETWORK_UNREACHABLE_TOS) => {
"network-unreachable-tos"
}
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_HOST_UNREACHABLE_TOS) => "host-unreachable-tos",
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_COMM_ADMIN_PROHIBITED) => {
"comm-admin-prohibited"
}
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_HOST_PRECEDENCE_VIOLATION) => {
"host-precedence-violation"
}
(ICMP_DESTINATION_UNREACHABLE, ICMP_CODE_DU_PRECEDENCE_CUTOFF) => "precedence-cutoff",
(ICMP_REDIRECT, ICMP_CODE_REDIRECT_NETWORK) => "redirect-network",
(ICMP_REDIRECT, ICMP_CODE_REDIRECT_HOST) => "redirect-host",
(ICMP_REDIRECT, ICMP_CODE_REDIRECT_TOS_NETWORK) => "redirect-tos-network",
(ICMP_REDIRECT, ICMP_CODE_REDIRECT_TOS_HOST) => "redirect-tos-host",
(ICMP_ROUTER_ADVERTISEMENT, ICMP_CODE_ROUTER_ADVERTISEMENT_NORMAL) => "normal",
(ICMP_ROUTER_ADVERTISEMENT, ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC) => {
"no-common-traffic"
}
(ICMP_TIME_EXCEEDED, ICMP_CODE_TIME_EXCEEDED_TTL) => "ttl-exceeded",
(ICMP_TIME_EXCEEDED, ICMP_CODE_TIME_EXCEEDED_FRAGMENT_REASSEMBLY) => {
"fragment-reassembly-time-exceeded"
}
(ICMP_PARAMETER_PROBLEM, ICMP_CODE_PARAMETER_PROBLEM_POINTER) => "pointer",
(ICMP_PARAMETER_PROBLEM, ICMP_CODE_PARAMETER_PROBLEM_MISSING_OPTION) => "missing-option",
(ICMP_PARAMETER_PROBLEM, ICMP_CODE_PARAMETER_PROBLEM_BAD_LENGTH) => "bad-length",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_BAD_SPI) => "bad-spi",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_AUTHENTICATION_FAILED) => "authentication-failed",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_DECOMPRESSION_FAILED) => "decompression-failed",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_DECRYPTION_FAILED) => "decryption-failed",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_NEED_AUTHENTICATION) => "need-authentication",
(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_NEED_AUTHORIZATION) => "need-authorization",
(ICMP_EXTENDED_ECHO_REPLY, ICMP_CODE_EXTENDED_ECHO_REPLY_NO_ERROR) => "no-error",
(ICMP_EXTENDED_ECHO_REPLY, ICMP_CODE_EXTENDED_ECHO_REPLY_MALFORMED_QUERY) => {
"malformed-query"
}
(ICMP_EXTENDED_ECHO_REPLY, ICMP_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_INTERFACE) => {
"no-such-interface"
}
(ICMP_EXTENDED_ECHO_REPLY, ICMP_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_TABLE_ENTRY) => {
"no-such-table-entry"
}
(ICMP_EXTENDED_ECHO_REPLY, ICMP_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES) => {
"multiple-interfaces"
}
_ => return None,
};
Some(name)
}
pub(crate) fn icmpv4_code_summary(icmp_type: u8, code: u8) -> String {
match icmpv4_code_name(icmp_type, code) {
Some(name) => format!("{name}({code})"),
None => code.to_string(),
}
}
pub(crate) fn icmpv6_type_summary(icmp_type: u8) -> String {
match icmp_type {
ICMPV6_DESTINATION_UNREACHABLE => "destination-unreachable(1)".to_string(),
ICMPV6_PACKET_TOO_BIG => "packet-too-big(2)".to_string(),
ICMPV6_TIME_EXCEEDED => "time-exceeded(3)".to_string(),
ICMPV6_PARAMETER_PROBLEM => "parameter-problem(4)".to_string(),
ICMPV6_ECHO_REQUEST => "echo-request(128)".to_string(),
ICMPV6_ECHO_REPLY => "echo-reply(129)".to_string(),
ICMPV6_MULTICAST_LISTENER_QUERY => "multicast-listener-query(130)".to_string(),
ICMPV6_MULTICAST_LISTENER_REPORT => "multicast-listener-report(131)".to_string(),
ICMPV6_MULTICAST_LISTENER_DONE => "multicast-listener-done(132)".to_string(),
ICMPV6_ROUTER_SOLICITATION => "router-solicitation(133)".to_string(),
ICMPV6_ROUTER_ADVERTISEMENT => "router-advertisement(134)".to_string(),
ICMPV6_NEIGHBOR_SOLICITATION => "neighbor-solicitation(135)".to_string(),
ICMPV6_NEIGHBOR_ADVERTISEMENT => "neighbor-advertisement(136)".to_string(),
ICMPV6_REDIRECT => "redirect(137)".to_string(),
ICMPV6_EXTENDED_ECHO_REQUEST => "extended-echo-request(160)".to_string(),
ICMPV6_EXTENDED_ECHO_REPLY => "extended-echo-reply(161)".to_string(),
value => value.to_string(),
}
}
#[cfg(test)]
mod icmpv4_codepoints {
use super::{
icmpv4_code_summary, icmpv4_type_is_deprecated, icmpv4_type_name, icmpv4_type_summary,
ICMP_ADDRESS_MASK_REPLY, ICMP_ADDRESS_MASK_REQUEST, ICMP_ALTERNATE_HOST_ADDRESS,
ICMP_CODE_DU_FRAGMENTATION_NEEDED, ICMP_CODE_DU_NET_UNREACHABLE,
ICMP_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES, ICMP_CODE_PHOTURIS_NEED_AUTHORIZATION,
ICMP_CODE_REDIRECT_HOST, ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC,
ICMP_DESTINATION_UNREACHABLE, ICMP_ECHO_REPLY, ICMP_ECHO_REQUEST, ICMP_EXPERIMENTAL_253,
ICMP_EXPERIMENTAL_254, ICMP_EXTENDED_ECHO_REPLY, ICMP_EXTENDED_ECHO_REQUEST,
ICMP_INFORMATION_REPLY, ICMP_PHOTURIS, ICMP_REDIRECT, ICMP_RESERVED_255,
ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_FIRST, ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_LAST,
ICMP_RESERVED_SECURITY, ICMP_ROUTER_ADVERTISEMENT, ICMP_ROUTER_SOLICITATION,
ICMP_SEAMOBY_EXPERIMENTAL, ICMP_SOURCE_QUENCH, ICMP_TIMESTAMP, ICMP_TIMESTAMP_REPLY,
};
#[test]
fn icmpv4_codepoints_representative_type_constants_have_iana_values() {
assert_eq!(ICMP_ECHO_REPLY, 0);
assert_eq!(ICMP_DESTINATION_UNREACHABLE, 3);
assert_eq!(ICMP_SOURCE_QUENCH, 4);
assert_eq!(ICMP_REDIRECT, 5);
assert_eq!(ICMP_ECHO_REQUEST, 8);
assert_eq!(ICMP_ROUTER_ADVERTISEMENT, 9);
assert_eq!(ICMP_ROUTER_SOLICITATION, 10);
assert_eq!(ICMP_TIMESTAMP, 13);
assert_eq!(ICMP_TIMESTAMP_REPLY, 14);
assert_eq!(ICMP_PHOTURIS, 40);
assert_eq!(ICMP_SEAMOBY_EXPERIMENTAL, 41);
assert_eq!(ICMP_EXTENDED_ECHO_REQUEST, 42);
assert_eq!(ICMP_EXTENDED_ECHO_REPLY, 43);
assert_eq!(ICMP_EXPERIMENTAL_253, 253);
assert_eq!(ICMP_EXPERIMENTAL_254, 254);
assert_eq!(ICMP_RESERVED_255, 255);
assert_eq!(ICMP_RESERVED_SECURITY, 19);
assert_eq!(ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_FIRST, 20);
assert_eq!(ICMP_RESERVED_ROBUSTNESS_EXPERIMENT_LAST, 29);
}
#[test]
fn icmpv4_codepoints_representative_code_constants_have_iana_values() {
assert_eq!(ICMP_CODE_DU_NET_UNREACHABLE, 0);
assert_eq!(ICMP_CODE_DU_FRAGMENTATION_NEEDED, 4);
assert_eq!(ICMP_CODE_REDIRECT_HOST, 1);
assert_eq!(ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC, 16);
assert_eq!(ICMP_CODE_PHOTURIS_NEED_AUTHORIZATION, 5);
assert_eq!(ICMP_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES, 4);
}
#[test]
fn icmpv4_codepoints_constants_are_publicly_exported() {
assert_eq!(crate::ICMP_TIMESTAMP, ICMP_TIMESTAMP);
assert_eq!(crate::ICMP_ROUTER_ADVERTISEMENT, ICMP_ROUTER_ADVERTISEMENT);
assert_eq!(
crate::ICMP_EXTENDED_ECHO_REQUEST,
ICMP_EXTENDED_ECHO_REQUEST
);
assert_eq!(crate::ICMP_EXPERIMENTAL_253, ICMP_EXPERIMENTAL_253);
assert_eq!(
crate::ICMP_ALTERNATE_HOST_ADDRESS,
ICMP_ALTERNATE_HOST_ADDRESS
);
assert_eq!(crate::ICMP_ADDRESS_MASK_REQUEST, ICMP_ADDRESS_MASK_REQUEST);
assert_eq!(crate::core::ICMP_PHOTURIS, ICMP_PHOTURIS);
assert_eq!(
crate::core::ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC,
ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC
);
}
#[test]
fn icmpv4_codepoints_known_type_summaries_use_stable_names() {
assert_eq!(icmpv4_type_summary(ICMP_ECHO_REPLY), "echo-reply(0)");
assert_eq!(
icmpv4_type_summary(ICMP_DESTINATION_UNREACHABLE),
"destination-unreachable(3)"
);
assert_eq!(icmpv4_type_summary(ICMP_TIMESTAMP), "timestamp(13)");
assert_eq!(
icmpv4_type_summary(ICMP_EXTENDED_ECHO_REQUEST),
"extended-echo-request(42)"
);
assert_eq!(
icmpv4_type_summary(ICMP_EXPERIMENTAL_253),
"experiment-1(253)"
);
assert_eq!(
icmpv4_type_summary(25),
"reserved-robustness-experiment(25)"
);
assert_eq!(icmpv4_type_name(ICMP_RESERVED_255), Some("reserved"));
}
#[test]
fn icmpv4_codepoints_known_code_summaries_use_stable_names() {
assert_eq!(
icmpv4_code_summary(
ICMP_DESTINATION_UNREACHABLE,
ICMP_CODE_DU_FRAGMENTATION_NEEDED
),
"fragmentation-needed(4)"
);
assert_eq!(
icmpv4_code_summary(ICMP_REDIRECT, ICMP_CODE_REDIRECT_HOST),
"redirect-host(1)"
);
assert_eq!(
icmpv4_code_summary(
ICMP_ROUTER_ADVERTISEMENT,
ICMP_CODE_ROUTER_ADVERTISEMENT_NO_COMMON_TRAFFIC
),
"no-common-traffic(16)"
);
assert_eq!(
icmpv4_code_summary(ICMP_PHOTURIS, ICMP_CODE_PHOTURIS_NEED_AUTHORIZATION),
"need-authorization(5)"
);
assert_eq!(
icmpv4_code_summary(
ICMP_EXTENDED_ECHO_REPLY,
ICMP_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES
),
"multiple-interfaces(4)"
);
}
#[test]
fn icmpv4_codepoints_deprecated_types_retain_names_and_report_status() {
assert_eq!(icmpv4_type_summary(ICMP_SOURCE_QUENCH), "source-quench(4)");
assert_eq!(
icmpv4_type_summary(ICMP_ALTERNATE_HOST_ADDRESS),
"alternate-host-address(6)"
);
assert_eq!(
icmpv4_type_summary(ICMP_ADDRESS_MASK_REPLY),
"address-mask-reply(18)"
);
assert!(icmpv4_type_is_deprecated(ICMP_SOURCE_QUENCH));
assert!(icmpv4_type_is_deprecated(ICMP_ALTERNATE_HOST_ADDRESS));
assert!(icmpv4_type_is_deprecated(ICMP_INFORMATION_REPLY));
assert!(icmpv4_type_is_deprecated(ICMP_ADDRESS_MASK_REQUEST));
assert!(!icmpv4_type_is_deprecated(ICMP_ECHO_REQUEST));
assert!(!icmpv4_type_is_deprecated(ICMP_SEAMOBY_EXPERIMENTAL));
assert!(!icmpv4_type_is_deprecated(ICMP_EXTENDED_ECHO_REQUEST));
assert!(!icmpv4_type_is_deprecated(ICMP_RESERVED_255));
}
#[test]
fn icmpv4_codepoints_unknown_type_falls_back_to_number() {
assert_eq!(icmpv4_type_name(1), None);
assert_eq!(icmpv4_type_name(2), None);
assert_eq!(icmpv4_type_name(7), None);
assert_eq!(icmpv4_type_summary(1), "1");
assert_eq!(icmpv4_type_summary(7), "7");
}
#[test]
fn icmpv4_codepoints_unknown_code_falls_back_to_number() {
assert_eq!(icmpv4_code_summary(ICMP_DESTINATION_UNREACHABLE, 99), "99");
assert_eq!(icmpv4_code_summary(super::ICMP_TIME_EXCEEDED, 200), "200");
assert_eq!(icmpv4_code_summary(ICMP_ECHO_REQUEST, 0), "0");
assert_eq!(icmpv4_code_summary(ICMP_ECHO_REQUEST, 5), "5");
}
}