nex_socket/icmp/
sync_impl.rs1use crate::SocketFamily;
2use crate::icmp::{IcmpConfig, IcmpKind, IcmpSocketType};
3use socket2::{Domain, Protocol, Socket, Type as SockType};
4use std::io;
5use std::net::{SocketAddr, UdpSocket};
6
7#[derive(Debug)]
9pub struct IcmpSocket {
10 inner: UdpSocket,
11 socket_type: IcmpSocketType,
12 socket_family: SocketFamily,
13}
14
15impl IcmpSocket {
16 pub fn new(config: &IcmpConfig) -> io::Result<Self> {
18 let (domain, proto) = match config.socket_family {
19 SocketFamily::IPV4 => (Domain::IPV4, Some(Protocol::ICMPV4)),
20 SocketFamily::IPV6 => (Domain::IPV6, Some(Protocol::ICMPV6)),
21 };
22
23 let socket = match Socket::new(domain, config.sock_type_hint.to_sock_type(), proto) {
24 Ok(s) => s,
25 Err(_) => {
26 let alt_type = if config.sock_type_hint.is_dgram() {
27 SockType::RAW
28 } else {
29 SockType::DGRAM
30 };
31 Socket::new(domain, alt_type, proto)?
32 }
33 };
34
35 socket.set_nonblocking(false)?;
36
37 if let Some(ttl) = config.ttl {
39 socket.set_ttl(ttl)?;
40 }
41 if let Some(hoplimit) = config.hoplimit {
42 socket.set_unicast_hops_v6(hoplimit)?;
43 }
44 if let Some(timeout) = config.read_timeout {
45 socket.set_read_timeout(Some(timeout))?;
46 }
47 if let Some(timeout) = config.write_timeout {
48 socket.set_write_timeout(Some(timeout))?;
49 }
50 #[cfg(target_os = "freebsd")]
52 if let Some(fib) = config.fib {
53 socket.set_fib(fib)?;
54 }
55 #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
57 if let Some(interface) = &config.interface {
58 socket.bind_device(Some(interface.as_bytes()))?;
59 }
60
61 if let Some(addr) = &config.bind {
63 socket.bind(&(*addr).into())?;
64 }
65
66 let sock_type = socket.r#type()?;
67
68 let std_socket: UdpSocket = socket.into();
70
71 Ok(Self {
72 inner: std_socket,
73 socket_type: IcmpSocketType::from_sock_type(sock_type),
74 socket_family: config.socket_family,
75 })
76 }
77
78 pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
80 self.inner.send_to(buf, target)
81 }
82
83 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
85 self.inner.recv_from(buf)
86 }
87
88 pub fn local_addr(&self) -> io::Result<SocketAddr> {
90 self.inner.local_addr()
91 }
92
93 pub fn socket_type(&self) -> IcmpSocketType {
95 self.socket_type
96 }
97
98 pub fn socket_family(&self) -> SocketFamily {
100 self.socket_family
101 }
102
103 pub fn icmp_kind(&self) -> IcmpKind {
105 match self.socket_family {
106 SocketFamily::IPV4 => IcmpKind::V4,
107 SocketFamily::IPV6 => IcmpKind::V6,
108 }
109 }
110
111 #[cfg(unix)]
113 pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
114 use std::os::fd::AsRawFd;
115 self.inner.as_raw_fd()
116 }
117
118 #[cfg(windows)]
120 pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
121 use std::os::windows::io::AsRawSocket;
122 self.inner.as_raw_socket()
123 }
124}