@@ -6,7 +6,12 @@ mod timespec;
66mod wgio;
77
88use 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} ;
1722use route:: { DestAddrMask , GatewayLink } ;
18- use sockaddr:: { SockAddrDl , SockAddrIn , SockAddrIn6 } ;
23+ use sockaddr:: { SockAddrDl , SockAddrIn , SockAddrIn6 , SocketFromRaw } ;
1924use thiserror:: Error ;
2025
2126use 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
3648static NV_LISTEN_PORT : & str = "listen-port" ;
3749static 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+
373441pub fn get_mtu ( if_name : & str ) -> Result < u32 , IoError > {
374442 let mut ifmtu = IfMtu :: new ( if_name) ;
375443 ifmtu. get_mtu ( )
0 commit comments