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
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::ERROR_OBJECT_ALREADY_EXISTS,
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);
}
match unsafe { CreateIpNetEntry2(&net_row) }.ok() {
Ok(_) => Some(net_row),
Err(err) => {
if err == ERROR_OBJECT_ALREADY_EXISTS.into() {
Some(net_row)
} else {
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);
}
match unsafe { CreateIpNetEntry2(&net_row) }.ok() {
Ok(_) => Some(net_row),
Err(err) => {
if err == ERROR_OBJECT_ALREADY_EXISTS.into() {
Some(net_row)
} else {
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 { DeleteIpNetEntry2(address) }.is_ok()
}
}