1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
use crate::IphlpNetworkAdapterInfo;
use std::net::{Ipv4Addr, Ipv6Addr};
use windows::Win32::NetworkManagement::IpHelper::{CreateIpNetEntry2, DeleteIpNetEntry2};
use windows::Win32::Networking::WinSock::NlnsPermanent;
use windows::Win32::{
Foundation::{SetLastError, ERROR_SUCCESS, NO_ERROR},
NetworkManagement::IpHelper::MIB_IPNET_ROW2,
Networking::WinSock::{AF_INET, AF_INET6, IN6_ADDR, IN6_ADDR_0},
};
use super::util::{set_is_router, set_is_unreachable};
impl IphlpNetworkAdapterInfo {
/// Adds an IPv4 NDP entry for the network interface.
///
/// # Arguments
///
/// * `address`: Ipv4Addr
/// * `hw_address`: [u8; 6] hardware address
///
/// # Returns
///
/// * `Option<MIB_IPNET_ROW2>`: Some with a MIB_IPNET_ROW2 if successful, None otherwise.
///
/// # Safety
///
/// This function uses unsafe Windows API calls to create an IP Net entry.
/// The caller should ensure that the provided IPv4 address and hardware address are valid and
/// that the network interface is properly configured before calling this function.
pub fn add_ndp_entry_ipv4(
&self,
address: Ipv4Addr,
hw_address: [u8; 6],
) -> Option<MIB_IPNET_ROW2> {
let mut net_row = unsafe { std::mem::zeroed::<MIB_IPNET_ROW2>() };
net_row.Address.si_family = AF_INET;
net_row.Address.Ipv4.sin_family = AF_INET;
net_row.Address.Ipv4.sin_addr.S_un.S_addr = u32::from(address);
net_row.InterfaceIndex = self.if_index;
net_row.InterfaceLuid = self.luid.into();
net_row.PhysicalAddress.copy_from_slice(&hw_address);
net_row.PhysicalAddressLength = 6;
net_row.State = NlnsPermanent;
unsafe {
set_is_router(&mut net_row, true);
set_is_unreachable(&mut net_row, true);
}
unsafe { SetLastError(ERROR_SUCCESS) };
let error_code = unsafe { CreateIpNetEntry2(&net_row) };
if error_code == NO_ERROR {
Some(net_row)
} else {
unsafe { SetLastError(error_code) };
None
}
}
/// Adds an IPv6 NDP entry for the network interface.
///
/// # Arguments
///
/// * `address`: Ipv6Addr
/// * `hw_address`: [u8; 6] hardware address
///
/// # Returns
///
/// * `Option<MIB_IPNET_ROW2>`: Some with a MIB_IPNET_ROW2 if successful, None otherwise.
///
/// # Safety
///
/// This function uses unsafe Windows API calls to create an IP Net entry.
/// The caller should ensure that the provided IPv6 address and hardware address are valid and
/// that the network interface is properly configured before calling this function.
pub fn add_ndp_entry_ipv6(
&self,
address: Ipv6Addr,
hw_address: [u8; 6],
) -> Option<MIB_IPNET_ROW2> {
let mut net_row = unsafe { std::mem::zeroed::<MIB_IPNET_ROW2>() };
net_row.Address.si_family = AF_INET6;
net_row.Address.Ipv6.sin6_family = AF_INET6;
net_row.Address.Ipv6.sin6_addr = IN6_ADDR {
u: IN6_ADDR_0 {
Byte: address.octets(),
},
};
net_row.InterfaceIndex = self.ipv6_if_index;
net_row.InterfaceLuid = self.luid.into();
net_row.PhysicalAddress.copy_from_slice(&hw_address);
net_row.PhysicalAddressLength = 6;
net_row.State = NlnsPermanent;
unsafe {
set_is_router(&mut net_row, true);
set_is_unreachable(&mut net_row, true);
}
unsafe { SetLastError(ERROR_SUCCESS) };
let error_code = unsafe { CreateIpNetEntry2(&net_row) };
if error_code == NO_ERROR {
Some(net_row)
} else {
unsafe { SetLastError(error_code) };
None
}
}
/// Removes an NDP entry by a MIB_IPNET_ROW2 reference.
///
/// # Arguments
///
/// * `address`: A reference to MIB_IPNET_ROW2
///
/// # Returns
///
/// * `bool`: `true` if successful, `false` otherwise.
///
/// # Safety
///
/// This function uses unsafe Windows API calls to delete an IP Net entry.
/// The caller should ensure that the provided MIB_IPNET_ROW2 reference is valid
/// and points to an existing NDP entry before calling this function.
pub fn delete_ndp_entry(address: &MIB_IPNET_ROW2) -> bool {
unsafe { SetLastError(ERROR_SUCCESS) };
let error_code = unsafe { DeleteIpNetEntry2(address) };
if error_code == NO_ERROR {
true
} else {
unsafe { SetLastError(error_code) };
false
}
}
}