mirror of
https://github.com/n0-computer/noq.git
synced 2026-09-21 02:33:23 +00:00
Allow to use the incoming IP address for sending outgoing packets
This is a follow-up for #943. When a socket is bound to a wildcard IP address, sending the outgoing IP might use a different source IP address than the one the packet was received on, since the OS might not be able to identify the necessary route. This would lead packets not allowing to reach the client. This change adds a setting which will set an explicit source address in all outgoing packets. The source address which will be used is the local IP address which was used to receive the initial incoming packet.
This commit is contained in:
committed by
Dirkjan Ochtman
parent
42fd00c20d
commit
1ca7149de1
@@ -365,6 +365,7 @@ where
|
||||
contents: buf,
|
||||
ecn: None,
|
||||
segment_size: None,
|
||||
src_ip: self.local_ip,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -554,6 +555,7 @@ where
|
||||
None
|
||||
},
|
||||
segment_size: None,
|
||||
src_ip: self.local_ip,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ where
|
||||
ecn: None,
|
||||
contents: buf,
|
||||
segment_size: None,
|
||||
src_ip: local_ip,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
@@ -253,7 +254,7 @@ where
|
||||
|
||||
if !self.is_server() {
|
||||
debug!("packet for unrecognized connection {}", dst_cid);
|
||||
self.stateless_reset(datagram_len, remote, &dst_cid);
|
||||
self.stateless_reset(datagram_len, remote, local_ip, &dst_cid);
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -288,7 +289,7 @@ where
|
||||
//
|
||||
|
||||
if !dst_cid.is_empty() {
|
||||
self.stateless_reset(datagram_len, remote, &dst_cid);
|
||||
self.stateless_reset(datagram_len, remote, local_ip, &dst_cid);
|
||||
} else {
|
||||
trace!("dropping unrecognized short packet without ID");
|
||||
}
|
||||
@@ -299,6 +300,7 @@ where
|
||||
&mut self,
|
||||
inciting_dgram_len: usize,
|
||||
remote: SocketAddr,
|
||||
local_ip: Option<IpAddr>,
|
||||
dst_cid: &ConnectionId,
|
||||
) {
|
||||
/// Minimum amount of padding for the stateless reset to look like a short-header packet
|
||||
@@ -336,6 +338,7 @@ where
|
||||
ecn: None,
|
||||
contents: buf,
|
||||
segment_size: None,
|
||||
src_ip: local_ip,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -535,6 +538,7 @@ where
|
||||
debug!("refusing connection");
|
||||
self.initial_close(
|
||||
remote,
|
||||
local_ip,
|
||||
crypto,
|
||||
&src_cid,
|
||||
&temp_loc_cid,
|
||||
@@ -553,6 +557,7 @@ where
|
||||
);
|
||||
self.initial_close(
|
||||
remote,
|
||||
local_ip,
|
||||
crypto,
|
||||
&src_cid,
|
||||
&temp_loc_cid,
|
||||
@@ -590,6 +595,7 @@ where
|
||||
ecn: None,
|
||||
contents: buf,
|
||||
segment_size: None,
|
||||
src_ip: local_ip,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
@@ -608,6 +614,7 @@ where
|
||||
debug!("rejecting invalid stateless retry token");
|
||||
self.initial_close(
|
||||
remote,
|
||||
local_ip,
|
||||
crypto,
|
||||
&src_cid,
|
||||
&temp_loc_cid,
|
||||
@@ -645,7 +652,7 @@ where
|
||||
debug!("handshake failed: {}", e);
|
||||
self.handle_event(ch, EndpointEvent(EndpointEventInner::Drained));
|
||||
if let ConnectionError::TransportError(e) = e {
|
||||
self.initial_close(remote, crypto, &src_cid, &temp_loc_cid, e);
|
||||
self.initial_close(remote, local_ip, crypto, &src_cid, &temp_loc_cid, e);
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -655,6 +662,7 @@ where
|
||||
fn initial_close(
|
||||
&mut self,
|
||||
destination: SocketAddr,
|
||||
local_ip: Option<IpAddr>,
|
||||
crypto: &Keys<S>,
|
||||
remote_id: &ConnectionId,
|
||||
local_id: &ConnectionId,
|
||||
@@ -683,6 +691,7 @@ where
|
||||
ecn: None,
|
||||
contents: buf,
|
||||
segment_size: None,
|
||||
src_ip: local_ip,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
#![allow(clippy::cognitive_complexity)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use std::{convert::TryInto, fmt, net::SocketAddr, ops, time::Duration};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
fmt,
|
||||
net::{IpAddr, SocketAddr},
|
||||
ops,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
mod cid_queue;
|
||||
#[doc(hidden)]
|
||||
@@ -277,6 +283,8 @@ pub struct Transmit {
|
||||
/// The segment size if this transmission contains multiple datagrams.
|
||||
/// This is `None` if the transmit only contains a single datagram
|
||||
pub segment_size: Option<usize>,
|
||||
/// Optional source IP address for the datagram
|
||||
pub src_ip: Option<IpAddr>,
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{
|
||||
io,
|
||||
io::IoSliceMut,
|
||||
mem::{self, MaybeUninit},
|
||||
net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
||||
os::unix::io::AsRawFd,
|
||||
ptr,
|
||||
};
|
||||
@@ -273,7 +273,7 @@ pub fn caps() -> UdpCapabilities {
|
||||
*CAPABILITIES
|
||||
}
|
||||
|
||||
const CMSG_LEN: usize = 64;
|
||||
const CMSG_LEN: usize = 80;
|
||||
|
||||
fn prepare_msg(
|
||||
transmit: &Transmit,
|
||||
@@ -312,6 +312,32 @@ fn prepare_msg(
|
||||
gso::set_segment_size(&mut encoder, segment_size as u16);
|
||||
}
|
||||
|
||||
if let Some(ip) = &transmit.src_ip {
|
||||
if cfg!(target_os = "linux") {
|
||||
match ip {
|
||||
IpAddr::V4(v4) => {
|
||||
let pktinfo = libc::in_pktinfo {
|
||||
ipi_ifindex: 0,
|
||||
ipi_spec_dst: unsafe {
|
||||
*(v4 as *const Ipv4Addr as *const () as *const libc::in_addr)
|
||||
},
|
||||
ipi_addr: libc::in_addr { s_addr: 0 },
|
||||
};
|
||||
encoder.push(libc::IPPROTO_IP, libc::IP_PKTINFO, pktinfo);
|
||||
}
|
||||
IpAddr::V6(v6) => {
|
||||
let pktinfo = libc::in6_pktinfo {
|
||||
ipi6_ifindex: 0,
|
||||
ipi6_addr: unsafe {
|
||||
*(v6 as *const Ipv6Addr as *const () as *const libc::in6_addr)
|
||||
},
|
||||
};
|
||||
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encoder.finish();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user