feat(shadowsocks): macOS if_nametoindex cache result

This commit is contained in:
zonyitoo
2023-08-13 07:37:31 +08:00
parent be18b4ee01
commit 169d880340
@@ -1,4 +1,6 @@
use std::{
cell::RefCell,
collections::HashMap,
io::{self, ErrorKind},
mem,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpStream as StdTcpStream},
@@ -7,6 +9,7 @@ use std::{
ptr,
sync::atomic::{AtomicBool, Ordering},
task::{self, Poll},
time::{Duration, Instant},
};
use log::{debug, error, warn};
@@ -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());
@@ -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(
@@ -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