Skip to content

Commit

Permalink
Add binding to the interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sashacmc committed Feb 23, 2024
1 parent 5c6398b commit 6400201
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 26 deletions.
25 changes: 17 additions & 8 deletions commons/zenoh-util/src/std_only/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,19 @@ pub fn get_multicast_interfaces() -> Vec<IpAddr> {
}
}

pub fn get_local_addresses() -> ZResult<Vec<IpAddr>> {
pub fn get_local_addresses(interface: Option<String>) -> ZResult<Vec<IpAddr>> {
#[cfg(unix)]
{
Ok(pnet_datalink::interfaces()
.into_iter()
.filter(|iface| iface.is_up() && iface.is_running())
.filter(|iface| {
if let Some(interface) = interface.clone() {
if iface.name != interface {
return false;
}
}
iface.is_up() && iface.is_running()
})
.flat_map(|iface| iface.ips)
.map(|ipnet| ipnet.ip())
.collect())
Expand Down Expand Up @@ -412,25 +419,26 @@ pub fn get_interface_names_by_addr(addr: IpAddr) -> ZResult<Vec<String>> {
}
}

pub fn get_ipv4_ipaddrs() -> Vec<IpAddr> {
get_local_addresses()
pub fn get_ipv4_ipaddrs(interface: Option<String>) -> Vec<IpAddr> {
get_local_addresses(interface)
.unwrap_or_else(|_| vec![])
.drain(..)
.filter_map(|x| match x {
IpAddr::V4(a) => Some(a),
IpAddr::V6(_) => None,
})
.filter(|x| !x.is_loopback() && !x.is_multicast())
.filter(|x| !x.is_multicast())
// .filter(|x| !x.is_loopback() && !x.is_multicast()) // TODO(sashacmc): Why we exclude loopback?
.map(IpAddr::V4)
.collect()
}

pub fn get_ipv6_ipaddrs() -> Vec<IpAddr> {
pub fn get_ipv6_ipaddrs(interface: Option<String>) -> Vec<IpAddr> {
const fn is_unicast_link_local(addr: &Ipv6Addr) -> bool {
(addr.segments()[0] & 0xffc0) == 0xfe80
}

let ipaddrs = get_local_addresses().unwrap_or_else(|_| vec![]);
let ipaddrs = get_local_addresses(interface).unwrap_or_else(|_| vec![]);

// Get first all IPv4 addresses
let ipv4_iter = ipaddrs
Expand All @@ -440,7 +448,8 @@ pub fn get_ipv6_ipaddrs() -> Vec<IpAddr> {
IpAddr::V6(_) => None,
})
.filter(|x| {
!x.is_loopback() && !x.is_link_local() && !x.is_multicast() && !x.is_broadcast()
// !x.is_loopback() && !x.is_link_local() && !x.is_multicast() && !x.is_broadcast() // TODO(sashacmc): Why we exclude loopback?
!x.is_multicast() && !x.is_broadcast()
});

// Get next all IPv6 addresses
Expand Down
3 changes: 3 additions & 0 deletions io/zenoh-link-commons/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ use zenoh_result::ZResult;
/*************************************/
/* GENERAL */
/*************************************/

pub const BIND_INTERFACE: &str = "iface";

#[derive(Clone, Debug, Serialize, Hash, PartialEq, Eq)]
pub struct Link {
pub src: Locator,
Expand Down
11 changes: 9 additions & 2 deletions io/zenoh-link-commons/src/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use zenoh_protocol::core::{EndPoint, Locator};
use zenoh_result::{zerror, ZResult};
use zenoh_sync::Signal;

use crate::BIND_INTERFACE;

pub struct ListenerUnicastIP {
endpoint: EndPoint,
active: Arc<AtomicBool>,
Expand Down Expand Up @@ -109,12 +111,17 @@ impl ListenersUnicastIP {
let guard = zread!(self.listeners);
for (key, value) in guard.iter() {
let (kip, kpt) = (key.ip(), key.port());
let iface = value
.endpoint
.config()
.get(BIND_INTERFACE)
.map(|s| s.to_string());

// Either ipv4/0.0.0.0 or ipv6/[::]
if kip.is_unspecified() {
let mut addrs = match kip {
IpAddr::V4(_) => zenoh_util::net::get_ipv4_ipaddrs(),
IpAddr::V6(_) => zenoh_util::net::get_ipv6_ipaddrs(),
IpAddr::V4(_) => zenoh_util::net::get_ipv4_ipaddrs(iface),
IpAddr::V6(_) => zenoh_util::net::get_ipv6_ipaddrs(iface),
};
let iter = addrs.drain(..).map(|x| {
Locator::new(
Expand Down
34 changes: 20 additions & 14 deletions io/zenoh-links/zenoh-link-tcp/src/unicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::sync::Arc;
use std::time::Duration;
use zenoh_link_commons::{
get_ip_interface_names, LinkManagerUnicastTrait, LinkUnicast, LinkUnicastTrait,
ListenersUnicastIP, NewLinkChannelSender,
ListenersUnicastIP, NewLinkChannelSender, BIND_INTERFACE,
};
use zenoh_protocol::core::{EndPoint, Locator};
use zenoh_result::{bail, zerror, Error as ZError, ZResult};
Expand Down Expand Up @@ -216,22 +216,28 @@ impl LinkManagerUnicastTcp {
Ok((stream, src_addr, dst_addr))
}

async fn new_listener_inner(&self, addr: &SocketAddr) -> ZResult<(TcpListener, SocketAddr)> {
async fn new_listener_inner(
&self,
addr: &SocketAddr,
iface: &Option<String>,
) -> ZResult<(TcpListener, SocketAddr)> {
// Bind the TCP socket
let socket = TcpListener::bind(addr)
.await
.map_err(|e| zerror!("{}: {}", addr, e))?;

//let iface = "wg0";
let iface = "lo";
unsafe {
libc::setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
iface.as_ptr() as *const std::os::raw::c_void,
iface.len() as libc::socklen_t,
);
if let Some(iface) = iface {
// @TODO: switch to bind_device after tokio porting
log::debug!("Listen at the interface: {}", iface);
unsafe {
libc::setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
iface.as_ptr() as *const std::os::raw::c_void,
iface.len() as libc::socklen_t,
);
}
}

let local_addr = socket
Expand Down Expand Up @@ -273,10 +279,10 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastTcp {

async fn new_listener(&self, mut endpoint: EndPoint) -> ZResult<Locator> {
let addrs = get_tcp_addrs(endpoint.address()).await?;

let iface = endpoint.config().get(BIND_INTERFACE).map(|s| s.to_string());
let mut errs: Vec<ZError> = vec![];
for da in addrs {
match self.new_listener_inner(&da).await {
match self.new_listener_inner(&da, &iface).await {
Ok((socket, local_addr)) => {
// Update the endpoint locator address
endpoint = EndPoint::new(
Expand Down
4 changes: 2 additions & 2 deletions io/zenoh-links/zenoh-link-ws/src/unicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastWs {
for (key, value) in guard.iter() {
let listener_locator = value.endpoint.to_locator();
if key.ip() == default_ipv4 {
match zenoh_util::net::get_local_addresses() {
match zenoh_util::net::get_local_addresses(None) {
Ok(ipaddrs) => {
for ipaddr in ipaddrs {
if !ipaddr.is_loopback() && !ipaddr.is_multicast() && ipaddr.is_ipv4() {
Expand All @@ -433,7 +433,7 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastWs {
Err(err) => log::error!("Unable to get local addresses: {}", err),
}
} else if key.ip() == default_ipv6 {
match zenoh_util::net::get_local_addresses() {
match zenoh_util::net::get_local_addresses(None) {
Ok(ipaddrs) => {
for ipaddr in ipaddrs {
if !ipaddr.is_loopback() && !ipaddr.is_multicast() && ipaddr.is_ipv6() {
Expand Down

0 comments on commit 6400201

Please sign in to comment.