mirror of
https://github.com/zaphar/icmp-socket.git
synced 2025-07-22 19:30:05 -04:00
More ergonomics and some packet parsing bug fixes
This commit is contained in:
parent
5a7287f10c
commit
a7079afbc4
44
examples/ping4.rs
Normal file
44
examples/ping4.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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::net::Ipv4Addr;
|
||||||
|
|
||||||
|
use icmp_socket::socket::IcmpSocket;
|
||||||
|
use icmp_socket::*;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let mut socket4 = IcmpSocket4::new().unwrap();
|
||||||
|
socket4
|
||||||
|
.bind("0.0.0.0".parse::<Ipv4Addr>().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let mut echo_socket = echo::EchoSocket::new(socket4);
|
||||||
|
echo_socket
|
||||||
|
.send_ping(
|
||||||
|
"127.0.0.1".parse::<Ipv4Addr>().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 resp = echo_socket.recv_ping().unwrap();
|
||||||
|
println!(
|
||||||
|
"seq: {}, identifier: {} payload: {}",
|
||||||
|
resp.sequence,
|
||||||
|
resp.identifier,
|
||||||
|
resp.payload.len()
|
||||||
|
);
|
||||||
|
}
|
@ -19,7 +19,7 @@ use icmp_socket::*;
|
|||||||
pub fn main() {
|
pub fn main() {
|
||||||
let mut socket6 = IcmpSocket6::new().unwrap();
|
let mut socket6 = IcmpSocket6::new().unwrap();
|
||||||
socket6.bind("::1".parse::<Ipv6Addr>().unwrap()).unwrap();
|
socket6.bind("::1".parse::<Ipv6Addr>().unwrap()).unwrap();
|
||||||
let mut echo_socket = echo::EchoSocket6::new(socket6);
|
let mut echo_socket = echo::EchoSocket::new(socket6);
|
||||||
echo_socket
|
echo_socket
|
||||||
.send_ping(
|
.send_ping(
|
||||||
"::1".parse::<Ipv6Addr>().unwrap(),
|
"::1".parse::<Ipv6Addr>().unwrap(),
|
||||||
@ -32,6 +32,8 @@ pub fn main() {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
// TODO(jwall): The first packet we recieve will be the one we sent.
|
||||||
|
// We need to implement packet filtering for the socket.
|
||||||
let _ = echo_socket.recv_ping();
|
let _ = echo_socket.recv_ping();
|
||||||
let resp = echo_socket.recv_ping().unwrap();
|
let resp = echo_socket.recv_ping().unwrap();
|
||||||
println!(
|
println!(
|
||||||
|
80
src/echo.rs
80
src/echo.rs
@ -12,11 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::convert::{From, TryFrom, TryInto};
|
use std::convert::{From, TryFrom, TryInto};
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
packet::{Icmpv4Message, Icmpv4Packet, Icmpv6Message, Icmpv6Packet},
|
packet::{Icmpv4Message, Icmpv4Packet, Icmpv6Message, Icmpv6Packet, WithEchoRequest},
|
||||||
socket::{IcmpSocket, IcmpSocket4, IcmpSocket6},
|
socket::IcmpSocket,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -80,15 +79,21 @@ impl TryFrom<Icmpv4Packet> for EchoResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EchoSocket4 {
|
pub struct EchoSocket<S> {
|
||||||
sequence: u16,
|
sequence: u16,
|
||||||
inner: IcmpSocket4,
|
inner: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jwall): Make this a trait
|
// TODO(jwall): Make this a trait
|
||||||
impl EchoSocket4 {
|
impl<S> EchoSocket<S>
|
||||||
pub fn new(sock: IcmpSocket4) -> Self {
|
where
|
||||||
EchoSocket4 {
|
S: IcmpSocket,
|
||||||
|
S::PacketType: WithEchoRequest<Packet = S::PacketType>
|
||||||
|
+ TryInto<EchoResponse, Error = std::io::Error>
|
||||||
|
+ std::fmt::Debug,
|
||||||
|
{
|
||||||
|
pub fn new(sock: S) -> Self {
|
||||||
|
EchoSocket {
|
||||||
inner: sock,
|
inner: sock,
|
||||||
sequence: 0,
|
sequence: 0,
|
||||||
}
|
}
|
||||||
@ -100,12 +105,12 @@ impl EchoSocket4 {
|
|||||||
|
|
||||||
pub fn send_ping(
|
pub fn send_ping(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Ipv4Addr,
|
dest: S::AddrType,
|
||||||
identifier: u16,
|
identifier: u16,
|
||||||
payload: &[u8],
|
payload: &[u8],
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
let packet =
|
let packet =
|
||||||
Icmpv4Packet::with_echo_request(identifier, self.sequence, payload.to_owned())?;
|
S::PacketType::with_echo_request(identifier, self.sequence, payload.to_owned())?;
|
||||||
self.sequence += 1;
|
self.sequence += 1;
|
||||||
self.inner.send_to(dest, packet)?;
|
self.inner.send_to(dest, packet)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -117,51 +122,14 @@ impl EchoSocket4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IcmpSocket4> for EchoSocket4 {
|
impl<S> From<S> for EchoSocket<S>
|
||||||
fn from(sock: IcmpSocket4) -> Self {
|
where
|
||||||
EchoSocket4::new(sock)
|
S: IcmpSocket,
|
||||||
}
|
S::PacketType: WithEchoRequest<Packet = S::PacketType>
|
||||||
}
|
+ TryInto<EchoResponse, Error = std::io::Error>
|
||||||
|
+ std::fmt::Debug,
|
||||||
pub struct EchoSocket6 {
|
{
|
||||||
sequence: u16,
|
fn from(sock: S) -> Self {
|
||||||
inner: IcmpSocket6,
|
EchoSocket::new(sock)
|
||||||
}
|
|
||||||
|
|
||||||
impl EchoSocket6 {
|
|
||||||
pub fn new(sock: IcmpSocket6) -> Self {
|
|
||||||
// TODO(jwall): How to set ICMPv6 filters.
|
|
||||||
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())?;
|
|
||||||
self.sequence += 1;
|
|
||||||
self.inner.send_to(dest, packet)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_ping(&mut self) -> std::io::Result<EchoResponse> {
|
|
||||||
let pkt = self.inner.rcv_from()?;
|
|
||||||
Ok(pkt.try_into()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IcmpSocket6> for EchoSocket6 {
|
|
||||||
fn from(sock: IcmpSocket6) -> Self {
|
|
||||||
EchoSocket6::new(sock)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@ pub mod echo;
|
|||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod socket;
|
pub mod socket;
|
||||||
|
|
||||||
pub use echo::{EchoSocket4, EchoSocket6};
|
pub use echo::EchoSocket;
|
||||||
pub use packet::{Icmpv4Message, Icmpv4Packet, Icmpv6Message, Icmpv6Packet};
|
pub use packet::{Icmpv4Message, Icmpv4Packet, Icmpv6Message, Icmpv6Packet};
|
||||||
pub use socket::{IcmpSocket, IcmpSocket4, IcmpSocket6};
|
pub use socket::{IcmpSocket, IcmpSocket4, IcmpSocket6};
|
||||||
|
131
src/packet.rs
131
src/packet.rs
@ -42,6 +42,16 @@ fn sum_big_endian_words(bs: &[u8]) -> u32 {
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait WithEchoRequest {
|
||||||
|
type Packet;
|
||||||
|
|
||||||
|
fn with_echo_request(
|
||||||
|
identifier: u16,
|
||||||
|
sequence: u16,
|
||||||
|
payload: Vec<u8>,
|
||||||
|
) -> Result<Self::Packet, IcmpPacketBuildError>;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Icmpv6Message {
|
pub enum Icmpv6Message {
|
||||||
// NOTE(JWALL): All of the below integers should be parsed as big endian on the
|
// NOTE(JWALL): All of the below integers should be parsed as big endian on the
|
||||||
@ -148,7 +158,7 @@ pub struct Icmpv6Packet {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PacketParseError {
|
pub enum PacketParseError {
|
||||||
PacketTooSmall(usize),
|
PacketTooSmall(usize),
|
||||||
UnrecognizedICMPType,
|
UnrecognizedICMPType(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Icmpv6Packet {
|
impl Icmpv6Packet {
|
||||||
@ -193,7 +203,7 @@ impl Icmpv6Packet {
|
|||||||
sequence: BigEndian::read_u16(&bytes[6..8]),
|
sequence: BigEndian::read_u16(&bytes[6..8]),
|
||||||
payload: payload,
|
payload: payload,
|
||||||
},
|
},
|
||||||
_ => return Err(PacketParseError::UnrecognizedICMPType),
|
t => return Err(PacketParseError::UnrecognizedICMPType(t)),
|
||||||
};
|
};
|
||||||
return Ok(Icmpv6Packet {
|
return Ok(Icmpv6Packet {
|
||||||
typ: typ,
|
typ: typ,
|
||||||
@ -249,9 +259,9 @@ impl Icmpv6Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a packet for Destination Unreachable messages.
|
/// Construct a packet for Destination Unreachable messages.
|
||||||
pub fn with_unreachable(code: u8, packet: Vec<u8>) -> Result<Self, Icmpv6PacketBuildError> {
|
pub fn with_unreachable(code: u8, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
|
||||||
if code > 6 {
|
if code > 6 {
|
||||||
return Err(Icmpv6PacketBuildError::InvalidCode(code));
|
return Err(IcmpPacketBuildError::InvalidCode(code));
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 1,
|
typ: 1,
|
||||||
@ -267,7 +277,7 @@ impl Icmpv6Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a packet for Packet Too Big messages.
|
/// Construct a packet for Packet Too Big messages.
|
||||||
pub fn with_packet_too_big(mtu: u32, packet: Vec<u8>) -> Result<Self, Icmpv6PacketBuildError> {
|
pub fn with_packet_too_big(mtu: u32, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 2,
|
typ: 2,
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -282,9 +292,9 @@ impl Icmpv6Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a packet for Time Exceeded messages.
|
/// Construct a packet for Time Exceeded messages.
|
||||||
pub fn with_time_exceeded(code: u8, packet: Vec<u8>) -> Result<Self, Icmpv6PacketBuildError> {
|
pub fn with_time_exceeded(code: u8, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
|
||||||
if code > 1 {
|
if code > 1 {
|
||||||
return Err(Icmpv6PacketBuildError::InvalidCode(code));
|
return Err(IcmpPacketBuildError::InvalidCode(code));
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 3,
|
typ: 3,
|
||||||
@ -304,9 +314,9 @@ impl Icmpv6Packet {
|
|||||||
code: u8,
|
code: u8,
|
||||||
pointer: u32,
|
pointer: u32,
|
||||||
packet: Vec<u8>,
|
packet: Vec<u8>,
|
||||||
) -> Result<Self, Icmpv6PacketBuildError> {
|
) -> Result<Self, IcmpPacketBuildError> {
|
||||||
if code > 1 {
|
if code > 1 {
|
||||||
return Err(Icmpv6PacketBuildError::InvalidCode(code));
|
return Err(IcmpPacketBuildError::InvalidCode(code));
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 4,
|
typ: 4,
|
||||||
@ -319,35 +329,38 @@ impl Icmpv6Packet {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a packet for Echo Request messages.
|
/// Construct a packet for Echo Reply messages.
|
||||||
pub fn with_echo_request(
|
pub fn with_echo_reply(
|
||||||
identifier: u16,
|
identifier: u16,
|
||||||
sequence: u16,
|
sequence: u16,
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
) -> Result<Self, Icmpv6PacketBuildError> {
|
) -> Result<Self, IcmpPacketBuildError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 128,
|
typ: 129,
|
||||||
code: 0,
|
code: 0,
|
||||||
checksum: 0,
|
checksum: 0,
|
||||||
message: EchoRequest {
|
message: EchoReply {
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
sequence: sequence,
|
sequence: sequence,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a packet for Echo Reply messages.
|
impl WithEchoRequest for Icmpv6Packet {
|
||||||
pub fn with_echo_reply(
|
type Packet = Icmpv6Packet;
|
||||||
|
|
||||||
|
fn with_echo_request(
|
||||||
identifier: u16,
|
identifier: u16,
|
||||||
sequence: u16,
|
sequence: u16,
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
) -> Result<Self, Icmpv6PacketBuildError> {
|
) -> Result<Self::Packet, IcmpPacketBuildError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 129,
|
typ: 128,
|
||||||
code: 0,
|
code: 0,
|
||||||
checksum: 0,
|
checksum: 0,
|
||||||
message: EchoReply {
|
message: EchoRequest {
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
sequence: sequence,
|
sequence: sequence,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
@ -364,12 +377,12 @@ impl TryFrom<&[u8]> for Icmpv6Packet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Icmpv6PacketBuildError {
|
pub enum IcmpPacketBuildError {
|
||||||
InvalidCode(u8),
|
InvalidCode(u8),
|
||||||
}
|
}
|
||||||
use Icmpv6PacketBuildError::InvalidCode;
|
use IcmpPacketBuildError::InvalidCode;
|
||||||
|
|
||||||
impl std::fmt::Display for Icmpv6PacketBuildError {
|
impl std::fmt::Display for IcmpPacketBuildError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -388,14 +401,14 @@ impl std::fmt::Display for PacketParseError {
|
|||||||
"{}",
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
PacketParseError::PacketTooSmall(c) => format!("Packet Too Small size: {}", c),
|
PacketParseError::PacketTooSmall(c) => format!("Packet Too Small size: {}", c),
|
||||||
PacketParseError::UnrecognizedICMPType => "UnrecognizedIcmpType".to_owned(),
|
PacketParseError::UnrecognizedICMPType(t) => format!("UnrecognizedIcmpType({})", t),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Icmpv6PacketBuildError> for std::io::Error {
|
impl From<IcmpPacketBuildError> for std::io::Error {
|
||||||
fn from(err: Icmpv6PacketBuildError) -> Self {
|
fn from(err: IcmpPacketBuildError) -> Self {
|
||||||
std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err))
|
std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,12 +609,15 @@ pub struct Icmpv4Packet {
|
|||||||
|
|
||||||
impl Icmpv4Packet {
|
impl Icmpv4Packet {
|
||||||
pub fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PacketParseError> {
|
pub fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PacketParseError> {
|
||||||
let bytes = bytes.as_ref();
|
let mut bytes = bytes.as_ref();
|
||||||
// NOTE(jwall): All ICMP packets are at least 8 bytes long.
|
let mut packet_len = bytes.len();
|
||||||
let packet_len = bytes.len();
|
if bytes.len() < 28 {
|
||||||
if packet_len < 8 {
|
return Err(PacketParseError::PacketTooSmall(packet_len));
|
||||||
return Err(PacketParseError::PacketTooSmall(bytes.len()));
|
|
||||||
}
|
}
|
||||||
|
// NOTE(jwall) Because we use raw sockets the first 20 bytes are the IPv4 header.
|
||||||
|
bytes = &bytes[20..];
|
||||||
|
// NOTE(jwall): All ICMP packets are at least 8 bytes long.
|
||||||
|
packet_len = bytes.len();
|
||||||
let (typ, code, checksum) = (bytes[0], bytes[1], BigEndian::read_u16(&bytes[2..4]));
|
let (typ, code, checksum) = (bytes[0], bytes[1], BigEndian::read_u16(&bytes[2..4]));
|
||||||
let message = match typ {
|
let message = match typ {
|
||||||
3 => Icmpv4Message::Unreachable {
|
3 => Icmpv4Message::Unreachable {
|
||||||
@ -638,8 +654,6 @@ impl Icmpv4Packet {
|
|||||||
identifier: BigEndian::read_u16(&bytes[4..6]),
|
identifier: BigEndian::read_u16(&bytes[4..6]),
|
||||||
sequence: BigEndian::read_u16(&bytes[6..8]),
|
sequence: BigEndian::read_u16(&bytes[6..8]),
|
||||||
},
|
},
|
||||||
// FIXME(jwall): Some of the below have size requirements larger than
|
|
||||||
// 8
|
|
||||||
13 => {
|
13 => {
|
||||||
if packet_len < 20 {
|
if packet_len < 20 {
|
||||||
return Err(PacketParseError::PacketTooSmall(bytes.len()));
|
return Err(PacketParseError::PacketTooSmall(bytes.len()));
|
||||||
@ -664,7 +678,10 @@ impl Icmpv4Packet {
|
|||||||
transmit: BigEndian::read_u32(&bytes[16..20]),
|
transmit: BigEndian::read_u32(&bytes[16..20]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(PacketParseError::UnrecognizedICMPType),
|
t => {
|
||||||
|
dbg!(bytes);
|
||||||
|
return Err(PacketParseError::UnrecognizedICMPType(t));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return Ok(Icmpv4Packet {
|
return Ok(Icmpv4Packet {
|
||||||
typ: typ,
|
typ: typ,
|
||||||
@ -679,8 +696,7 @@ impl Icmpv4Packet {
|
|||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
bytes.push(self.typ);
|
bytes.push(self.typ);
|
||||||
bytes.push(self.code);
|
bytes.push(self.code);
|
||||||
let mut buf = Vec::with_capacity(2);
|
let mut buf = vec![0; 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 buf);
|
||||||
bytes.append(&mut self.message.get_bytes());
|
bytes.append(&mut self.message.get_bytes());
|
||||||
@ -709,12 +725,23 @@ impl Icmpv4Packet {
|
|||||||
self.checksum = self.calculate_checksum();
|
self.checksum = self.calculate_checksum();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_echo_request(
|
impl TryFrom<&[u8]> for Icmpv4Packet {
|
||||||
|
type Error = PacketParseError;
|
||||||
|
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
Icmpv4Packet::parse(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WithEchoRequest for Icmpv4Packet {
|
||||||
|
type Packet = Icmpv4Packet;
|
||||||
|
|
||||||
|
fn with_echo_request(
|
||||||
identifier: u16,
|
identifier: u16,
|
||||||
sequence: u16,
|
sequence: u16,
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
) -> Result<Self, Icmpv6PacketBuildError> {
|
) -> Result<Self::Packet, IcmpPacketBuildError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
typ: 8,
|
typ: 8,
|
||||||
code: 0,
|
code: 0,
|
||||||
@ -726,34 +753,10 @@ impl Icmpv4Packet {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_echo_reply(
|
|
||||||
identifier: u16,
|
|
||||||
sequence: u16,
|
|
||||||
payload: Vec<u8>,
|
|
||||||
) -> Result<Self, Icmpv6PacketBuildError> {
|
|
||||||
Ok(Self {
|
|
||||||
typ: 0,
|
|
||||||
code: 0,
|
|
||||||
checksum: 0,
|
|
||||||
message: Icmpv4Message::EchoReply {
|
|
||||||
identifier,
|
|
||||||
sequence,
|
|
||||||
payload,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&[u8]> for Icmpv4Packet {
|
|
||||||
type Error = PacketParseError;
|
|
||||||
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
|
|
||||||
Icmpv4Packet::parse(b)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod checksum_tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -819,7 +822,7 @@ mod checksum_tests {
|
|||||||
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());
|
assert!(pkt.is_err());
|
||||||
let e = pkt.unwrap_err();
|
let e = pkt.unwrap_err();
|
||||||
assert_eq!(e, Icmpv6PacketBuildError::InvalidCode(2));
|
assert_eq!(e, IcmpPacketBuildError::InvalidCode(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -842,7 +845,7 @@ mod checksum_tests {
|
|||||||
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());
|
assert!(pkt.is_err());
|
||||||
let e = pkt.unwrap_err();
|
let e = pkt.unwrap_err();
|
||||||
assert_eq!(e, Icmpv6PacketBuildError::InvalidCode(3));
|
assert_eq!(e, IcmpPacketBuildError::InvalidCode(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user