harden network errors

This commit is contained in:
John Smith 2022-08-04 12:48:19 -04:00
parent 44cde7a939
commit 0106f682f7
3 changed files with 68 additions and 47 deletions

View File

@ -316,7 +316,7 @@ impl Network {
let h = RawUdpProtocolHandler::new_unspecified_bound_handler(&peer_socket_addr) let h = RawUdpProtocolHandler::new_unspecified_bound_handler(&peer_socket_addr)
.await .await
.wrap_err("create socket failure")?; .wrap_err("create socket failure")?;
network_result_try!(h let _ = network_result_try!(h
.send_message(data, peer_socket_addr) .send_message(data, peer_socket_addr)
.await .await
.map(NetworkResult::Value) .map(NetworkResult::Value)
@ -375,9 +375,10 @@ impl Network {
let h = RawUdpProtocolHandler::new_unspecified_bound_handler(&peer_socket_addr) let h = RawUdpProtocolHandler::new_unspecified_bound_handler(&peer_socket_addr)
.await .await
.wrap_err("create socket failure")?; .wrap_err("create socket failure")?;
h.send_message(data, peer_socket_addr) network_result_try!(h
.send_message(data, peer_socket_addr)
.await .await
.wrap_err("send message failure")?; .wrap_err("send message failure")?);
self.network_manager() self.network_manager()
.stats_packet_sent(dial_info.to_ip_addr(), data_len as u64); .stats_packet_sent(dial_info.to_ip_addr(), data_len as u64);
@ -449,10 +450,10 @@ impl Network {
&peer_socket_addr, &peer_socket_addr,
&descriptor.local().map(|sa| sa.to_socket_addr()), &descriptor.local().map(|sa| sa.to_socket_addr()),
) { ) {
ph.clone() network_result_value_or_log!(debug ph.clone()
.send_message(data, peer_socket_addr) .send_message(data.clone(), peer_socket_addr)
.await .await
.wrap_err("sending data to existing conection")?; .wrap_err("sending data to existing conection")? => { return Ok(Some(data)); } );
// Network accounting // Network accounting
self.network_manager() self.network_manager()
@ -506,7 +507,7 @@ impl Network {
Some(ph) => ph, Some(ph) => ph,
None => bail!("no appropriate UDP protocol handler for dial_info"), None => bail!("no appropriate UDP protocol handler for dial_info"),
}; };
network_result_try!(ph let _ = network_result_try!(ph
.send_message(data, peer_socket_addr) .send_message(data, peer_socket_addr)
.await .await
.into_network_result() .into_network_result()
@ -532,7 +533,7 @@ impl Network {
self.network_manager() self.network_manager()
.stats_packet_sent(dial_info.to_ip_addr(), data_len as u64); .stats_packet_sent(dial_info.to_ip_addr(), data_len as u64);
Ok(NetworkResult::Value(())) Ok(NetworkResult::value(()))
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////

View File

@ -14,21 +14,12 @@ impl RawUdpProtocolHandler {
#[instrument(level = "trace", err, skip(self, data), fields(data.len = data.len(), ret.len, ret.from))] #[instrument(level = "trace", err, skip(self, data), fields(data.len = data.len(), ret.len, ret.from))]
pub async fn recv_message(&self, data: &mut [u8]) -> io::Result<(usize, ConnectionDescriptor)> { pub async fn recv_message(&self, data: &mut [u8]) -> io::Result<(usize, ConnectionDescriptor)> {
let (size, remote_addr) = loop { let (size, remote_addr) = loop {
match self.socket.recv_from(data).await { let (size, remote_addr) = network_result_value_or_log!(debug self.socket.recv_from(data).await.into_network_result()? => continue);
Ok((size, remote_addr)) => { if size > MAX_MESSAGE_SIZE {
if size > MAX_MESSAGE_SIZE { log_net!(debug "{}({}) at {}@{}:{}", "Invalid message".green(), "received too large UDP message", file!(), line!(), column!());
bail_io_error_other!("received too large UDP message"); continue;
}
break (size, remote_addr);
}
Err(e) => {
if e.kind() == io::ErrorKind::ConnectionReset {
// Ignore icmp
} else {
return Err(e);
}
}
} }
break (size, remote_addr);
}; };
let peer_addr = PeerAddress::new( let peer_addr = PeerAddress::new(
@ -47,17 +38,25 @@ impl RawUdpProtocolHandler {
} }
#[instrument(level = "trace", err, skip(self, data), fields(data.len = data.len(), ret.len, ret.from))] #[instrument(level = "trace", err, skip(self, data), fields(data.len = data.len(), ret.len, ret.from))]
pub async fn send_message(&self, data: Vec<u8>, socket_addr: SocketAddr) -> io::Result<()> { pub async fn send_message(
&self,
data: Vec<u8>,
socket_addr: SocketAddr,
) -> io::Result<NetworkResult<()>> {
if data.len() > MAX_MESSAGE_SIZE { if data.len() > MAX_MESSAGE_SIZE {
bail_io_error_other!("sending too large UDP message"); bail_io_error_other!("sending too large UDP message");
} }
let len = self.socket.send_to(&data, socket_addr).await?; let len = network_result_try!(self
.socket
.send_to(&data, socket_addr)
.await
.into_network_result()?);
if len != data.len() { if len != data.len() {
bail_io_error_other!("UDP partial send") bail_io_error_other!("UDP partial send")
} }
Ok(()) Ok(NetworkResult::value(()))
} }
#[instrument(level = "trace", err)] #[instrument(level = "trace", err)]

View File

@ -38,13 +38,20 @@ impl<T> IoNetworkResultExt<T> for io::Result<T> {
_ => Err(e), _ => Err(e),
}, },
#[cfg(not(feature = "io_error_more"))] #[cfg(not(feature = "io_error_more"))]
Err(e) => match e.kind() { Err(e) => {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), if let Some(os_err) = e.raw_os_error() {
io::ErrorKind::ConnectionAborted if os_err == libc::EHOSTUNREACH || os_err == libc::ENETUNREACH {
| io::ErrorKind::ConnectionRefused return Ok(NetworkResult::NoConnection(e));
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), }
_ => Err(e), }
}, match e.kind() {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout),
io::ErrorKind::ConnectionAborted
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)),
_ => Err(e),
}
}
} }
} }
} }
@ -85,13 +92,20 @@ impl<T> FoldedNetworkResultExt<T> for io::Result<TimeoutOr<T>> {
_ => Err(e), _ => Err(e),
}, },
#[cfg(not(feature = "io_error_more"))] #[cfg(not(feature = "io_error_more"))]
Err(e) => match e.kind() { Err(e) => {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), if let Some(os_err) = e.raw_os_error() {
io::ErrorKind::ConnectionAborted if os_err == libc::EHOSTUNREACH || os_err == libc::ENETUNREACH {
| io::ErrorKind::ConnectionRefused return Ok(NetworkResult::NoConnection(e));
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), }
_ => Err(e), }
}, match e.kind() {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout),
io::ErrorKind::ConnectionAborted
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)),
_ => Err(e),
}
}
} }
} }
} }
@ -111,13 +125,20 @@ impl<T> FoldedNetworkResultExt<T> for io::Result<NetworkResult<T>> {
_ => Err(e), _ => Err(e),
}, },
#[cfg(not(feature = "io_error_more"))] #[cfg(not(feature = "io_error_more"))]
Err(e) => match e.kind() { Err(e) => {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout), if let Some(os_err) = e.raw_os_error() {
io::ErrorKind::ConnectionAborted if os_err == libc::EHOSTUNREACH || os_err == libc::ENETUNREACH {
| io::ErrorKind::ConnectionRefused return Ok(NetworkResult::NoConnection(e));
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)), }
_ => Err(e), }
}, match e.kind() {
io::ErrorKind::TimedOut => Ok(NetworkResult::Timeout),
io::ErrorKind::ConnectionAborted
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionReset => Ok(NetworkResult::NoConnection(e)),
_ => Err(e),
}
}
} }
} }
} }
@ -270,7 +291,7 @@ macro_rules! network_result_value_or_log {
$f $f
} }
NetworkResult::InvalidMessage(s) => { NetworkResult::InvalidMessage(s) => {
log_net!($level "{}({}) at {}@{}:{}", "No connection".green(), s, file!(), line!(), column!()); log_net!($level "{}({}) at {}@{}:{}", "Invalid message".green(), s, file!(), line!(), column!());
$f $f
} }
NetworkResult::Value(v) => v, NetworkResult::Value(v) => v,