From 6de7e2724206e8244e26315fa2e74104426dc64b Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 25 Jan 2021 19:50:40 -0500 Subject: [PATCH] cargo fmt --- examples/ping6.rs | 37 +++--- src/echo.rs | 91 ++++++++++----- src/lib.rs | 12 +- src/packet.rs | 290 ++++++++++++++++++++++++++++------------------ src/socket.rs | 37 +++--- 5 files changed, 294 insertions(+), 173 deletions(-) diff --git a/examples/ping6.rs b/examples/ping6.rs index f45aeb0..78d1c27 100644 --- a/examples/ping6.rs +++ b/examples/ping6.rs @@ -1,11 +1,11 @@ // Copyright 2021 Jeremy Wall -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,18 +16,27 @@ use std::net::Ipv6Addr; use icmp_socket::*; pub fn main() { - let mut socket6 = IcmpSocket6::new().unwrap(); + let mut socket6 = IcmpSocket6::new().unwrap(); socket6.bind("::1".parse::().unwrap()).unwrap(); let mut echo_socket = echo::EchoSocket6::new(socket6); - echo_socket.send_ping("::1".parse::().unwrap(), 42, &[ - 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, - 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, 0x77, 0x6f, - 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, - 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, - 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, - 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, - 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20]).unwrap(); + echo_socket + .send_ping( + "::1".parse::().unwrap(), + 42, + &[ + 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, + 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, 0x6b, 0x6e, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20, + ], + ) + .unwrap(); let _ = echo_socket.recv_ping(); let resp = echo_socket.recv_ping().unwrap(); - println!("seq: {}, identifier: {} payload: {}", resp.sequence, resp.identifier, resp.payload.len()); -} \ No newline at end of file + println!( + "seq: {}, identifier: {} payload: {}", + resp.sequence, + resp.identifier, + resp.payload.len() + ); +} diff --git a/src/echo.rs b/src/echo.rs index 1a8b5c5..e0c9890 100644 --- a/src/echo.rs +++ b/src/echo.rs @@ -1,23 +1,23 @@ // Copyright 2021 Jeremy Wall -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::convert::{TryFrom, From, TryInto}; +use std::convert::{From, TryFrom, TryInto}; use std::net::{Ipv4Addr, Ipv6Addr}; -use packet::{Builder, Packet as P}; use packet::icmp::echo::Packet; +use packet::{Builder, Packet as P}; -use crate::packet::{Icmpv6Packet, Icmpv6Message::EchoReply}; +use crate::packet::{Icmpv6Message::EchoReply, Icmpv6Packet}; // TODO(jwall): It turns out that the ICMPv6 packets are sufficiently // different from the ICMPv4 packets. In order to handle them appropriately @@ -35,18 +35,25 @@ impl TryFrom for EchoResponse { type Error = std::io::Error; fn try_from(pkt: Icmpv6Packet) -> Result { - if let EchoReply{ + if let EchoReply { identifier, sequence, payload, - } = pkt.message { - Ok(EchoResponse{ + } = pkt.message + { + Ok(EchoResponse { identifier, sequence, payload, }) } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, format!("Incorrect icmpv6 message: {:?}, code: {}", pkt.message, pkt.code))) + Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!( + "Incorrect icmpv6 message: {:?}, code: {}", + pkt.message, pkt.code + ), + )) } } } @@ -59,19 +66,36 @@ pub struct EchoSocket4 { impl EchoSocket4 { pub fn new(sock: IcmpSocket4) -> Self { - EchoSocket4{inner:sock, sequence: 0, buf: Vec::with_capacity(512)} + EchoSocket4 { + inner: sock, + sequence: 0, + buf: Vec::with_capacity(512), + } } pub fn set_max_hops(&mut self, hops: u32) { self.inner.set_max_hops(hops); } - pub fn send_ping(&mut self, dest: Ipv4Addr, identifier: u16, payload: &[u8]) -> std::io::Result<()> { + pub fn send_ping( + &mut self, + dest: Ipv4Addr, + identifier: u16, + payload: &[u8], + ) -> std::io::Result<()> { let packet = packet::icmp::Builder::default() - .echo().unwrap().request().unwrap() - .identifier(identifier).unwrap() - .sequence(self.sequence).unwrap() - .payload(payload).unwrap().build().unwrap(); + .echo() + .unwrap() + .request() + .unwrap() + .identifier(identifier) + .unwrap() + .sequence(self.sequence) + .unwrap() + .payload(payload) + .unwrap() + .build() + .unwrap(); self.sequence += 1; self.inner.send_to(dest, &packet)?; Ok(()) @@ -80,12 +104,19 @@ impl EchoSocket4 { pub fn recv_ping(&mut self) -> std::io::Result { let bytes_read = self.inner.rcv_from(&mut self.buf)?; match Packet::new(&self.buf[0..bytes_read]) { - Ok(p) => return Ok(EchoResponse{ - sequence: p.sequence(), - identifier: p.identifier(), - payload: p.payload().to_owned(), - }), - Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, format!("Malformed ICMP Response: {:?}", e))), + Ok(p) => { + return Ok(EchoResponse { + sequence: p.sequence(), + identifier: p.identifier(), + payload: p.payload().to_owned(), + }) + } + Err(e) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("Malformed ICMP Response: {:?}", e), + )) + } }; } } @@ -102,18 +133,26 @@ pub struct EchoSocket6 { } impl EchoSocket6 { - pub fn new(sock: IcmpSocket6) -> Self { // TODO(jwall): How to set ICMPv6 filters. - EchoSocket6{inner:sock, sequence: 0} + EchoSocket6 { + inner: sock, + sequence: 0, + } } pub fn set_max_hops(&mut self, hops: u32) { self.inner.set_max_hops(hops); } - pub fn send_ping(&mut self, dest: Ipv6Addr, identifier: u16, payload: &[u8]) -> std::io::Result<()> { - let packet = Icmpv6Packet::with_echo_request(identifier, self.sequence, payload.to_owned())?; + pub fn send_ping( + &mut self, + dest: Ipv6Addr, + identifier: u16, + payload: &[u8], + ) -> std::io::Result<()> { + let packet = + Icmpv6Packet::with_echo_request(identifier, self.sequence, payload.to_owned())?; self.sequence += 1; self.inner.send_to(dest, packet)?; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index fb224bb..9c0631b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,20 @@ // Copyright 2021 Jeremy Wall -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -pub mod socket; pub mod echo; pub mod packet; +pub mod socket; -pub use crate::packet::{Icmpv6Packet, Icmpv6Message}; -pub use socket::{IcmpSocket4, IcmpSocket6}; \ No newline at end of file +pub use crate::packet::{Icmpv6Message, Icmpv6Packet}; +pub use socket::{IcmpSocket4, IcmpSocket6}; diff --git a/src/packet.rs b/src/packet.rs index e75bcf3..e68402d 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,18 +1,18 @@ // Copyright 2021 Jeremy Wall -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +use byteorder::{BigEndian, ByteOrder}; use std::net::Ipv6Addr; -use byteorder::{ByteOrder, BigEndian}; fn ipv6_sum_words(ip: &Ipv6Addr) -> u32 { ip.segments().iter().map(|x| *x as u32).sum() @@ -33,7 +33,8 @@ fn sum_big_endian_words(bs: &[u8]) -> u32 { data = &data[2..]; } - if (len % 2) != 0 { // If odd then checksum the last byte + if (len % 2) != 0 { + // If odd then checksum the last byte sum += (data[0] as u32) << 8; } return sum; @@ -72,30 +73,49 @@ pub enum Icmpv6Message { identifier: u16, sequence: u16, payload: Vec, - } + }, } -use Icmpv6Message::{Unreachable, PacketTooBig, TimeExceeded, ParameterProblem, PrivateExperimental, EchoRequest, EchoReply}; +use Icmpv6Message::{ + EchoReply, EchoRequest, PacketTooBig, ParameterProblem, PrivateExperimental, TimeExceeded, + Unreachable, +}; impl Icmpv6Message { pub fn get_bytes(&self) -> Vec { let mut bytes = Vec::new(); match self { - Unreachable {_unused: field1, invoking_packet: field2 } | - PacketTooBig {mtu: field1, invoking_packet: field2 } | - TimeExceeded {_unused: field1, invoking_packet: field2 } | - ParameterProblem {pointer: field1, invoking_packet: field2 } | - PrivateExperimental {padding: field1, payload: field2 } => { + Unreachable { + _unused: field1, + invoking_packet: field2, + } + | PacketTooBig { + mtu: field1, + invoking_packet: field2, + } + | TimeExceeded { + _unused: field1, + invoking_packet: field2, + } + | ParameterProblem { + pointer: field1, + invoking_packet: field2, + } + | PrivateExperimental { + padding: field1, + payload: field2, + } => { let mut buf = vec![0; 4]; BigEndian::write_u32(&mut buf, *field1); bytes.append(&mut buf); bytes.extend_from_slice(field2); - }, - EchoRequest{ + } + EchoRequest { identifier, sequence, payload, - } | EchoReply{ + } + | EchoReply { identifier, sequence, payload, @@ -141,15 +161,15 @@ impl Icmpv6Packet { let next_field = BigEndian::read_u32(&bytes[4..8]); let payload = bytes[8..].to_owned(); let message = match typ { - 1 => Unreachable{ + 1 => Unreachable { _unused: next_field, invoking_packet: payload, }, - 2 => PacketTooBig{ + 2 => PacketTooBig { mtu: next_field, invoking_packet: payload, }, - 3 => TimeExceeded{ + 3 => TimeExceeded { _unused: next_field, invoking_packet: payload, }, @@ -157,28 +177,28 @@ impl Icmpv6Packet { pointer: next_field, invoking_packet: payload, }, - 100 | 101 | 200 | 201 => PrivateExperimental{ + 100 | 101 | 200 | 201 => PrivateExperimental { padding: next_field, - payload: payload, + payload: payload, }, - 128 => EchoRequest{ + 128 => EchoRequest { identifier: BigEndian::read_u16(&bytes[4..6]), sequence: BigEndian::read_u16(&bytes[6..8]), payload: payload, }, - 129 => EchoReply{ + 129 => EchoReply { identifier: BigEndian::read_u16(&bytes[4..6]), sequence: BigEndian::read_u16(&bytes[6..8]), payload: payload, }, _ => return Err(PacketParseError::UnrecognizedICMPType), }; - return Ok(Icmpv6Packet{ + return Ok(Icmpv6Packet { typ: typ, code: code, checksum: checksum, message: message, - }) + }); } /// Get this packet serialized to bytes suitable for sending on the wire. @@ -188,11 +208,7 @@ impl Icmpv6Packet { bytes.push(self.code); let mut buf = Vec::with_capacity(2); buf.resize(2, 0); - BigEndian::write_u16(&mut buf, if with_checksum { - self.checksum - } else { - 0 - }); + BigEndian::write_u16(&mut buf, if with_checksum { self.checksum } else { 0 }); bytes.append(&mut buf); bytes.append(&mut self.message.get_bytes()); return bytes; @@ -215,7 +231,7 @@ impl Icmpv6Packet { let len = bytes.len(); sum += len as u32; sum += sum_big_endian_words(&bytes); - + // handle the carry while sum >> 16 != 0 { sum = (sum >> 16) + (sum & 0xFFFF); @@ -241,40 +257,40 @@ impl Icmpv6Packet { checksum: 0, // TODO(jwall): Should we enforce that the packet isn't too big? // It is not supposed to be larger than the minimum IPv6 MTU - message: Unreachable{ + message: Unreachable { _unused: 0, invoking_packet: packet, }, }) } - + /// Construct a packet for Packet Too Big messages. pub fn with_packet_too_big(mtu: u32, packet: Vec) -> Result { - Ok(Self{ + Ok(Self { typ: 2, code: 0, checksum: 0, // TODO(jwall): Should we enforce that the packet isn't too big? // It is not supposed to be larger than the minimum IPv6 MTU - message: PacketTooBig{ + message: PacketTooBig { mtu: mtu, invoking_packet: packet, }, }) } - + /// Construct a packet for Time Exceeded messages. pub fn with_time_exceeded(code: u8, packet: Vec) -> Result { if code > 1 { return Err(Icmpv6PacketBuildError::InvalidCode(code)); } - Ok(Self{ + Ok(Self { typ: 3, code: code, checksum: 0, // TODO(jwall): Should we enforce that the packet isn't too big? // It is not supposed to be larger than the minimum IPv6 MTU - message: TimeExceeded{ + message: TimeExceeded { _unused: 0, invoking_packet: packet, }, @@ -282,7 +298,11 @@ impl Icmpv6Packet { } /// Construct a packet for Parameter Problem messages. - pub fn with_parameter_problem(code: u8, pointer: u32, packet: Vec) -> Result { + pub fn with_parameter_problem( + code: u8, + pointer: u32, + packet: Vec, + ) -> Result { if code > 1 { return Err(Icmpv6PacketBuildError::InvalidCode(code)); } @@ -290,38 +310,46 @@ impl Icmpv6Packet { typ: 4, code: code, checksum: 0, - message: ParameterProblem{ + message: ParameterProblem { pointer: pointer, invoking_packet: packet, - } + }, }) } /// Construct a packet for Echo Request messages. - pub fn with_echo_request(identifier: u16, sequence: u16, payload: Vec) -> Result { + pub fn with_echo_request( + identifier: u16, + sequence: u16, + payload: Vec, + ) -> Result { Ok(Self { typ: 128, code: 0, checksum: 0, - message: EchoRequest{ + message: EchoRequest { identifier: identifier, sequence: sequence, payload: payload, - } + }, }) } /// Construct a packet for Echo Reply messages. - pub fn with_echo_reply(identifier: u16, sequence: u16, payload: Vec) -> Result { + pub fn with_echo_reply( + identifier: u16, + sequence: u16, + payload: Vec, + ) -> Result { Ok(Self { typ: 129, code: 0, checksum: 0, - message: EchoReply{ + message: EchoReply { identifier: identifier, sequence: sequence, payload: payload, - } + }, }) } } @@ -334,18 +362,26 @@ use Icmpv6PacketBuildError::InvalidCode; impl std::fmt::Display for Icmpv6PacketBuildError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - InvalidCode(c) => format!("Invalid Code: {}", c), - }) + write!( + f, + "{}", + match self { + InvalidCode(c) => format!("Invalid Code: {}", c), + } + ) } } impl std::fmt::Display for PacketParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - PacketParseError::PacketTooSmall(c) => format!("Packet Too Small size: {}", c), - PacketParseError::UnrecognizedICMPType => "UnrecognizedIcmpType".to_owned(), - }) + write!( + f, + "{}", + match self { + PacketParseError::PacketTooSmall(c) => format!("Packet Too Small size: {}", c), + PacketParseError::UnrecognizedICMPType => "UnrecognizedIcmpType".to_owned(), + } + ) } } @@ -367,47 +403,65 @@ mod checksum_tests { #[test] fn packet_construction_echo_request_test() { - let pkt = Icmpv6Packet::with_echo_request(42, 1, vec![1,2,3,4]).unwrap(); + let pkt = Icmpv6Packet::with_echo_request(42, 1, vec![1, 2, 3, 4]).unwrap(); assert_eq!(pkt.typ, 128); assert_eq!(pkt.code, 0); - assert_eq!(pkt.message, EchoRequest{ - identifier: 42, sequence: 1, payload: vec![1,2,3,4], - }); + assert_eq!( + pkt.message, + EchoRequest { + identifier: 42, + sequence: 1, + payload: vec![1, 2, 3, 4], + } + ); } #[test] fn packet_construction_echo_reply_test() { - let pkt = Icmpv6Packet::with_echo_reply(42, 1, vec![1,2,3,4]).unwrap(); + let pkt = Icmpv6Packet::with_echo_reply(42, 1, vec![1, 2, 3, 4]).unwrap(); assert_eq!(pkt.typ, 129); assert_eq!(pkt.code, 0); - assert_eq!(pkt.message, EchoReply{ - identifier: 42, sequence: 1, payload: vec![1,2,3,4], - }); + assert_eq!( + pkt.message, + EchoReply { + identifier: 42, + sequence: 1, + payload: vec![1, 2, 3, 4], + } + ); } #[test] fn packet_construction_too_big_test() { - let pkt = Icmpv6Packet::with_packet_too_big(3, vec![1,2,3,4]).unwrap(); + let pkt = Icmpv6Packet::with_packet_too_big(3, vec![1, 2, 3, 4]).unwrap(); assert_eq!(pkt.typ, 2); assert_eq!(pkt.code, 0); - assert_eq!(pkt.message, PacketTooBig{ - mtu: 3, invoking_packet: vec![1,2,3,4], - }); + assert_eq!( + pkt.message, + PacketTooBig { + mtu: 3, + invoking_packet: vec![1, 2, 3, 4], + } + ); } #[test] fn packet_construction_time_exceeded() { - let pkt = Icmpv6Packet::with_time_exceeded(0, vec![1,2,3,4]).unwrap(); + let pkt = Icmpv6Packet::with_time_exceeded(0, vec![1, 2, 3, 4]).unwrap(); assert_eq!(pkt.typ, 3); assert_eq!(pkt.code, 0); - assert_eq!(pkt.message, TimeExceeded{ - _unused: 0, invoking_packet: vec![1,2,3,4], - }); + assert_eq!( + pkt.message, + TimeExceeded { + _unused: 0, + invoking_packet: vec![1, 2, 3, 4], + } + ); } - + #[test] fn packet_construction_time_exceeded_invalid_code() { - let pkt = Icmpv6Packet::with_time_exceeded(2, vec![1,2,3,4]); + let pkt = Icmpv6Packet::with_time_exceeded(2, vec![1, 2, 3, 4]); assert!(pkt.is_err()); let e = pkt.unwrap_err(); assert_eq!(e, Icmpv6PacketBuildError::InvalidCode(2)); @@ -415,17 +469,22 @@ mod checksum_tests { #[test] fn packet_construction_parameter_problem() { - let pkt = Icmpv6Packet::with_parameter_problem(0, 30, vec![1,2,3,4,5,6,7,8,9,10]).unwrap(); + let pkt = Icmpv6Packet::with_parameter_problem(0, 30, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + .unwrap(); assert_eq!(pkt.typ, 4); assert_eq!(pkt.code, 0); - assert_eq!(pkt.message, ParameterProblem{ - pointer: 30, invoking_packet: vec![1,2,3,4,5,6,7,8,9,10], - }); + assert_eq!( + pkt.message, + ParameterProblem { + pointer: 30, + invoking_packet: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + } + ); } - + #[test] fn packet_construction_parameter_problem_invalid_code() { - let pkt = Icmpv6Packet::with_parameter_problem(3, 30, vec![1,2,3,4]); + let pkt = Icmpv6Packet::with_parameter_problem(3, 30, vec![1, 2, 3, 4]); assert!(pkt.is_err()); let e = pkt.unwrap_err(); assert_eq!(e, Icmpv6PacketBuildError::InvalidCode(3)); @@ -443,35 +502,38 @@ mod checksum_tests { 0x00, 0x00, // Id 0x00, 0x01, // Sequence // 56 bytes of "random" data - 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, - 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, 0x77, 0x6f, - 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, - 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, - 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, - 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, - 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20 + 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, + 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, 0x6b, 0x6e, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20, ]; let mut pkt = Icmpv6Packet::parse(&data).unwrap(); assert_eq!(pkt.typ, 128); assert_eq!(pkt.code, 0x00); - if let EchoRequest{ + if let EchoRequest { identifier, sequence, payload, - }= &pkt.message { + } = &pkt.message + { assert_eq!(*identifier, 0); assert_eq!(*sequence, 1); - assert_eq!(payload, &[ - 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, - 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, 0x77, 0x6f, - 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, - 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, - 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, - 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, - 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20 - ]); - } else { - assert!(false, "Packet did not parse as an EchoRequest {:?}", pkt.message); + assert_eq!( + payload, + &[ + 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, + 0x20, 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x20, 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, + 0x69, 0x20, 0x20, 0x20 + ] + ); + } else { + assert!( + false, + "Packet did not parse as an EchoRequest {:?}", + pkt.message + ); } assert_eq!(pkt.get_bytes(true), data); assert_eq!(pkt.calculate_checksum(lo, lo), 0x1d2e); @@ -483,26 +545,32 @@ mod checksum_tests { let pkt = Icmpv6Packet::parse(&data).unwrap(); assert_eq!(pkt.typ, 129); assert_eq!(pkt.code, 0); - if let EchoReply{ + if let EchoReply { identifier, sequence, payload, - }= &pkt.message { + } = &pkt.message + { assert_eq!(*identifier, 0); assert_eq!(*sequence, 1); - assert_eq!(payload, &[ - 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, - 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20, 0x77, 0x6f, - 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, - 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, - 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, - 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, - 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20 - ]); - } else { - assert!(false, "Packet did not parse as an EchoReply {:?}", pkt.message); + assert_eq!( + payload, + &[ + 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, + 0x20, 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x20, 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, + 0x69, 0x20, 0x20, 0x20 + ] + ); + } else { + assert!( + false, + "Packet did not parse as an EchoReply {:?}", + pkt.message + ); } assert_eq!(pkt.get_bytes(true), data); assert_eq!(pkt.calculate_checksum(lo, lo), 0x1c2e); } -} \ No newline at end of file +} diff --git a/src/socket.rs b/src/socket.rs index 00359b0..b493adf 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -1,21 +1,21 @@ // Copyright 2021 Jeremy Wall -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::convert::{TryFrom, Into}; +use std::convert::{Into, TryFrom}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; -use socket2::{Socket, Domain, Type, Protocol}; +use socket2::{Domain, Protocol, Socket, Type}; use crate::packet::Icmpv6Packet; @@ -35,17 +35,17 @@ pub struct IcmpSocket4 { impl IcmpSocket4 { pub fn new() -> std::io::Result { - Ok(Self{ + Ok(Self { bound_to: None, inner: Socket::new(Domain::ipv4(), Type::raw(), Some(Protocol::icmpv4()))?, - opts: Opts{ hops: 50 }, + opts: Opts { hops: 50 }, }) } pub fn set_max_hops(&mut self, hops: u32) { self.opts.hops = hops; } - + pub fn bind>(&mut self, addr: A) -> std::io::Result<()> { let addr = addr.into(); self.bound_to = Some(addr.clone()); @@ -61,7 +61,7 @@ impl IcmpSocket4 { self.inner.send_to(payload, &(dest.into()))?; Ok(()) } - + pub fn rcv_from(&self, buf: &mut [u8]) -> std::io::Result { let (read_count, _addr) = self.inner.recv_from(buf)?; Ok(read_count) @@ -75,18 +75,18 @@ pub struct IcmpSocket6 { } impl IcmpSocket6 { - pub fn new()-> std::io::Result { - Ok(Self{ + pub fn new() -> std::io::Result { + Ok(Self { bound_to: None, inner: Socket::new(Domain::ipv6(), Type::raw(), Some(Protocol::icmpv6()))?, - opts: Opts{ hops: 50 }, + opts: Opts { hops: 50 }, }) } pub fn set_max_hops(&mut self, hops: u32) { self.opts.hops = hops; } - + pub fn bind>(&mut self, addr: A) -> std::io::Result<()> { let addr = addr.into(); self.bound_to = Some(addr.clone()); @@ -98,7 +98,12 @@ impl IcmpSocket6 { pub fn send_to(&mut self, dest: Ipv6Addr, mut packet: Icmpv6Packet) -> std::io::Result<()> { let source = match self.bound_to { Some(ref addr) => addr, - None => return Err(std::io::Error::new(std::io::ErrorKind::Other, "Socket not bound to an address")), + None => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Socket not bound to an address", + )) + } }; packet = packet.with_checksum(source, &dest); let dest = ip_to_socket(&IpAddr::V6(dest)); @@ -107,7 +112,7 @@ impl IcmpSocket6 { self.inner.send_to(&pkt, &(dest.into()))?; Ok(()) } - + pub fn rcv_from(&self) -> std::io::Result { let mut buf = vec![0; 512]; let (read_count, _addr) = self.inner.recv_from(&mut buf)?; @@ -132,6 +137,6 @@ impl TryFrom for IcmpSocket6 { fn try_from(addr: Ipv6Addr) -> Result { let mut sock = IcmpSocket6::new()?; sock.bind(addr)?; - Ok(sock) + Ok(sock) } }