Skip to content

Commit d090d22

Browse files
authored
Flush interface on BSD (#92)
1 parent 37c1ed8 commit d090d22

File tree

7 files changed

+132
-46
lines changed

7 files changed

+132
-46
lines changed

Cargo.lock

Lines changed: 31 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "defguard_wireguard_rs"
3-
version = "0.7.4"
3+
version = "0.7.5"
44
edition = "2021"
55
rust-version = "1.80"
66
description = "A unified multi-platform high-level API for managing WireGuard interfaces"

src/bsd/mod.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ mod timespec;
66
mod wgio;
77

88
use std::{
9-
collections::HashMap, ffi::CString, mem::size_of, net::IpAddr, os::fd::OwnedFd, ptr::from_ref,
9+
collections::HashMap,
10+
ffi::{CStr, CString},
11+
mem::{size_of, MaybeUninit},
12+
net::IpAddr,
13+
os::fd::OwnedFd,
14+
ptr::from_ref,
1015
slice::from_raw_parts,
1116
};
1217

@@ -15,7 +20,7 @@ use nix::{
1520
sys::socket::{socket, AddressFamily, SockFlag, SockType},
1621
};
1722
use route::{DestAddrMask, GatewayLink};
18-
use sockaddr::{SockAddrDl, SockAddrIn, SockAddrIn6};
23+
use sockaddr::{SockAddrDl, SockAddrIn, SockAddrIn6, SocketFromRaw};
1924
use thiserror::Error;
2025

2126
use self::{
@@ -32,6 +37,13 @@ use crate::{
3237
IpVersion, Key, WireguardInterfaceError,
3338
};
3439

40+
// Note: these values differ across different platforms.
41+
const AF_INET: u8 = libc::AF_INET as u8;
42+
const AF_INET6: u8 = libc::AF_INET6 as u8;
43+
const AF_LINK: u8 = libc::AF_LINK as u8;
44+
const SA_IN_SIZE: u8 = size_of::<SockAddrIn>() as u8;
45+
const SA_IN6_SIZE: u8 = size_of::<SockAddrIn6>() as u8;
46+
3547
// nvlist key names
3648
static NV_LISTEN_PORT: &str = "listen-port";
3749
static NV_FWMARK: &str = "user-cookie";
@@ -370,6 +382,62 @@ pub fn remove_address(if_name: &str, address: &IpAddrMask) -> Result<(), IoError
370382
}
371383
}
372384

385+
pub fn flush_interface(if_name: &str) -> Result<(), IoError> {
386+
let ifname_c = CString::new(if_name).unwrap();
387+
let mut addr_to_remove = Vec::new();
388+
389+
let mut addrs = MaybeUninit::<*mut libc::ifaddrs>::uninit();
390+
let errno = unsafe { libc::getifaddrs(addrs.as_mut_ptr()) };
391+
if errno == 0 {
392+
let addrs = unsafe { addrs.assume_init() };
393+
let mut addr = addrs;
394+
while !addr.is_null() {
395+
unsafe {
396+
let name = CStr::from_ptr((*addr).ifa_name);
397+
if name == ifname_c.as_c_str() {
398+
let ifa_addr = (*addr).ifa_addr;
399+
if ifa_addr.is_null() {
400+
continue;
401+
}
402+
// Convert `ifa_addr` to `IpAddr`.
403+
// Note: `ifa_addr` is actually `sockaddr_in` or `sockaddr_in6` depending on
404+
// `sa_len` and `sa_family`.
405+
if (*ifa_addr).sa_len == SA_IN_SIZE && (*ifa_addr).sa_family == AF_INET {
406+
if let Some(sockaddr) = SockAddrIn::from_raw(ifa_addr) {
407+
addr_to_remove.push(sockaddr.ip_addr());
408+
}
409+
} else if (*ifa_addr).sa_len == SA_IN6_SIZE
410+
&& (*ifa_addr).sa_family == libc::AF_INET6 as u8
411+
{
412+
if let Some(sockaddr) = SockAddrIn6::from_raw(ifa_addr) {
413+
addr_to_remove.push(sockaddr.ip_addr());
414+
}
415+
}
416+
}
417+
addr = (*addr).ifa_next;
418+
};
419+
}
420+
unsafe { libc::freeifaddrs(addrs) };
421+
} else {
422+
debug!("getifaddrs returned {errno}");
423+
}
424+
425+
for address in addr_to_remove {
426+
match address {
427+
IpAddr::V4(address) => {
428+
let ifreq = IfReq::new_with_address(if_name, address);
429+
ifreq.delete_address()?;
430+
}
431+
IpAddr::V6(address) => {
432+
let ifreq6 = IfReq6::new_with_address(if_name, address);
433+
ifreq6.delete_address()?;
434+
}
435+
}
436+
}
437+
438+
Ok(())
439+
}
440+
373441
pub fn get_mtu(if_name: &str) -> Result<u32, IoError> {
374442
let mut ifmtu = IfMtu::new(if_name);
375443
ifmtu.get_mtu()

src/bsd/route.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
ffi::{CStr, CString},
23
mem::{size_of, MaybeUninit},
34
net::IpAddr,
45
os::fd::{AsFd, AsRawFd},
@@ -214,14 +215,15 @@ pub(super) struct GatewayLink<S> {
214215

215216
/// Get an address for a given interface. First address is returned.
216217
fn if_addr<S: SocketFromRaw>(if_name: &str) -> Option<S> {
218+
let ifname_c = CString::new(if_name).unwrap();
217219
let mut addrs = MaybeUninit::<*mut libc::ifaddrs>::uninit();
218220
let errno = unsafe { libc::getifaddrs(addrs.as_mut_ptr()) };
219221
if errno == 0 {
220222
let addrs = unsafe { addrs.assume_init() };
221223
let mut addr = addrs;
222224
while !addr.is_null() {
223-
let name = unsafe { std::ffi::CStr::from_ptr((*addr).ifa_name) };
224-
if name.to_str().unwrap() == if_name {
225+
let name = unsafe { CStr::from_ptr((*addr).ifa_name) };
226+
if name == ifname_c.as_c_str() {
225227
if let Some(sockaddr) = unsafe { S::from_raw((*addr).ifa_addr) } {
226228
return Some(sockaddr);
227229
}

src/bsd/sockaddr.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
//! Convert binary `sockaddr_in` or `sockaddr_in6` (see netinet/in.h) to `SocketAddr`.
22
use std::{
33
mem::{size_of, zeroed},
4-
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
4+
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
55
ptr::{copy, from_mut},
66
};
77

8-
use super::{cast_bytes, cast_ref};
9-
10-
// Note: these values differ across different platforms.
11-
const AF_INET: u8 = libc::AF_INET as u8;
12-
const AF_INET6: u8 = libc::AF_INET6 as u8;
13-
const AF_LINK: u8 = libc::AF_LINK as u8;
14-
const SA_IN_SIZE: u8 = size_of::<SockAddrIn>() as u8;
15-
const SA_IN6_SIZE: u8 = size_of::<SockAddrIn6>() as u8;
8+
use super::{cast_bytes, cast_ref, AF_INET, AF_INET6, AF_LINK, SA_IN6_SIZE, SA_IN_SIZE};
169

1710
pub(super) trait SocketFromRaw {
1811
unsafe fn from_raw(addr: *const libc::sockaddr) -> Option<Self>
@@ -30,6 +23,13 @@ pub(super) struct SockAddrIn {
3023
zero: [u8; 8],
3124
}
3225

26+
impl SockAddrIn {
27+
#[must_use]
28+
pub(super) fn ip_addr(&self) -> IpAddr {
29+
IpAddr::from(self.addr)
30+
}
31+
}
32+
3333
impl SocketFromRaw for SockAddrIn {
3434
/// Construct `SockAddrIn` from `libc::sockaddr`.
3535
unsafe fn from_raw(addr: *const libc::sockaddr) -> Option<Self> {
@@ -117,6 +117,11 @@ impl SockAddrIn6 {
117117
scope_id: 0,
118118
}
119119
}
120+
121+
#[must_use]
122+
pub(super) fn ip_addr(&self) -> IpAddr {
123+
IpAddr::from(self.addr)
124+
}
120125
}
121126

122127
impl SocketFromRaw for SockAddrIn6 {

src/wgapi_freebsd.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
6464
self.ifname
6565
);
6666

67+
// Flush all IP addresses from WireGuard interface.
68+
debug!(
69+
"Flushing all existing IP addresses from interface {} before assigning a new one",
70+
self.ifname
71+
);
72+
bsd::flush_interface(&self.ifname)?;
73+
debug!(
74+
"All existing IP addresses flushed from interface {}",
75+
self.ifname
76+
);
77+
6778
// Assign IP address to the interface.
6879
for address in &config.addresses {
6980
self.assign_address(address)?;

src/wgapi_linux.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
3939
self.ifname
4040
);
4141

42-
// flush all IP addresses
42+
// Flush all IP addresses from WireGuard interface.
4343
debug!(
4444
"Flushing all existing IP addresses from interface {} before assigning a new one",
4545
self.ifname

0 commit comments

Comments
 (0)