Add support for IPv6 to ICMP sockets.
Closes: #205 Approved by: whitequark
This commit is contained in:
parent
435292cc35
commit
2afc538fd9
|
@ -20,6 +20,8 @@ use wire::{ArpPacket, ArpRepr, ArpOperation};
|
||||||
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
|
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
use wire::{Icmpv6Packet, Icmpv6Repr, Icmpv6ParamProblem};
|
use wire::{Icmpv6Packet, Icmpv6Repr, Icmpv6ParamProblem};
|
||||||
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
|
use wire::IcmpRepr;
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
use wire::{NdiscNeighborFlags, NdiscRepr};
|
use wire::{NdiscNeighborFlags, NdiscRepr};
|
||||||
#[cfg(all(feature = "proto-ipv6", feature = "socket-udp"))]
|
#[cfg(all(feature = "proto-ipv6", feature = "socket-udp"))]
|
||||||
|
@ -32,7 +34,7 @@ use wire::{TcpPacket, TcpRepr, TcpControl};
|
||||||
use socket::{Socket, SocketSet, AnySocket};
|
use socket::{Socket, SocketSet, AnySocket};
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
use socket::RawSocket;
|
use socket::RawSocket;
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
use socket::IcmpSocket;
|
use socket::IcmpSocket;
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
use socket::UdpSocket;
|
use socket::UdpSocket;
|
||||||
|
@ -424,13 +426,16 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
||||||
Socket::Raw(ref mut socket) =>
|
Socket::Raw(ref mut socket) =>
|
||||||
socket.dispatch(&caps.checksum, |response|
|
socket.dispatch(&caps.checksum, |response|
|
||||||
respond!(Packet::Raw(response))),
|
respond!(Packet::Raw(response))),
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
Socket::Icmp(ref mut socket) =>
|
Socket::Icmp(ref mut socket) =>
|
||||||
socket.dispatch(&caps, |response| {
|
socket.dispatch(&caps, |response| {
|
||||||
match response {
|
match response {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
(IpRepr::Ipv4(ipv4_repr), icmpv4_repr) =>
|
(IpRepr::Ipv4(ipv4_repr), IcmpRepr::Ipv4(icmpv4_repr)) =>
|
||||||
respond!(Packet::Icmpv4((ipv4_repr, icmpv4_repr))),
|
respond!(Packet::Icmpv4((ipv4_repr, icmpv4_repr))),
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
(IpRepr::Ipv6(ipv6_repr), IcmpRepr::Ipv6(icmpv6_repr)) =>
|
||||||
|
respond!(Packet::Icmpv6((ipv6_repr, icmpv6_repr))),
|
||||||
_ => Err(Error::Unaddressable)
|
_ => Err(Error::Unaddressable)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -746,6 +751,23 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
let icmp_repr = Icmpv6Repr::parse(&ip_repr.src_addr(), &ip_repr.dst_addr(),
|
let icmp_repr = Icmpv6Repr::parse(&ip_repr.src_addr(), &ip_repr.dst_addr(),
|
||||||
&icmp_packet, &checksum_caps)?;
|
&icmp_packet, &checksum_caps)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "socket-icmp")]
|
||||||
|
let mut handled_by_icmp_socket = false;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv6"))]
|
||||||
|
for mut icmp_socket in _sockets.iter_mut().filter_map(IcmpSocket::downcast) {
|
||||||
|
if !icmp_socket.accepts(&ip_repr, &icmp_repr.into(), &checksum_caps) { continue }
|
||||||
|
|
||||||
|
match icmp_socket.process(&ip_repr, &icmp_repr.into(), &checksum_caps) {
|
||||||
|
// The packet is valid and handled by socket.
|
||||||
|
Ok(()) => handled_by_icmp_socket = true,
|
||||||
|
// The socket buffer is full.
|
||||||
|
Err(Error::Exhausted) => (),
|
||||||
|
// ICMP sockets don't validate the packets in any way.
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match icmp_repr {
|
match icmp_repr {
|
||||||
// Respond to echo requests.
|
// Respond to echo requests.
|
||||||
Icmpv6Repr::EchoRequest { ident, seq_no, data } => {
|
Icmpv6Repr::EchoRequest { ident, seq_no, data } => {
|
||||||
|
@ -771,6 +793,11 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
_ => Ok(Packet::None)
|
_ => Ok(Packet::None)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Don't report an error if a packet with unknown type
|
||||||
|
// has been handled by an ICMP socket
|
||||||
|
#[cfg(feature = "socket-icmp")]
|
||||||
|
_ if handled_by_icmp_socket => Ok(Packet::None),
|
||||||
|
|
||||||
// FIXME: do something correct here?
|
// FIXME: do something correct here?
|
||||||
_ => Err(Error::Unrecognized),
|
_ => Err(Error::Unrecognized),
|
||||||
}
|
}
|
||||||
|
@ -839,9 +866,9 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
|
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
||||||
for mut icmp_socket in _sockets.iter_mut().filter_map(IcmpSocket::downcast) {
|
for mut icmp_socket in _sockets.iter_mut().filter_map(IcmpSocket::downcast) {
|
||||||
if !icmp_socket.accepts(&ip_repr, &icmp_repr, &checksum_caps) { continue }
|
if !icmp_socket.accepts(&ip_repr, &icmp_repr.into(), &checksum_caps) { continue }
|
||||||
|
|
||||||
match icmp_socket.process(&ip_repr, &icmp_repr, &checksum_caps) {
|
match icmp_socket.process(&ip_repr, &icmp_repr.into(), &checksum_caps) {
|
||||||
// The packet is valid and handled by socket.
|
// The packet is valid and handled by socket.
|
||||||
Ok(()) => handled_by_icmp_socket = true,
|
Ok(()) => handled_by_icmp_socket = true,
|
||||||
// The socket buffer is full.
|
// The socket buffer is full.
|
||||||
|
@ -853,6 +880,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
|
|
||||||
match icmp_repr {
|
match icmp_repr {
|
||||||
// Respond to echo requests.
|
// Respond to echo requests.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
Icmpv4Repr::EchoRequest { ident, seq_no, data } => {
|
Icmpv4Repr::EchoRequest { ident, seq_no, data } => {
|
||||||
let icmp_reply_repr = Icmpv4Repr::EchoReply {
|
let icmp_reply_repr = Icmpv4Repr::EchoReply {
|
||||||
ident: ident,
|
ident: ident,
|
||||||
|
@ -863,7 +891,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
IpRepr::Ipv4(ipv4_repr) => Ok(self.icmpv4_reply(ipv4_repr, icmp_reply_repr)),
|
IpRepr::Ipv4(ipv4_repr) => Ok(self.icmpv4_reply(ipv4_repr, icmp_reply_repr)),
|
||||||
_ => Err(Error::Unrecognized),
|
_ => Err(Error::Unrecognized),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
// Ignore any echo replies.
|
// Ignore any echo replies.
|
||||||
Icmpv4Repr::EchoReply { .. } => Ok(Packet::None),
|
Icmpv4Repr::EchoReply { .. } => Ok(Packet::None),
|
||||||
|
|
|
@ -6,8 +6,12 @@ use socket::{Socket, SocketMeta, SocketHandle};
|
||||||
use storage::{PacketBuffer, PacketMetadata};
|
use storage::{PacketBuffer, PacketMetadata};
|
||||||
use time::Instant;
|
use time::Instant;
|
||||||
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
||||||
use wire::{Ipv4Address, Ipv4Repr};
|
|
||||||
use wire::{Icmpv4Packet, Icmpv4Repr};
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
use wire::{Ipv4Address, Ipv4Repr, Icmpv4Packet, Icmpv4Repr};
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
use wire::{Ipv6Address, Ipv6Repr, Icmpv6Packet, Icmpv6Repr};
|
||||||
|
use wire::IcmpRepr;
|
||||||
use wire::{UdpPacket, UdpRepr};
|
use wire::{UdpPacket, UdpRepr};
|
||||||
|
|
||||||
/// Type of endpoint to bind the ICMP socket to. See [IcmpSocket::bind] for
|
/// Type of endpoint to bind the ICMP socket to. See [IcmpSocket::bind] for
|
||||||
|
@ -244,13 +248,23 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
|
|
||||||
/// Filter determining which packets received by the interface are appended to
|
/// Filter determining which packets received by the interface are appended to
|
||||||
/// the given sockets received buffer.
|
/// the given sockets received buffer.
|
||||||
pub(crate) fn accepts(&self, ip_repr: &IpRepr, icmp_repr: &Icmpv4Repr,
|
pub(crate) fn accepts(&self, ip_repr: &IpRepr, icmp_repr: &IcmpRepr,
|
||||||
cksum: &ChecksumCapabilities) -> bool {
|
cksum: &ChecksumCapabilities) -> bool {
|
||||||
match (&self.endpoint, icmp_repr) {
|
match (&self.endpoint, icmp_repr) {
|
||||||
// If we are bound to ICMP errors associated to a UDP port, only
|
// If we are bound to ICMP errors associated to a UDP port, only
|
||||||
// accept Destination Unreachable messages with the data containing
|
// accept Destination Unreachable messages with the data containing
|
||||||
// a UDP packet send from the local port we are bound to.
|
// a UDP packet send from the local port we are bound to.
|
||||||
(&Endpoint::Udp(endpoint), &Icmpv4Repr::DstUnreachable { data, .. })
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
(&Endpoint::Udp(endpoint), &IcmpRepr::Ipv4(Icmpv4Repr::DstUnreachable { data, .. }))
|
||||||
|
if endpoint.addr.is_unspecified() || endpoint.addr == ip_repr.dst_addr() => {
|
||||||
|
let packet = UdpPacket::new(data);
|
||||||
|
match UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr(), cksum) {
|
||||||
|
Ok(repr) => endpoint.port == repr.src_port,
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
(&Endpoint::Udp(endpoint), &IcmpRepr::Ipv6(Icmpv6Repr::DstUnreachable { data, .. }))
|
||||||
if endpoint.addr.is_unspecified() || endpoint.addr == ip_repr.dst_addr() => {
|
if endpoint.addr.is_unspecified() || endpoint.addr == ip_repr.dst_addr() => {
|
||||||
let packet = UdpPacket::new(data);
|
let packet = UdpPacket::new(data);
|
||||||
match UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr(), cksum) {
|
match UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr(), cksum) {
|
||||||
|
@ -261,25 +275,44 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
// If we are bound to a specific ICMP identifier value, only accept an
|
// If we are bound to a specific ICMP identifier value, only accept an
|
||||||
// Echo Request/Reply with the identifier field matching the endpoint
|
// Echo Request/Reply with the identifier field matching the endpoint
|
||||||
// port.
|
// port.
|
||||||
(&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoRequest { ident, .. }) |
|
#[cfg(feature = "proto-ipv4")]
|
||||||
(&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoReply { ident, .. }) =>
|
(&Endpoint::Ident(bound_ident), &IcmpRepr::Ipv4(Icmpv4Repr::EchoRequest { ident, .. })) |
|
||||||
|
(&Endpoint::Ident(bound_ident), &IcmpRepr::Ipv4(Icmpv4Repr::EchoReply { ident, .. })) =>
|
||||||
|
ident == bound_ident,
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
(&Endpoint::Ident(bound_ident), &IcmpRepr::Ipv6(Icmpv6Repr::EchoRequest { ident, .. })) |
|
||||||
|
(&Endpoint::Ident(bound_ident), &IcmpRepr::Ipv6(Icmpv6Repr::EchoReply { ident, .. })) =>
|
||||||
ident == bound_ident,
|
ident == bound_ident,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process(&mut self, ip_repr: &IpRepr, icmp_repr: &Icmpv4Repr,
|
pub(crate) fn process(&mut self, ip_repr: &IpRepr, icmp_repr: &IcmpRepr,
|
||||||
_cksum: &ChecksumCapabilities) -> Result<()> {
|
_cksum: &ChecksumCapabilities) -> Result<()> {
|
||||||
let packet_buf = self.rx_buffer.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
|
match icmp_repr {
|
||||||
icmp_repr.emit(&mut Icmpv4Packet::new(packet_buf), &ChecksumCapabilities::default());
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
&IcmpRepr::Ipv4(ref icmp_repr) => {
|
||||||
|
let packet_buf = self.rx_buffer.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
|
||||||
|
icmp_repr.emit(&mut Icmpv4Packet::new(packet_buf), &ChecksumCapabilities::default());
|
||||||
|
|
||||||
net_trace!("{}:{}: receiving {} octets",
|
net_trace!("{}:{}: receiving {} octets",
|
||||||
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
||||||
|
},
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
&IcmpRepr::Ipv6(ref icmp_repr) => {
|
||||||
|
let packet_buf = self.rx_buffer.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
|
||||||
|
icmp_repr.emit(&ip_repr.src_addr(), &ip_repr.dst_addr(),
|
||||||
|
&mut Icmpv6Packet::new(packet_buf), &ChecksumCapabilities::default());
|
||||||
|
|
||||||
|
net_trace!("{}:{}: receiving {} octets",
|
||||||
|
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
||||||
|
},
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn dispatch<F>(&mut self, _caps: &DeviceCapabilities, emit: F) -> Result<()>
|
pub(crate) fn dispatch<F>(&mut self, _caps: &DeviceCapabilities, emit: F) -> Result<()>
|
||||||
where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()>
|
where F: FnOnce((IpRepr, IcmpRepr)) -> Result<()>
|
||||||
{
|
{
|
||||||
let handle = self.meta.handle;
|
let handle = self.meta.handle;
|
||||||
let hop_limit = self.hop_limit.unwrap_or(64);
|
let hop_limit = self.hop_limit.unwrap_or(64);
|
||||||
|
@ -287,9 +320,10 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
net_trace!("{}:{}: sending {} octets",
|
net_trace!("{}:{}: sending {} octets",
|
||||||
handle, remote_endpoint, packet_buf.len());
|
handle, remote_endpoint, packet_buf.len());
|
||||||
match *remote_endpoint {
|
match *remote_endpoint {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
IpAddress::Ipv4(ipv4_addr) => {
|
IpAddress::Ipv4(ipv4_addr) => {
|
||||||
let packet = Icmpv4Packet::new(&*packet_buf);
|
let packet = Icmpv4Packet::new(&*packet_buf);
|
||||||
let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::default())?;
|
let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored())?;
|
||||||
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
|
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
|
||||||
src_addr: Ipv4Address::default(),
|
src_addr: Ipv4Address::default(),
|
||||||
dst_addr: ipv4_addr,
|
dst_addr: ipv4_addr,
|
||||||
|
@ -297,7 +331,21 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
payload_len: repr.buffer_len(),
|
payload_len: repr.buffer_len(),
|
||||||
hop_limit: hop_limit,
|
hop_limit: hop_limit,
|
||||||
});
|
});
|
||||||
emit((ip_repr, repr))
|
emit((ip_repr, IcmpRepr::Ipv4(repr)))
|
||||||
|
},
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
IpAddress::Ipv6(ipv6_addr) => {
|
||||||
|
let packet = Icmpv6Packet::new(&*packet_buf);
|
||||||
|
let src_addr = Ipv6Address::default();
|
||||||
|
let repr = Icmpv6Repr::parse(&src_addr.into(), &ipv6_addr.into(), &packet, &ChecksumCapabilities::ignored())?;
|
||||||
|
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
|
||||||
|
src_addr: src_addr,
|
||||||
|
dst_addr: ipv6_addr,
|
||||||
|
next_header: IpProtocol::Icmp,
|
||||||
|
payload_len: repr.buffer_len(),
|
||||||
|
hop_limit: hop_limit,
|
||||||
|
});
|
||||||
|
emit((ip_repr, IcmpRepr::Ipv6(repr)))
|
||||||
},
|
},
|
||||||
_ => Err(Error::Unaddressable)
|
_ => Err(Error::Unaddressable)
|
||||||
}
|
}
|
||||||
|
@ -320,40 +368,46 @@ impl<'a, 'b> Into<Socket<'a, 'b>> for IcmpSocket<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod tests_common {
|
||||||
use phy::DeviceCapabilities;
|
pub use phy::DeviceCapabilities;
|
||||||
use wire::{IpAddress, Icmpv4DstUnreachable};
|
pub use wire::IpAddress;
|
||||||
use super::*;
|
pub use super::*;
|
||||||
|
|
||||||
fn buffer(packets: usize) -> IcmpSocketBuffer<'static, 'static> {
|
pub fn buffer(packets: usize) -> IcmpSocketBuffer<'static, 'static> {
|
||||||
IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY; packets], vec![0; 46 * packets])
|
IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY; packets], vec![0; 66 * packets])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn socket(rx_buffer: IcmpSocketBuffer<'static, 'static>,
|
pub fn socket(rx_buffer: IcmpSocketBuffer<'static, 'static>,
|
||||||
tx_buffer: IcmpSocketBuffer<'static, 'static>) -> IcmpSocket<'static, 'static> {
|
tx_buffer: IcmpSocketBuffer<'static, 'static>) -> IcmpSocket<'static, 'static> {
|
||||||
IcmpSocket::new(rx_buffer, tx_buffer)
|
IcmpSocket::new(rx_buffer, tx_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const LOCAL_PORT: u16 = 53;
|
||||||
|
|
||||||
|
pub static UDP_REPR: UdpRepr = UdpRepr {
|
||||||
|
src_port: 53,
|
||||||
|
dst_port: 9090,
|
||||||
|
payload: &[0xff; 10]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, feature = "proto-ipv4"))]
|
||||||
|
mod test_ipv4 {
|
||||||
|
use super::tests_common::*;
|
||||||
|
|
||||||
|
use wire::Icmpv4DstUnreachable;
|
||||||
|
|
||||||
const REMOTE_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
|
const REMOTE_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
|
||||||
const LOCAL_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
|
const LOCAL_IPV4: Ipv4Address = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
|
||||||
const REMOTE_IP: IpAddress = IpAddress::Ipv4(REMOTE_IPV4);
|
const LOCAL_END_V4: IpEndpoint = IpEndpoint { addr: IpAddress::Ipv4(LOCAL_IPV4), port: LOCAL_PORT };
|
||||||
const LOCAL_IP: IpAddress = IpAddress::Ipv4(LOCAL_IPV4);
|
|
||||||
const LOCAL_PORT: u16 = 53;
|
|
||||||
const LOCAL_END: IpEndpoint = IpEndpoint { addr: LOCAL_IP, port: LOCAL_PORT };
|
|
||||||
|
|
||||||
static ECHO_REPR: Icmpv4Repr = Icmpv4Repr::EchoRequest {
|
static ECHOV4_REPR: Icmpv4Repr = Icmpv4Repr::EchoRequest {
|
||||||
ident: 0x1234,
|
ident: 0x1234,
|
||||||
seq_no: 0x5678,
|
seq_no: 0x5678,
|
||||||
data: &[0xff; 16]
|
data: &[0xff; 16]
|
||||||
};
|
};
|
||||||
|
|
||||||
static UDP_REPR: UdpRepr = UdpRepr {
|
static LOCAL_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
|
||||||
src_port: 53,
|
|
||||||
dst_port: 9090,
|
|
||||||
payload: &[0xff; 10]
|
|
||||||
};
|
|
||||||
|
|
||||||
static LOCAL_IP_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
|
|
||||||
src_addr: Ipv4Address::UNSPECIFIED,
|
src_addr: Ipv4Address::UNSPECIFIED,
|
||||||
dst_addr: REMOTE_IPV4,
|
dst_addr: REMOTE_IPV4,
|
||||||
protocol: IpProtocol::Icmp,
|
protocol: IpProtocol::Icmp,
|
||||||
|
@ -361,7 +415,7 @@ mod test {
|
||||||
hop_limit: 0x40
|
hop_limit: 0x40
|
||||||
});
|
});
|
||||||
|
|
||||||
static REMOTE_IP_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
|
static REMOTE_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
|
||||||
src_addr: REMOTE_IPV4,
|
src_addr: REMOTE_IPV4,
|
||||||
dst_addr: LOCAL_IPV4,
|
dst_addr: LOCAL_IPV4,
|
||||||
protocol: IpProtocol::Icmp,
|
protocol: IpProtocol::Icmp,
|
||||||
|
@ -374,7 +428,7 @@ mod test {
|
||||||
let mut socket = socket(buffer(0), buffer(1));
|
let mut socket = socket(buffer(0), buffer(1));
|
||||||
assert_eq!(socket.send_slice(b"abcdef", IpAddress::default()),
|
assert_eq!(socket.send_slice(b"abcdef", IpAddress::default()),
|
||||||
Err(Error::Unaddressable));
|
Err(Error::Unaddressable));
|
||||||
assert_eq!(socket.send_slice(b"abcdef", REMOTE_IP), Ok(()));
|
assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -386,28 +440,28 @@ mod test {
|
||||||
Err(Error::Exhausted));
|
Err(Error::Exhausted));
|
||||||
|
|
||||||
// This buffer is too long
|
// This buffer is too long
|
||||||
assert_eq!(socket.send_slice(&[0xff; 47], REMOTE_IP), Err(Error::Truncated));
|
assert_eq!(socket.send_slice(&[0xff; 67], REMOTE_IPV4.into()), Err(Error::Truncated));
|
||||||
assert!(socket.can_send());
|
assert!(socket.can_send());
|
||||||
|
|
||||||
let mut bytes = [0xff; 24];
|
let mut bytes = [0xff; 24];
|
||||||
let mut packet = Icmpv4Packet::new(&mut bytes);
|
let mut packet = Icmpv4Packet::new(&mut bytes);
|
||||||
ECHO_REPR.emit(&mut packet, &caps.checksum);
|
ECHOV4_REPR.emit(&mut packet, &caps.checksum);
|
||||||
|
|
||||||
assert_eq!(socket.send_slice(&packet.into_inner()[..], REMOTE_IP), Ok(()));
|
assert_eq!(socket.send_slice(&packet.into_inner()[..], REMOTE_IPV4.into()), Ok(()));
|
||||||
assert_eq!(socket.send_slice(b"123456", REMOTE_IP), Err(Error::Exhausted));
|
assert_eq!(socket.send_slice(b"123456", REMOTE_IPV4.into()), Err(Error::Exhausted));
|
||||||
assert!(!socket.can_send());
|
assert!(!socket.can_send());
|
||||||
|
|
||||||
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
||||||
assert_eq!(ip_repr, LOCAL_IP_REPR);
|
assert_eq!(ip_repr, LOCAL_IPV4_REPR);
|
||||||
assert_eq!(icmp_repr, ECHO_REPR);
|
assert_eq!(icmp_repr, ECHOV4_REPR.into());
|
||||||
Err(Error::Unaddressable)
|
Err(Error::Unaddressable)
|
||||||
}), Err(Error::Unaddressable));
|
}), Err(Error::Unaddressable));
|
||||||
// buffer is not taken off of the tx queue due to the error
|
// buffer is not taken off of the tx queue due to the error
|
||||||
assert!(!socket.can_send());
|
assert!(!socket.can_send());
|
||||||
|
|
||||||
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
||||||
assert_eq!(ip_repr, LOCAL_IP_REPR);
|
assert_eq!(ip_repr, LOCAL_IPV4_REPR);
|
||||||
assert_eq!(icmp_repr, ECHO_REPR);
|
assert_eq!(icmp_repr, ECHOV4_REPR.into());
|
||||||
Ok(())
|
Ok(())
|
||||||
}), Ok(()));
|
}), Ok(()));
|
||||||
// buffer is taken off of the queue this time
|
// buffer is taken off of the queue this time
|
||||||
|
@ -415,23 +469,23 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set_hop_limit() {
|
fn test_set_hop_limit_v4() {
|
||||||
let mut s = socket(buffer(0), buffer(1));
|
let mut s = socket(buffer(0), buffer(1));
|
||||||
let caps = DeviceCapabilities::default();
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
let mut bytes = [0xff; 24];
|
let mut bytes = [0xff; 24];
|
||||||
let mut packet = Icmpv4Packet::new(&mut bytes);
|
let mut packet = Icmpv4Packet::new(&mut bytes);
|
||||||
ECHO_REPR.emit(&mut packet, &caps.checksum);
|
ECHOV4_REPR.emit(&mut packet, &caps.checksum);
|
||||||
|
|
||||||
s.set_hop_limit(Some(0x2a));
|
s.set_hop_limit(Some(0x2a));
|
||||||
|
|
||||||
assert_eq!(s.send_slice(&packet.into_inner()[..], REMOTE_IP), Ok(()));
|
assert_eq!(s.send_slice(&packet.into_inner()[..], REMOTE_IPV4.into()), Ok(()));
|
||||||
assert_eq!(s.dispatch(&caps, |(ip_repr, _)| {
|
assert_eq!(s.dispatch(&caps, |(ip_repr, _)| {
|
||||||
assert_eq!(ip_repr, IpRepr::Ipv4(Ipv4Repr {
|
assert_eq!(ip_repr, IpRepr::Ipv4(Ipv4Repr {
|
||||||
src_addr: Ipv4Address::UNSPECIFIED,
|
src_addr: Ipv4Address::UNSPECIFIED,
|
||||||
dst_addr: REMOTE_IPV4,
|
dst_addr: REMOTE_IPV4,
|
||||||
protocol: IpProtocol::Icmp,
|
protocol: IpProtocol::Icmp,
|
||||||
payload_len: ECHO_REPR.buffer_len(),
|
payload_len: ECHOV4_REPR.buffer_len(),
|
||||||
hop_limit: 0x2a,
|
hop_limit: 0x2a,
|
||||||
}));
|
}));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -450,19 +504,19 @@ mod test {
|
||||||
|
|
||||||
let mut bytes = [0xff; 24];
|
let mut bytes = [0xff; 24];
|
||||||
let mut packet = Icmpv4Packet::new(&mut bytes);
|
let mut packet = Icmpv4Packet::new(&mut bytes);
|
||||||
ECHO_REPR.emit(&mut packet, &caps.checksum);
|
ECHOV4_REPR.emit(&mut packet, &caps.checksum);
|
||||||
let data = &packet.into_inner()[..];
|
let data = &packet.into_inner()[..];
|
||||||
|
|
||||||
assert!(socket.accepts(&REMOTE_IP_REPR, &ECHO_REPR, &caps.checksum));
|
assert!(socket.accepts(&REMOTE_IPV4_REPR, &ECHOV4_REPR.into(), &caps.checksum));
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &ECHO_REPR, &caps.checksum),
|
assert_eq!(socket.process(&REMOTE_IPV4_REPR, &ECHOV4_REPR.into(), &caps.checksum),
|
||||||
Ok(()));
|
Ok(()));
|
||||||
assert!(socket.can_recv());
|
assert!(socket.can_recv());
|
||||||
|
|
||||||
assert!(socket.accepts(&REMOTE_IP_REPR, &ECHO_REPR, &caps.checksum));
|
assert!(socket.accepts(&REMOTE_IPV4_REPR, &ECHOV4_REPR.into(), &caps.checksum));
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &ECHO_REPR, &caps.checksum),
|
assert_eq!(socket.process(&REMOTE_IPV4_REPR, &ECHOV4_REPR.into(), &caps.checksum),
|
||||||
Err(Error::Exhausted));
|
Err(Error::Exhausted));
|
||||||
|
|
||||||
assert_eq!(socket.recv(), Ok((&data[..], REMOTE_IP)));
|
assert_eq!(socket.recv(), Ok((&data[..], REMOTE_IPV4.into())));
|
||||||
assert!(!socket.can_recv());
|
assert!(!socket.can_recv());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,19 +537,19 @@ mod test {
|
||||||
|
|
||||||
// Ensure that a packet with an identifier that isn't the bound
|
// Ensure that a packet with an identifier that isn't the bound
|
||||||
// ID is not accepted
|
// ID is not accepted
|
||||||
assert!(!socket.accepts(&REMOTE_IP_REPR, &icmp_repr, &caps.checksum));
|
assert!(!socket.accepts(&REMOTE_IPV4_REPR, &icmp_repr.into(), &caps.checksum));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_accepts_udp() {
|
fn test_accepts_udp() {
|
||||||
let mut socket = socket(buffer(1), buffer(1));
|
let mut socket = socket(buffer(1), buffer(1));
|
||||||
assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END)), Ok(()));
|
assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V4)), Ok(()));
|
||||||
|
|
||||||
let caps = DeviceCapabilities::default();
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
let mut bytes = [0xff; 18];
|
let mut bytes = [0xff; 18];
|
||||||
let mut packet = UdpPacket::new(&mut bytes);
|
let mut packet = UdpPacket::new(&mut bytes);
|
||||||
UDP_REPR.emit(&mut packet, &REMOTE_IP, &LOCAL_IP, &caps.checksum);
|
UDP_REPR.emit(&mut packet, &REMOTE_IPV4.into(), &LOCAL_IPV4.into(), &caps.checksum);
|
||||||
|
|
||||||
let data = &packet.into_inner()[..];
|
let data = &packet.into_inner()[..];
|
||||||
|
|
||||||
|
@ -511,8 +565,8 @@ mod test {
|
||||||
data: data
|
data: data
|
||||||
};
|
};
|
||||||
let ip_repr = IpRepr::Unspecified {
|
let ip_repr = IpRepr::Unspecified {
|
||||||
src_addr: REMOTE_IP,
|
src_addr: REMOTE_IPV4.into(),
|
||||||
dst_addr: LOCAL_IP,
|
dst_addr: LOCAL_IPV4.into(),
|
||||||
protocol: IpProtocol::Icmp,
|
protocol: IpProtocol::Icmp,
|
||||||
payload_len: icmp_repr.buffer_len(),
|
payload_len: icmp_repr.buffer_len(),
|
||||||
hop_limit: 0x40
|
hop_limit: 0x40
|
||||||
|
@ -522,15 +576,214 @@ mod test {
|
||||||
|
|
||||||
// Ensure we can accept ICMP error response to the bound
|
// Ensure we can accept ICMP error response to the bound
|
||||||
// UDP port
|
// UDP port
|
||||||
assert!(socket.accepts(&ip_repr, &icmp_repr, &caps.checksum));
|
assert!(socket.accepts(&ip_repr, &icmp_repr.into(), &caps.checksum));
|
||||||
assert_eq!(socket.process(&ip_repr, &icmp_repr, &caps.checksum),
|
assert_eq!(socket.process(&ip_repr, &icmp_repr.into(), &caps.checksum),
|
||||||
Ok(()));
|
Ok(()));
|
||||||
assert!(socket.can_recv());
|
assert!(socket.can_recv());
|
||||||
|
|
||||||
let mut bytes = [0x00; 46];
|
let mut bytes = [0x00; 46];
|
||||||
let mut packet = Icmpv4Packet::new(&mut bytes[..]);
|
let mut packet = Icmpv4Packet::new(&mut bytes[..]);
|
||||||
icmp_repr.emit(&mut packet, &caps.checksum);
|
icmp_repr.emit(&mut packet, &caps.checksum);
|
||||||
assert_eq!(socket.recv(), Ok((&packet.into_inner()[..], REMOTE_IP)));
|
assert_eq!(socket.recv(), Ok((&packet.into_inner()[..], REMOTE_IPV4.into())));
|
||||||
|
assert!(!socket.can_recv());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, feature = "proto-ipv6"))]
|
||||||
|
mod test_ipv6 {
|
||||||
|
use super::tests_common::*;
|
||||||
|
|
||||||
|
use wire::Icmpv6DstUnreachable;
|
||||||
|
|
||||||
|
const REMOTE_IPV6: Ipv6Address = Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
|
const LOCAL_IPV6: Ipv6Address = Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 2]);
|
||||||
|
const LOCAL_END_V6: IpEndpoint = IpEndpoint { addr: IpAddress::Ipv6(LOCAL_IPV6), port: LOCAL_PORT };
|
||||||
|
static ECHOV6_REPR: Icmpv6Repr = Icmpv6Repr::EchoRequest {
|
||||||
|
ident: 0x1234,
|
||||||
|
seq_no: 0x5678,
|
||||||
|
data: &[0xff; 16]
|
||||||
|
};
|
||||||
|
|
||||||
|
static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
|
||||||
|
src_addr: Ipv6Address::UNSPECIFIED,
|
||||||
|
dst_addr: REMOTE_IPV6,
|
||||||
|
next_header: IpProtocol::Icmp,
|
||||||
|
payload_len: 24,
|
||||||
|
hop_limit: 0x40
|
||||||
|
});
|
||||||
|
|
||||||
|
static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
|
||||||
|
src_addr: REMOTE_IPV6,
|
||||||
|
dst_addr: LOCAL_IPV6,
|
||||||
|
next_header: IpProtocol::Icmp,
|
||||||
|
payload_len: 24,
|
||||||
|
hop_limit: 0x40
|
||||||
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_send_unaddressable() {
|
||||||
|
let mut socket = socket(buffer(0), buffer(1));
|
||||||
|
assert_eq!(socket.send_slice(b"abcdef", IpAddress::default()),
|
||||||
|
Err(Error::Unaddressable));
|
||||||
|
assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_send_dispatch() {
|
||||||
|
let mut socket = socket(buffer(0), buffer(1));
|
||||||
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
|
assert_eq!(socket.dispatch(&caps, |_| unreachable!()),
|
||||||
|
Err(Error::Exhausted));
|
||||||
|
|
||||||
|
// This buffer is too long
|
||||||
|
assert_eq!(socket.send_slice(&[0xff; 67], REMOTE_IPV6.into()), Err(Error::Truncated));
|
||||||
|
assert!(socket.can_send());
|
||||||
|
|
||||||
|
let mut bytes = vec![0xff; 24];
|
||||||
|
let mut packet = Icmpv6Packet::new(&mut bytes);
|
||||||
|
ECHOV6_REPR.emit(&LOCAL_IPV6.into(), &REMOTE_IPV6.into(), &mut packet, &caps.checksum);
|
||||||
|
|
||||||
|
assert_eq!(socket.send_slice(&packet.into_inner()[..], REMOTE_IPV6.into()), Ok(()));
|
||||||
|
assert_eq!(socket.send_slice(b"123456", REMOTE_IPV6.into()), Err(Error::Exhausted));
|
||||||
|
assert!(!socket.can_send());
|
||||||
|
|
||||||
|
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
||||||
|
assert_eq!(ip_repr, LOCAL_IPV6_REPR);
|
||||||
|
assert_eq!(icmp_repr, ECHOV6_REPR.into());
|
||||||
|
Err(Error::Unaddressable)
|
||||||
|
}), Err(Error::Unaddressable));
|
||||||
|
// buffer is not taken off of the tx queue due to the error
|
||||||
|
assert!(!socket.can_send());
|
||||||
|
|
||||||
|
assert_eq!(socket.dispatch(&caps, |(ip_repr, icmp_repr)| {
|
||||||
|
assert_eq!(ip_repr, LOCAL_IPV6_REPR);
|
||||||
|
assert_eq!(icmp_repr, ECHOV6_REPR.into());
|
||||||
|
Ok(())
|
||||||
|
}), Ok(()));
|
||||||
|
// buffer is taken off of the queue this time
|
||||||
|
assert!(socket.can_send());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_hop_limit() {
|
||||||
|
let mut s = socket(buffer(0), buffer(1));
|
||||||
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
|
let mut bytes = vec![0xff; 24];
|
||||||
|
let mut packet = Icmpv6Packet::new(&mut bytes);
|
||||||
|
ECHOV6_REPR.emit(&LOCAL_IPV6.into(), &REMOTE_IPV6.into(), &mut packet, &caps.checksum);
|
||||||
|
|
||||||
|
s.set_hop_limit(Some(0x2a));
|
||||||
|
|
||||||
|
assert_eq!(s.send_slice(&packet.into_inner()[..], REMOTE_IPV6.into()), Ok(()));
|
||||||
|
assert_eq!(s.dispatch(&caps, |(ip_repr, _)| {
|
||||||
|
assert_eq!(ip_repr, IpRepr::Ipv6(Ipv6Repr {
|
||||||
|
src_addr: Ipv6Address::UNSPECIFIED,
|
||||||
|
dst_addr: REMOTE_IPV6,
|
||||||
|
next_header: IpProtocol::Icmp,
|
||||||
|
payload_len: ECHOV6_REPR.buffer_len(),
|
||||||
|
hop_limit: 0x2a,
|
||||||
|
}));
|
||||||
|
Ok(())
|
||||||
|
}), Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_recv_process() {
|
||||||
|
let mut socket = socket(buffer(1), buffer(1));
|
||||||
|
assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
|
||||||
|
|
||||||
|
assert!(!socket.can_recv());
|
||||||
|
assert_eq!(socket.recv(), Err(Error::Exhausted));
|
||||||
|
|
||||||
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
|
let mut bytes = [0xff; 24];
|
||||||
|
let mut packet = Icmpv6Packet::new(&mut bytes);
|
||||||
|
ECHOV6_REPR.emit(&LOCAL_IPV6.into(), &REMOTE_IPV6.into(), &mut packet, &caps.checksum);
|
||||||
|
let data = &packet.into_inner()[..];
|
||||||
|
|
||||||
|
assert!(socket.accepts(&REMOTE_IPV6_REPR, &ECHOV6_REPR.into(), &caps.checksum));
|
||||||
|
assert_eq!(socket.process(&REMOTE_IPV6_REPR, &ECHOV6_REPR.into(), &caps.checksum),
|
||||||
|
Ok(()));
|
||||||
|
assert!(socket.can_recv());
|
||||||
|
|
||||||
|
assert!(socket.accepts(&REMOTE_IPV6_REPR, &ECHOV6_REPR.into(), &caps.checksum));
|
||||||
|
assert_eq!(socket.process(&REMOTE_IPV6_REPR, &ECHOV6_REPR.into(), &caps.checksum),
|
||||||
|
Err(Error::Exhausted));
|
||||||
|
|
||||||
|
assert_eq!(socket.recv(), Ok((&data[..], REMOTE_IPV6.into())));
|
||||||
|
assert!(!socket.can_recv());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_accept_bad_id() {
|
||||||
|
let mut socket = socket(buffer(1), buffer(1));
|
||||||
|
assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
|
||||||
|
|
||||||
|
let caps = DeviceCapabilities::default();
|
||||||
|
let mut bytes = [0xff; 20];
|
||||||
|
let mut packet = Icmpv6Packet::new(&mut bytes);
|
||||||
|
let icmp_repr = Icmpv6Repr::EchoRequest {
|
||||||
|
ident: 0x4321,
|
||||||
|
seq_no: 0x5678,
|
||||||
|
data: &[0xff; 16]
|
||||||
|
};
|
||||||
|
icmp_repr.emit(&LOCAL_IPV6.into(), &REMOTE_IPV6.into(), &mut packet, &caps.checksum);
|
||||||
|
|
||||||
|
// Ensure that a packet with an identifier that isn't the bound
|
||||||
|
// ID is not accepted
|
||||||
|
assert!(!socket.accepts(&REMOTE_IPV6_REPR, &icmp_repr.into(), &caps.checksum));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_accepts_udp() {
|
||||||
|
let mut socket = socket(buffer(1), buffer(1));
|
||||||
|
assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V6)), Ok(()));
|
||||||
|
|
||||||
|
let caps = DeviceCapabilities::default();
|
||||||
|
|
||||||
|
let mut bytes = [0xff; 18];
|
||||||
|
let mut packet = UdpPacket::new(&mut bytes);
|
||||||
|
UDP_REPR.emit(&mut packet, &REMOTE_IPV6.into(), &LOCAL_IPV6.into(), &caps.checksum);
|
||||||
|
|
||||||
|
let data = &packet.into_inner()[..];
|
||||||
|
|
||||||
|
let icmp_repr = Icmpv6Repr::DstUnreachable {
|
||||||
|
reason: Icmpv6DstUnreachable::PortUnreachable,
|
||||||
|
header: Ipv6Repr {
|
||||||
|
src_addr: LOCAL_IPV6,
|
||||||
|
dst_addr: REMOTE_IPV6,
|
||||||
|
next_header: IpProtocol::Icmp,
|
||||||
|
payload_len: 12,
|
||||||
|
hop_limit: 0x40
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
let ip_repr = IpRepr::Unspecified {
|
||||||
|
src_addr: REMOTE_IPV6.into(),
|
||||||
|
dst_addr: LOCAL_IPV6.into(),
|
||||||
|
protocol: IpProtocol::Icmp,
|
||||||
|
payload_len: icmp_repr.buffer_len(),
|
||||||
|
hop_limit: 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!socket.can_recv());
|
||||||
|
|
||||||
|
// Ensure we can accept ICMP error response to the bound
|
||||||
|
// UDP port
|
||||||
|
assert!(socket.accepts(&ip_repr, &icmp_repr.into(), &caps.checksum));
|
||||||
|
assert_eq!(socket.process(&ip_repr, &icmp_repr.into(), &caps.checksum),
|
||||||
|
Ok(()));
|
||||||
|
assert!(socket.can_recv());
|
||||||
|
|
||||||
|
let mut bytes = [0x00; 66];
|
||||||
|
let mut packet = Icmpv6Packet::new(&mut bytes[..]);
|
||||||
|
icmp_repr.emit(&LOCAL_IPV6.into(), &REMOTE_IPV6.into(), &mut packet, &caps.checksum);
|
||||||
|
assert_eq!(socket.recv(), Ok((&packet.into_inner()[..], REMOTE_IPV6.into())));
|
||||||
assert!(!socket.can_recv());
|
assert!(!socket.can_recv());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use time::Instant;
|
||||||
mod meta;
|
mod meta;
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
mod raw;
|
mod raw;
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
mod icmp;
|
mod icmp;
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
mod udp;
|
mod udp;
|
||||||
|
@ -33,7 +33,7 @@ pub use self::raw::{RawPacketMetadata,
|
||||||
RawSocketBuffer,
|
RawSocketBuffer,
|
||||||
RawSocket};
|
RawSocket};
|
||||||
|
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
pub use self::icmp::{IcmpPacketMetadata,
|
pub use self::icmp::{IcmpPacketMetadata,
|
||||||
IcmpSocketBuffer,
|
IcmpSocketBuffer,
|
||||||
Endpoint as IcmpEndpoint,
|
Endpoint as IcmpEndpoint,
|
||||||
|
@ -69,7 +69,7 @@ pub(crate) use self::ref_::Session as SocketSession;
|
||||||
pub enum Socket<'a, 'b: 'a> {
|
pub enum Socket<'a, 'b: 'a> {
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
Raw(RawSocket<'a, 'b>),
|
Raw(RawSocket<'a, 'b>),
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
Icmp(IcmpSocket<'a, 'b>),
|
Icmp(IcmpSocket<'a, 'b>),
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
Udp(UdpSocket<'a, 'b>),
|
Udp(UdpSocket<'a, 'b>),
|
||||||
|
@ -90,7 +90,7 @@ macro_rules! dispatch_socket {
|
||||||
match $self_ {
|
match $self_ {
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
&$( $mut_ )* Socket::Raw(ref $( $mut_ )* $socket) => $code,
|
&$( $mut_ )* Socket::Raw(ref $( $mut_ )* $socket) => $code,
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
&$( $mut_ )* Socket::Icmp(ref $( $mut_ )* $socket) => $code,
|
&$( $mut_ )* Socket::Icmp(ref $( $mut_ )* $socket) => $code,
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
&$( $mut_ )* Socket::Udp(ref $( $mut_ )* $socket) => $code,
|
&$( $mut_ )* Socket::Udp(ref $( $mut_ )* $socket) => $code,
|
||||||
|
@ -149,7 +149,7 @@ macro_rules! from_socket {
|
||||||
|
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
from_socket!(RawSocket<'a, 'b>, Raw);
|
from_socket!(RawSocket<'a, 'b>, Raw);
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
from_socket!(IcmpSocket<'a, 'b>, Icmp);
|
from_socket!(IcmpSocket<'a, 'b>, Icmp);
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
from_socket!(UdpSocket<'a, 'b>, Udp);
|
from_socket!(UdpSocket<'a, 'b>, Udp);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
use socket::RawSocket;
|
use socket::RawSocket;
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
use socket::IcmpSocket;
|
use socket::IcmpSocket;
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
use socket::UdpSocket;
|
use socket::UdpSocket;
|
||||||
|
@ -21,7 +21,7 @@ pub trait Session {
|
||||||
|
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
impl<'a, 'b> Session for RawSocket<'a, 'b> {}
|
impl<'a, 'b> Session for RawSocket<'a, 'b> {}
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
impl<'a, 'b> Session for IcmpSocket<'a, 'b> {}
|
impl<'a, 'b> Session for IcmpSocket<'a, 'b> {}
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
impl<'a, 'b> Session for UdpSocket<'a, 'b> {}
|
impl<'a, 'b> Session for UdpSocket<'a, 'b> {}
|
||||||
|
|
|
@ -144,7 +144,7 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> {
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
&mut Socket::Raw(_) =>
|
&mut Socket::Raw(_) =>
|
||||||
may_remove = true,
|
may_remove = true,
|
||||||
#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
|
#[cfg(all(feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6")))]
|
||||||
&mut Socket::Icmp(_) =>
|
&mut Socket::Icmp(_) =>
|
||||||
may_remove = true,
|
may_remove = true,
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
use super::icmpv4;
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
use super::icmpv6;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Repr<'a> {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
Ipv4(icmpv4::Repr<'a>),
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
Ipv6(icmpv6::Repr<'a>),
|
||||||
|
}
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
impl<'a> From<icmpv4::Repr<'a>> for Repr<'a> {
|
||||||
|
fn from(s: icmpv4::Repr<'a>) -> Self {
|
||||||
|
Repr::Ipv4(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
impl<'a> From<icmpv6::Repr<'a>> for Repr<'a> {
|
||||||
|
fn from(s: icmpv6::Repr<'a>) -> Self {
|
||||||
|
Repr::Ipv6(s)
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,6 +95,8 @@ mod ipv6fragment;
|
||||||
mod icmpv4;
|
mod icmpv4;
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
mod icmpv6;
|
mod icmpv6;
|
||||||
|
#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
|
||||||
|
mod icmp;
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
mod igmp;
|
mod igmp;
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
@ -174,6 +176,8 @@ pub use self::icmpv6::{Message as Icmpv6Message,
|
||||||
ParamProblem as Icmpv6ParamProblem,
|
ParamProblem as Icmpv6ParamProblem,
|
||||||
Packet as Icmpv6Packet,
|
Packet as Icmpv6Packet,
|
||||||
Repr as Icmpv6Repr};
|
Repr as Icmpv6Repr};
|
||||||
|
#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
|
||||||
|
pub use self::icmp::Repr as IcmpRepr;
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
pub use self::icmpv6::{RouterFlags as NdiscRouterFlags,
|
pub use self::icmpv6::{RouterFlags as NdiscRouterFlags,
|
||||||
|
|
Loading…
Reference in New Issue