ip.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. use core::fmt;
  2. use super::Ipv4Address;
  3. enum_with_unknown! {
  4. /// Internetworking protocol type.
  5. pub enum ProtocolType(u8) {
  6. Icmp = 0x01,
  7. Tcp = 0x06,
  8. Udp = 0x11
  9. }
  10. }
  11. impl fmt::Display for ProtocolType {
  12. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  13. match self {
  14. &ProtocolType::Icmp => write!(f, "ICMP"),
  15. &ProtocolType::Tcp => write!(f, "TCP"),
  16. &ProtocolType::Udp => write!(f, "UDP"),
  17. &ProtocolType::Unknown(id) => write!(f, "0x{:02x}", id)
  18. }
  19. }
  20. }
  21. /// An internetworking address.
  22. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  23. pub enum Address {
  24. /// An invalid address.
  25. /// May be used as a placeholder for storage where the address is not assigned yet.
  26. Invalid,
  27. /// An IPv4 address.
  28. Ipv4(Ipv4Address)
  29. }
  30. impl Address {
  31. /// Create an address wrapping an IPv4 address with the given octets.
  32. pub const fn ipv4(octets: [u8; 4]) -> Address {
  33. Address::Ipv4(Ipv4Address(octets))
  34. }
  35. /// Query whether the address is a valid unicast address.
  36. pub fn is_unicast(&self) -> bool {
  37. match self {
  38. &Address::Invalid => false,
  39. &Address::Ipv4(addr) => addr.is_unicast()
  40. }
  41. }
  42. }
  43. impl Default for Address {
  44. fn default() -> Address {
  45. Address::Invalid
  46. }
  47. }
  48. impl From<Ipv4Address> for Address {
  49. fn from(addr: Ipv4Address) -> Self {
  50. Address::Ipv4(addr)
  51. }
  52. }
  53. impl fmt::Display for Address {
  54. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  55. match self {
  56. &Address::Invalid => write!(f, "(invalid)"),
  57. &Address::Ipv4(addr) => write!(f, "{}", addr)
  58. }
  59. }
  60. }
  61. pub mod checksum {
  62. use byteorder::{ByteOrder, NetworkEndian};
  63. use super::*;
  64. /// Compute an RFC 1071 compliant checksum (without the final complement).
  65. pub fn data(data: &[u8]) -> u16 {
  66. let mut accum: u32 = 0;
  67. for i in (0..data.len()).step_by(2) {
  68. let word = NetworkEndian::read_u16(&data[i..i + 2]) as u32;
  69. accum += word;
  70. }
  71. (((accum >> 16) as u16) + (accum as u16))
  72. }
  73. /// Combine several RFC 1071 compliant checksums.
  74. pub fn combine(checksums: &[u16]) -> u16 {
  75. let mut accum: u32 = 0;
  76. for &word in checksums {
  77. accum += word as u32;
  78. }
  79. (((accum >> 16) as u16) + (accum as u16))
  80. }
  81. /// Compute an IP pseudo header checksum.
  82. pub fn pseudo_header(src_addr: &Address, dst_addr: &Address,
  83. protocol: ProtocolType, length: u32) -> u16 {
  84. match (src_addr, dst_addr) {
  85. (&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
  86. let mut proto_len = [0u8; 4];
  87. proto_len[1] = protocol.into();
  88. NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
  89. combine(&[
  90. data(src_addr.as_bytes()),
  91. data(dst_addr.as_bytes()),
  92. data(&proto_len[..])
  93. ])
  94. },
  95. _ => panic!("Unexpected pseudo header ")
  96. }
  97. }
  98. }