Skip to content

Commit

Permalink
feat(shadowsocks): macOS if_nametoindex cache result
Browse files Browse the repository at this point in the history
  • Loading branch information
zonyitoo committed Aug 12, 2023
1 parent be18b4e commit 169d880
Showing 1 changed file with 43 additions and 10 deletions.
53 changes: 43 additions & 10 deletions crates/shadowsocks/src/net/sys/unix/bsd/macos.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{
cell::RefCell,
collections::HashMap,
io::{self, ErrorKind},
mem,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpStream as StdTcpStream},
Expand All @@ -7,6 +9,7 @@ use std::{
ptr,
sync::atomic::{AtomicBool, Ordering},
task::{self, Poll},
time::{Duration, Instant},
};

use log::{debug, error, warn};
Expand Down Expand Up @@ -228,11 +231,24 @@ pub async fn create_inbound_tcp_socket(bind_addr: &SocketAddr, _accept_opts: &Ac
}
}

fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> {
const IP_BOUND_IF: libc::c_int = 25; // bsd/netinet/in.h
const IPV6_BOUND_IF: libc::c_int = 125; // bsd/netinet6/in6.h
fn find_interface_index_cached(iface: &str) -> io::Result<u32> {
const INDEX_EXPIRE_DURATION: Duration = Duration::from_secs(5);

unsafe {
thread_local! {
static INTERFACE_INDEX_CACHE: RefCell<HashMap<String, (u32, Instant)>> =
RefCell::new(HashMap::new());
}

let cache_index = INTERFACE_INDEX_CACHE.with(|cache| cache.borrow().get(iface).cloned());
if let Some((idx, insert_time)) = cache_index {
// short-path, cache hit for most cases
let now = Instant::now();
if now - insert_time < INDEX_EXPIRE_DURATION {
return Ok(idx);
}
}

let index = unsafe {
let mut ciface = [0u8; libc::IFNAMSIZ];
if iface.len() >= ciface.len() {
return Err(ErrorKind::InvalidInput.into());
Expand All @@ -241,12 +257,28 @@ fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io
let iface_bytes = iface.as_bytes();
ptr::copy_nonoverlapping(iface_bytes.as_ptr(), ciface.as_mut_ptr(), iface_bytes.len());

let index = libc::if_nametoindex(ciface.as_ptr() as *const libc::c_char);
if index == 0 {
let err = io::Error::last_os_error();
error!("if_nametoindex ifname: {} error: {}", iface, err);
return Err(err);
}
libc::if_nametoindex(ciface.as_ptr() as *const libc::c_char)
};

if index == 0 {
let err = io::Error::last_os_error();
error!("if_nametoindex ifname: {} error: {}", iface, err);
return Err(err);
}

INTERFACE_INDEX_CACHE.with(|cache| {
cache.borrow_mut().insert(iface.to_owned(), (index, Instant::now()));
});

Ok(index)
}

fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> {
const IP_BOUND_IF: libc::c_int = 25; // bsd/netinet/in.h
const IPV6_BOUND_IF: libc::c_int = 125; // bsd/netinet6/in6.h

unsafe {
let index = find_interface_index_cached(iface)?;

let ret = match addr {
SocketAddr::V4(..) => libc::setsockopt(
Expand Down Expand Up @@ -359,6 +391,7 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp

/// https://github.com/apple/darwin-xnu/blob/main/bsd/sys/socket.h
#[repr(C)]
#[allow(non_camel_case_types)]
struct msghdr_x {
msg_name: *mut libc::c_void, //< optional address
msg_namelen: libc::socklen_t, //< size of address
Expand Down

0 comments on commit 169d880

Please sign in to comment.