1use crate::{
7 Wintun,
8 error::{Error, OutOfRangeData},
9 handle::{SafeEvent, UnsafeHandle},
10 session::Session,
11 util::{self},
12 wintun_raw,
13};
14use std::{
15 ffi::OsStr,
16 net::{IpAddr, Ipv4Addr},
17 os::windows::prelude::OsStrExt,
18 ptr,
19 sync::Arc,
20 sync::OnceLock,
21};
22use windows_sys::{
23 Win32::NetworkManagement::{IpHelper::ConvertLengthToIpv4Mask, Ndis::NET_LUID_LH},
24 core::GUID,
25};
26
27pub struct Adapter {
29 adapter: UnsafeHandle<wintun_raw::WINTUN_ADAPTER_HANDLE>,
30 pub(crate) wintun: Wintun,
31 guid: u128,
32 index: u32,
33 luid: NET_LUID_LH,
34}
35
36impl Adapter {
37 pub fn get_name(&self) -> Result<String, Error> {
40 Ok(crate::ffi::luid_to_alias(&self.luid)?)
41 }
42
43 pub fn set_name(&self, name: &str) -> Result<(), Error> {
48 let args = &[
51 "interface",
52 "set",
53 "interface",
54 &format!("name=\"{}\"", self.get_name()?),
55 &format!("newname=\"{}\"", name),
56 ];
57 util::run_command("netsh", args)?;
58
59 Ok(())
60 }
61
62 pub fn get_guid(&self) -> u128 {
63 self.guid
64 }
65
66 pub fn create(wintun: &Wintun, name: &str, tunnel_type: &str, guid: Option<u128>) -> Result<Arc<Adapter>, Error> {
70 let name_utf16: Vec<_> = name.encode_utf16().chain(std::iter::once(0)).collect();
71 let tunnel_type_utf16: Vec<u16> = tunnel_type.encode_utf16().chain(std::iter::once(0)).collect();
72
73 let mut guid = match guid {
74 Some(guid) => guid,
75 None => {
76 let mut guid: GUID = unsafe { std::mem::zeroed() };
77 unsafe { windows_sys::Win32::System::Rpc::UuidCreate(&mut guid as *mut GUID) };
78 util::win_guid_to_u128(&guid)
79 }
80 };
81
82 crate::log::set_default_logger_if_unset(wintun);
83
84 let guid_s: GUID = GUID::from_u128(guid);
85 let result = unsafe { wintun.WintunCreateAdapter(name_utf16.as_ptr(), tunnel_type_utf16.as_ptr(), &guid_s) };
86
87 if result.is_null() {
88 return crate::log::extract_wintun_log_error("WintunCreateAdapter failed")?;
89 }
90 let mut call = || -> Result<Arc<Adapter>, Error> {
91 let luid = crate::ffi::alias_to_luid(name)?;
92 let index = crate::ffi::luid_to_index(&luid)?;
93 let real_guid = util::win_guid_to_u128(&crate::ffi::luid_to_guid(&luid)?);
94 if guid != real_guid {
95 let real_guid_s = util::guid_to_win_style_string(&GUID::from_u128(real_guid))?;
96 let guid_s = util::guid_to_win_style_string(&GUID::from_u128(guid))?;
97 let (major, minor, build) = util::get_windows_version()?;
98 log::warn!(
99 "Windows {major}.{minor}.{build} internal bug cause the GUID mismatch: Expected {guid_s}, got {real_guid_s}"
100 );
101 guid = real_guid;
102 }
103 Ok(Arc::new(Adapter {
104 adapter: UnsafeHandle(result),
105 wintun: wintun.clone(),
106 guid,
107 index,
108 luid,
109 }))
110 };
111 match call() {
112 Ok(adapter) => Ok(adapter),
113 Err(e) => {
114 unsafe { wintun.WintunCloseAdapter(result) };
115 Err(e)
116 }
117 }
118 }
119
120 pub fn open(wintun: &Wintun, name: &str) -> Result<Arc<Adapter>, Error> {
122 let name_utf16: Vec<u16> = OsStr::new(name).encode_wide().chain(std::iter::once(0)).collect();
123
124 crate::log::set_default_logger_if_unset(wintun);
125
126 let result = unsafe { wintun.WintunOpenAdapter(name_utf16.as_ptr()) };
127
128 if result.is_null() {
129 return crate::log::extract_wintun_log_error("WintunOpenAdapter failed")?;
130 }
131 let call = || -> Result<Arc<Adapter>, Error> {
132 let luid = crate::ffi::alias_to_luid(name)?;
133 let index = crate::ffi::luid_to_index(&luid)?;
134 let guid = crate::ffi::luid_to_guid(&luid)?;
135 let guid = util::win_guid_to_u128(&guid);
136 Ok(Arc::new(Adapter {
137 adapter: UnsafeHandle(result),
138 wintun: wintun.clone(),
139 guid,
140 index,
141 luid,
142 }))
143 };
144 match call() {
145 Ok(adapter) => Ok(adapter),
146 Err(e) => {
147 unsafe { wintun.WintunCloseAdapter(result) };
148 Err(e)
149 }
150 }
151 }
152
153 pub fn delete(self) -> Result<(), Error> {
155 drop(self);
157 Ok(())
160 }
161
162 fn validate_capacity(capacity: u32) -> Result<(), Error> {
163 let range = crate::MIN_RING_CAPACITY..=crate::MAX_RING_CAPACITY;
164 if !range.contains(&capacity) {
165 return Err(Error::CapacityOutOfRange(OutOfRangeData { range, value: capacity }));
166 }
167 if !capacity.is_power_of_two() {
168 return Err(Error::CapacityNotPowerOfTwo(capacity));
169 }
170 Ok(())
171 }
172
173 pub fn start_session(self: &Arc<Self>, capacity: u32) -> Result<Arc<Session>, Error> {
178 Self::validate_capacity(capacity)?;
179
180 let result = unsafe { self.wintun.WintunStartSession(self.adapter.0, capacity) };
181
182 if result.is_null() {
183 return crate::log::extract_wintun_log_error("WintunStartSession failed")?;
184 }
185 let shutdown_event = SafeEvent::new(true, false)?;
187 Ok(Arc::new(Session {
188 inner: UnsafeHandle(result),
189 read_event: OnceLock::new(),
190 shutdown_event: Arc::new(shutdown_event),
191 adapter: self.clone(),
192 }))
193 }
194
195 pub fn get_luid(&self) -> NET_LUID_LH {
197 self.luid
198 }
199
200 pub fn set_mtu(&self, mtu: usize) -> Result<(), Error> {
202 util::set_adapter_mtu(&self.luid, mtu, false)?;
203 util::set_adapter_mtu(&self.luid, mtu, true)?;
205 Ok(())
206 }
207
208 pub fn get_mtu(&self) -> Result<usize, Error> {
210 Ok(util::get_adapter_mtu(&self.luid, false)? as _)
212 }
213
214 pub fn get_adapter_index(&self) -> Result<u32, Error> {
217 Ok(self.index)
218 }
219
220 pub fn set_address(&self, address: Ipv4Addr) -> Result<(), Error> {
222 let binding = self.get_addresses()?;
223 let old_address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
224 let mask = match old_address {
225 Some(IpAddr::V4(addr)) => self.get_netmask_of_address(&(*addr).into())?,
226 _ => "255.255.255.0".parse()?,
227 };
228 let gateway = self
229 .get_gateways()?
230 .iter()
231 .find(|addr| matches!(addr, IpAddr::V4(_)))
232 .cloned();
233 self.set_network_addresses_tuple(address.into(), mask, gateway)?;
234 Ok(())
235 }
236
237 pub fn set_gateway(&self, gateway: Option<Ipv4Addr>) -> Result<(), Error> {
239 let binding = self.get_addresses()?;
240 let address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
241 let address = match address {
242 Some(IpAddr::V4(addr)) => addr,
243 _ => return Err("Unable to find IPv4 address".into()),
244 };
245 let mask = self.get_netmask_of_address(&(*address).into())?;
246 let gateway = gateway.map(|addr| addr.into());
247 self.set_network_addresses_tuple((*address).into(), mask, gateway)?;
248 Ok(())
249 }
250
251 pub fn set_netmask(&self, mask: Ipv4Addr) -> Result<(), Error> {
253 let binding = self.get_addresses()?;
254 let address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
255 let address = match address {
256 Some(IpAddr::V4(addr)) => addr,
257 _ => return Err("Unable to find IPv4 address".into()),
258 };
259 let gateway = self
260 .get_gateways()?
261 .iter()
262 .find(|addr| matches!(addr, IpAddr::V4(_)))
263 .cloned();
264 self.set_network_addresses_tuple((*address).into(), mask.into(), gateway)?;
265 Ok(())
266 }
267
268 pub fn set_dns_servers(&self, dns_servers: &[IpAddr]) -> Result<(), Error> {
270 let interface = GUID::from_u128(self.get_guid());
271 if let Err(e) = util::set_interface_dns_servers(interface, dns_servers) {
272 log::debug!("Failed to set DNS servers in first attempt: \"{}\", try another...", e);
273 util::set_interface_dns_servers_via_cmd(&self.get_name()?, dns_servers)?;
274 }
275 Ok(())
276 }
277
278 pub fn set_network_addresses_tuple(
280 &self,
281 address: IpAddr,
282 mask: IpAddr,
283 gateway: Option<IpAddr>,
284 ) -> Result<(), Error> {
285 let name = self.get_name()?;
286 let mut args: Vec<String> = vec![
290 "interface".into(),
291 if address.is_ipv4() {
292 "ipv4".into()
293 } else {
294 "ipv6".into()
295 },
296 "set".into(),
297 "address".into(),
298 format!("name=\"{}\"", name),
299 "source=static".into(),
300 format!("address={}", address),
301 format!("mask={}", mask),
302 ];
303 if let Some(gateway) = gateway {
304 args.push(format!("gateway={}", gateway));
305 }
306 util::run_command("netsh", &args.iter().map(|s| s.as_str()).collect::<Vec<&str>>())?;
307 Ok(())
308 }
309
310 pub fn get_addresses(&self) -> Result<Vec<IpAddr>, Error> {
312 let name = util::guid_to_win_style_string(&GUID::from_u128(self.guid))?;
313
314 let mut adapter_addresses = vec![];
315
316 util::get_adapters_addresses(|adapter| {
317 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
318 Ok(name) => name,
319 Err(err) => {
320 log::error!("Failed to parse adapter name: {}", err);
321 return false;
322 }
323 };
324 if name_iter == name {
325 let mut current_address = adapter.FirstUnicastAddress;
326 while !current_address.is_null() {
327 let address = unsafe { (*current_address).Address };
328 match util::retrieve_ipaddr_from_socket_address(&address) {
329 Ok(addr) => adapter_addresses.push(addr),
330 Err(err) => {
331 log::error!("Failed to parse address: {}", err);
332 }
333 }
334 unsafe { current_address = (*current_address).Next };
335 }
336 }
337 true
338 })?;
339
340 Ok(adapter_addresses)
341 }
342
343 pub fn get_gateways(&self) -> Result<Vec<IpAddr>, Error> {
345 let name = util::guid_to_win_style_string(&GUID::from_u128(self.guid))?;
346 let mut gateways = vec![];
347 util::get_adapters_addresses(|adapter| {
348 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
349 Ok(name) => name,
350 Err(err) => {
351 log::error!("Failed to parse adapter name: {}", err);
352 return false;
353 }
354 };
355 if name_iter == name {
356 let mut current_gateway = adapter.FirstGatewayAddress;
357 while !current_gateway.is_null() {
358 let gateway = unsafe { (*current_gateway).Address };
359 match util::retrieve_ipaddr_from_socket_address(&gateway) {
360 Ok(addr) => gateways.push(addr),
361 Err(err) => {
362 log::error!("Failed to parse gateway: {}", err);
363 }
364 }
365 unsafe { current_gateway = (*current_gateway).Next };
366 }
367 }
368 true
369 })?;
370 Ok(gateways)
371 }
372
373 pub fn get_netmask_of_address(&self, target_address: &IpAddr) -> Result<IpAddr, Error> {
375 let name = util::guid_to_win_style_string(&GUID::from_u128(self.guid))?;
376 let mut subnet_mask = None;
377 util::get_adapters_addresses(|adapter| {
378 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
379 Ok(name) => name,
380 Err(err) => {
381 log::warn!("Failed to parse adapter name: {}", err);
382 return false;
383 }
384 };
385 if name_iter == name {
386 let mut current_address = adapter.FirstUnicastAddress;
387 while !current_address.is_null() {
388 let address = unsafe { (*current_address).Address };
389 let address = match util::retrieve_ipaddr_from_socket_address(&address) {
390 Ok(addr) => addr,
391 Err(err) => {
392 log::warn!("Failed to parse address: {}", err);
393 return false;
394 }
395 };
396 if address == *target_address {
397 let masklength = unsafe { (*current_address).OnLinkPrefixLength };
398 match address {
399 IpAddr::V4(_) => {
400 let mut mask = 0_u32;
401 match unsafe { ConvertLengthToIpv4Mask(masklength as u32, &mut mask as *mut u32) } {
402 0 => {}
403 err => {
404 log::warn!("Failed to convert length to mask: {}", err);
405 return false;
406 }
407 }
408 subnet_mask = Some(IpAddr::V4(Ipv4Addr::from(mask.to_le_bytes())));
409 }
410 IpAddr::V6(_) => match util::ipv6_netmask_for_prefix(masklength) {
411 Ok(v) => subnet_mask = Some(IpAddr::V6(v)),
412 Err(err) => {
413 log::warn!("Failed to convert length to mask: {}", err);
414 return false;
415 }
416 },
417 }
418 break;
419 }
420 unsafe { current_address = (*current_address).Next };
421 }
422 }
423 true
424 })?;
425
426 Ok(subnet_mask.ok_or("Unable to find matching address")?)
427 }
428}
429
430impl Drop for Adapter {
431 fn drop(&mut self) {
432 let _name = self.get_name();
433 unsafe { self.wintun.WintunCloseAdapter(self.adapter.0) };
436 self.adapter = UnsafeHandle(ptr::null_mut());
437 #[cfg(feature = "winreg")]
438 if let Ok(name) = _name {
439 _ = delete_adapter_info_from_reg(&name);
441 }
442 }
443}
444
445#[cfg(feature = "winreg")]
447pub(crate) fn delete_adapter_info_from_reg(dev_name: &str) -> std::io::Result<()> {
448 use winreg::{RegKey, enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS};
449 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
450 let profiles_key = hklm.open_subkey_with_flags(
451 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
452 KEY_ALL_ACCESS,
453 )?;
454
455 for sub_key_name in profiles_key.enum_keys().filter_map(Result::ok) {
456 let sub_key = profiles_key.open_subkey(&sub_key_name)?;
457 match sub_key.get_value::<String, _>("ProfileName") {
458 Ok(profile_name) => {
459 if dev_name == profile_name {
460 match profiles_key.delete_subkey_all(&sub_key_name) {
461 Ok(_) => log::info!("Successfully deleted Profiles sub_key: {}", sub_key_name),
462 Err(e) => log::warn!("Failed to delete Profiles sub_key {}: {}", sub_key_name, e),
463 }
464 }
465 }
466 Err(e) => log::warn!("Failed to read ProfileName for sub_key {}: {}", sub_key_name, e),
467 }
468 }
469 let unmanaged_key = hklm.open_subkey_with_flags(
470 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
471 KEY_ALL_ACCESS,
472 )?;
473 for sub_key_name in unmanaged_key.enum_keys().filter_map(Result::ok) {
474 let sub_key = unmanaged_key.open_subkey(&sub_key_name)?;
475 match sub_key.get_value::<String, _>("Description") {
476 Ok(description) => {
477 if dev_name == description {
478 match unmanaged_key.delete_subkey_all(&sub_key_name) {
479 Ok(_) => log::info!("Successfully deleted Unmanaged sub_key: {}", sub_key_name),
480 Err(e) => log::warn!("Failed to delete Unmanaged sub_key {}: {}", sub_key_name, e),
481 }
482 }
483 }
484 Err(e) => log::warn!("Failed to read Description for sub_key {}: {}", sub_key_name, e),
485 }
486 }
487 Ok(())
488}