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::{
24 Foundation::ERROR_NOT_FOUND,
25 NetworkManagement::{IpHelper::ConvertLengthToIpv4Mask, Ndis::NET_LUID_LH},
26 },
27 core::GUID,
28};
29
30pub struct Adapter {
32 adapter: UnsafeHandle<wintun_raw::WINTUN_ADAPTER_HANDLE>,
33 pub(crate) wintun: Wintun,
34 requested_guid: Option<u128>,
35 guid: OnceLock<u128>,
36 index: OnceLock<u32>,
37 luid: NET_LUID_LH,
38}
39
40impl Adapter {
41 pub fn get_name(&self) -> Result<String, Error> {
44 Ok(crate::ffi::luid_to_alias(&self.luid)?)
45 }
46
47 pub fn set_name(&self, name: &str) -> Result<(), Error> {
52 let args = &[
55 "interface",
56 "set",
57 "interface",
58 &format!("name=\"{}\"", self.get_name()?),
59 &format!("newname=\"{}\"", name),
60 ];
61 util::run_command("netsh", args)?;
62
63 Ok(())
64 }
65
66 pub fn get_guid(&self) -> u128 {
67 if let Some(guid) = self.guid.get() {
68 return *guid;
69 }
70
71 let real_guid = match resolve_with_retry(|| crate::ffi::luid_to_guid(&self.luid)) {
72 Ok(g) => util::win_guid_to_u128(&g),
73 Err(_) => return self.requested_guid.unwrap_or(0),
74 };
75
76 if let Some(req) = self.requested_guid
77 && req != real_guid
78 && let (Ok(real_s), Ok(req_s), Ok((major, minor, build))) = (
79 util::guid_to_win_style_string(&GUID::from_u128(real_guid)),
80 util::guid_to_win_style_string(&GUID::from_u128(req)),
81 util::get_windows_version(),
82 )
83 {
84 log::warn!(
85 "Windows {major}.{minor}.{build}: an internal bug causes the GUID mismatch: Expected {req_s}, got {real_s}"
86 );
87 }
88
89 match self.guid.set(real_guid) {
90 Ok(()) => real_guid,
91 Err(_) => *self
92 .guid
93 .get()
94 .expect("guid should be initialized by this thread or another"),
95 }
96 }
97
98 pub fn create(wintun: &Wintun, name: &str, tunnel_type: &str, guid: Option<u128>) -> Result<Arc<Adapter>, Error> {
102 let name_utf16: Vec<_> = name.encode_utf16().chain(std::iter::once(0)).collect();
103 let tunnel_type_utf16: Vec<u16> = tunnel_type.encode_utf16().chain(std::iter::once(0)).collect();
104
105 let requested_guid = guid.unwrap_or_else(|| {
106 let mut guid: GUID = unsafe { std::mem::zeroed() };
107 unsafe { windows_sys::Win32::System::Rpc::UuidCreate(&mut guid as *mut GUID) };
108 util::win_guid_to_u128(&guid)
109 });
110
111 crate::log::set_default_logger_if_unset(wintun);
112
113 let guid_s: GUID = GUID::from_u128(requested_guid);
114 let result = unsafe { wintun.WintunCreateAdapter(name_utf16.as_ptr(), tunnel_type_utf16.as_ptr(), &guid_s) };
115
116 if result.is_null() {
117 return crate::log::extract_wintun_log_error("WintunCreateAdapter failed")?;
118 }
119
120 let mut luid: NET_LUID_LH = unsafe { std::mem::zeroed() };
121 unsafe { wintun.WintunGetAdapterLUID(result, &mut luid) };
122
123 Ok(Arc::new(Adapter {
124 adapter: UnsafeHandle(result),
125 wintun: wintun.clone(),
126 luid,
127 requested_guid: Some(requested_guid),
128 guid: OnceLock::new(),
129 index: OnceLock::new(),
130 }))
131 }
132
133 pub fn open(wintun: &Wintun, name: &str) -> Result<Arc<Adapter>, Error> {
135 let name_utf16: Vec<u16> = OsStr::new(name).encode_wide().chain(std::iter::once(0)).collect();
136
137 crate::log::set_default_logger_if_unset(wintun);
138
139 let result = unsafe { wintun.WintunOpenAdapter(name_utf16.as_ptr()) };
140
141 if result.is_null() {
142 return crate::log::extract_wintun_log_error("WintunOpenAdapter failed")?;
143 }
144
145 let mut luid: NET_LUID_LH = unsafe { std::mem::zeroed() };
146 unsafe { wintun.WintunGetAdapterLUID(result, &mut luid) };
147
148 Ok(Arc::new(Adapter {
149 adapter: UnsafeHandle(result),
150 wintun: wintun.clone(),
151 luid,
152 requested_guid: None,
153 guid: OnceLock::new(),
154 index: OnceLock::new(),
155 }))
156 }
157
158 pub fn delete(self) -> Result<(), Error> {
160 drop(self);
162 Ok(())
165 }
166
167 fn validate_capacity(capacity: u32) -> Result<(), Error> {
168 let range = crate::MIN_RING_CAPACITY..=crate::MAX_RING_CAPACITY;
169 if !range.contains(&capacity) {
170 return Err(Error::CapacityOutOfRange(OutOfRangeData { range, value: capacity }));
171 }
172 if !capacity.is_power_of_two() {
173 return Err(Error::CapacityNotPowerOfTwo(capacity));
174 }
175 Ok(())
176 }
177
178 pub fn start_session(self: &Arc<Self>, capacity: u32) -> Result<Arc<Session>, Error> {
183 Self::validate_capacity(capacity)?;
184
185 let result = unsafe { self.wintun.WintunStartSession(self.adapter.0, capacity) };
186
187 if result.is_null() {
188 return crate::log::extract_wintun_log_error("WintunStartSession failed")?;
189 }
190 let shutdown_event = SafeEvent::new(true, false)?;
192 Ok(Arc::new(Session {
193 inner: UnsafeHandle(result),
194 read_event: OnceLock::new(),
195 shutdown_event: Arc::new(shutdown_event),
196 adapter: self.clone(),
197 }))
198 }
199
200 pub fn get_luid(&self) -> NET_LUID_LH {
202 self.luid
203 }
204
205 pub fn set_mtu(&self, mtu: usize) -> Result<(), Error> {
207 util::set_adapter_mtu(&self.luid, mtu, false)?;
208 if let Err(e) = util::set_adapter_mtu(&self.luid, mtu, true) {
212 if e.raw_os_error() != Some(ERROR_NOT_FOUND as i32) {
213 return Err(e.into());
214 }
215 log::warn!("skipping IPv6 MTU, no IPv6 interface row");
216 }
217 Ok(())
218 }
219
220 pub fn get_mtu(&self) -> Result<usize, Error> {
222 Ok(util::get_adapter_mtu(&self.luid, false)? as _)
224 }
225
226 pub fn get_adapter_index(&self) -> Result<u32, Error> {
229 if let Some(idx) = self.index.get() {
230 return Ok(*idx);
231 }
232 let idx = resolve_with_retry(|| crate::ffi::luid_to_index(&self.luid))?;
233 Ok(*self.index.get_or_init(|| idx))
234 }
235
236 pub fn set_address(&self, address: Ipv4Addr) -> Result<(), Error> {
238 let binding = self.get_addresses()?;
239 let old_address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
240 let mask = match old_address {
241 Some(IpAddr::V4(addr)) => self.get_netmask_of_address(&(*addr).into())?,
242 _ => "255.255.255.0".parse()?,
243 };
244 let gateway = self
245 .get_gateways()?
246 .iter()
247 .find(|addr| matches!(addr, IpAddr::V4(_)))
248 .cloned();
249 self.set_network_addresses_tuple(address.into(), mask, gateway)?;
250 Ok(())
251 }
252
253 pub fn set_gateway(&self, gateway: Option<Ipv4Addr>) -> Result<(), Error> {
255 let binding = self.get_addresses()?;
256 let address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
257 let address = match address {
258 Some(IpAddr::V4(addr)) => addr,
259 _ => return Err("Unable to find IPv4 address".into()),
260 };
261 let mask = self.get_netmask_of_address(&(*address).into())?;
262 let gateway = gateway.map(|addr| addr.into());
263 self.set_network_addresses_tuple((*address).into(), mask, gateway)?;
264 Ok(())
265 }
266
267 pub fn set_netmask(&self, mask: Ipv4Addr) -> Result<(), Error> {
269 let binding = self.get_addresses()?;
270 let address = binding.iter().find(|addr| matches!(addr, IpAddr::V4(_)));
271 let address = match address {
272 Some(IpAddr::V4(addr)) => addr,
273 _ => return Err("Unable to find IPv4 address".into()),
274 };
275 let gateway = self
276 .get_gateways()?
277 .iter()
278 .find(|addr| matches!(addr, IpAddr::V4(_)))
279 .cloned();
280 self.set_network_addresses_tuple((*address).into(), mask.into(), gateway)?;
281 Ok(())
282 }
283
284 pub fn set_dns_servers(&self, dns_servers: &[IpAddr]) -> Result<(), Error> {
286 let interface = GUID::from_u128(self.get_guid());
287 if let Err(e) = util::set_interface_dns_servers(interface, dns_servers) {
288 log::debug!("Failed to set DNS servers in first attempt: \"{}\", try another...", e);
289 if let Err(e) = crate::dns_via_reg::set_dns_via_registry(&interface, dns_servers) {
290 log::debug!("Failed to set DNS servers via registry: \"{}\", try another...", e);
291 util::set_interface_dns_servers_via_cmd(&self.get_name()?, dns_servers)?;
292 }
293 }
294 Ok(())
295 }
296
297 pub fn set_network_addresses_tuple(
299 &self,
300 address: IpAddr,
301 mask: IpAddr,
302 gateway: Option<IpAddr>,
303 ) -> Result<(), Error> {
304 let name = self.get_name()?;
305 let mut args: Vec<String> = vec![
309 "interface".into(),
310 if address.is_ipv4() {
311 "ipv4".into()
312 } else {
313 "ipv6".into()
314 },
315 "set".into(),
316 "address".into(),
317 format!("name=\"{}\"", name),
318 "source=static".into(),
319 format!("address={}", address),
320 format!("mask={}", mask),
321 ];
322 if let Some(gateway) = gateway {
323 args.push(format!("gateway={}", gateway));
324 }
325 util::run_command("netsh", &args.iter().map(|s| s.as_str()).collect::<Vec<&str>>())?;
326 Ok(())
327 }
328
329 pub fn get_addresses(&self) -> Result<Vec<IpAddr>, Error> {
331 let name = util::guid_to_win_style_string(&GUID::from_u128(self.get_guid()))?;
332
333 let mut adapter_addresses = vec![];
334
335 util::get_adapters_addresses(|adapter| {
336 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
337 Ok(name) => name,
338 Err(err) => {
339 log::error!("Failed to parse adapter name: {}", err);
340 return false;
341 }
342 };
343 if name_iter == name {
344 let mut current_address = adapter.FirstUnicastAddress;
345 while !current_address.is_null() {
346 let address = unsafe { (*current_address).Address };
347 match util::retrieve_ipaddr_from_socket_address(&address) {
348 Ok(addr) => adapter_addresses.push(addr),
349 Err(err) => {
350 log::error!("Failed to parse address: {}", err);
351 }
352 }
353 unsafe { current_address = (*current_address).Next };
354 }
355 }
356 true
357 })?;
358
359 Ok(adapter_addresses)
360 }
361
362 pub fn get_gateways(&self) -> Result<Vec<IpAddr>, Error> {
364 let name = util::guid_to_win_style_string(&GUID::from_u128(self.get_guid()))?;
365 let mut gateways = vec![];
366 util::get_adapters_addresses(|adapter| {
367 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
368 Ok(name) => name,
369 Err(err) => {
370 log::error!("Failed to parse adapter name: {}", err);
371 return false;
372 }
373 };
374 if name_iter == name {
375 let mut current_gateway = adapter.FirstGatewayAddress;
376 while !current_gateway.is_null() {
377 let gateway = unsafe { (*current_gateway).Address };
378 match util::retrieve_ipaddr_from_socket_address(&gateway) {
379 Ok(addr) => gateways.push(addr),
380 Err(err) => {
381 log::error!("Failed to parse gateway: {}", err);
382 }
383 }
384 unsafe { current_gateway = (*current_gateway).Next };
385 }
386 }
387 true
388 })?;
389 Ok(gateways)
390 }
391
392 pub fn get_netmask_of_address(&self, target_address: &IpAddr) -> Result<IpAddr, Error> {
394 let name = util::guid_to_win_style_string(&GUID::from_u128(self.get_guid()))?;
395 let mut subnet_mask = None;
396 util::get_adapters_addresses(|adapter| {
397 let name_iter = match unsafe { util::win_pstr_to_string(adapter.AdapterName) } {
398 Ok(name) => name,
399 Err(err) => {
400 log::warn!("Failed to parse adapter name: {}", err);
401 return false;
402 }
403 };
404 if name_iter == name {
405 let mut current_address = adapter.FirstUnicastAddress;
406 while !current_address.is_null() {
407 let address = unsafe { (*current_address).Address };
408 let address = match util::retrieve_ipaddr_from_socket_address(&address) {
409 Ok(addr) => addr,
410 Err(err) => {
411 log::warn!("Failed to parse address: {}", err);
412 return false;
413 }
414 };
415 if address == *target_address {
416 let masklength = unsafe { (*current_address).OnLinkPrefixLength };
417 match address {
418 IpAddr::V4(_) => {
419 let mut mask = 0_u32;
420 match unsafe { ConvertLengthToIpv4Mask(masklength as u32, &mut mask as *mut u32) } {
421 0 => {}
422 err => {
423 log::warn!("Failed to convert length to mask: {}", err);
424 return false;
425 }
426 }
427 subnet_mask = Some(IpAddr::V4(Ipv4Addr::from(mask.to_le_bytes())));
428 }
429 IpAddr::V6(_) => match util::ipv6_netmask_for_prefix(masklength) {
430 Ok(v) => subnet_mask = Some(IpAddr::V6(v)),
431 Err(err) => {
432 log::warn!("Failed to convert length to mask: {}", err);
433 return false;
434 }
435 },
436 }
437 break;
438 }
439 unsafe { current_address = (*current_address).Next };
440 }
441 }
442 true
443 })?;
444
445 Ok(subnet_mask.ok_or("Unable to find matching address")?)
446 }
447}
448
449impl Drop for Adapter {
450 fn drop(&mut self) {
451 let _name = self.get_name();
452 unsafe { self.wintun.WintunCloseAdapter(self.adapter.0) };
455 self.adapter = UnsafeHandle(ptr::null_mut());
456 #[cfg(feature = "winreg")]
457 if let Ok(name) = _name {
458 _ = delete_adapter_info_from_reg(&name);
460 }
461 }
462}
463
464#[cfg(feature = "winreg")]
466pub(crate) fn delete_adapter_info_from_reg(dev_name: &str) -> std::io::Result<()> {
467 use windows_sys::Win32::Foundation::ERROR_NO_MORE_ITEMS;
468 use windows_sys::Win32::System::Registry::{
469 HKEY, HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, KEY_READ, REG_SZ, RegCloseKey, RegDeleteTreeW, RegEnumKeyExW,
470 RegOpenKeyExW, RegQueryValueExW,
471 };
472
473 fn to_wide_null(value: &str) -> Vec<u16> {
474 value.encode_utf16().chain(std::iter::once(0)).collect()
475 }
476
477 fn open_registry_key(parent: HKEY, subkey: &str, access: u32) -> std::io::Result<HKEY> {
478 let subkey_wide = to_wide_null(subkey);
479 let mut handle: HKEY = std::ptr::null_mut();
480 let status = unsafe { RegOpenKeyExW(parent, subkey_wide.as_ptr(), 0, access, &mut handle) };
481 if status != 0 {
482 return Err(std::io::Error::from_raw_os_error(status as i32));
483 }
484 Ok(handle)
485 }
486
487 fn enum_registry_subkeys(hkey: HKEY) -> std::io::Result<Vec<String>> {
488 let mut subkeys = Vec::new();
489 let mut index = 0;
490 loop {
491 let mut name = vec![0u16; 260];
492 let mut name_len = name.len() as u32;
493 let status = unsafe {
494 RegEnumKeyExW(
495 hkey,
496 index,
497 name.as_mut_ptr(),
498 &mut name_len,
499 std::ptr::null_mut(),
500 std::ptr::null_mut(),
501 std::ptr::null_mut(),
502 std::ptr::null_mut(),
503 )
504 };
505 if status == ERROR_NO_MORE_ITEMS {
506 break;
507 }
508 if status != 0 {
509 return Err(std::io::Error::from_raw_os_error(status as i32));
510 }
511 subkeys.push(String::from_utf16_lossy(&name[..name_len as usize]));
512 index += 1;
513 }
514 Ok(subkeys)
515 }
516
517 fn query_registry_string_value(hkey: HKEY, value_name: &str) -> std::io::Result<String> {
518 let value_name_wide = to_wide_null(value_name);
519 let mut value_type = 0_u32;
520 let mut data_len = 0_u32;
521 let status = unsafe {
522 RegQueryValueExW(
523 hkey,
524 value_name_wide.as_ptr(),
525 std::ptr::null_mut(),
526 &mut value_type,
527 std::ptr::null_mut(),
528 &mut data_len,
529 )
530 };
531 if status != 0 {
532 return Err(std::io::Error::from_raw_os_error(status as i32));
533 }
534 if value_type != REG_SZ {
535 return Err(std::io::Error::new(
536 std::io::ErrorKind::InvalidData,
537 "Registry value is not a string",
538 ));
539 }
540 let mut buffer = vec![0u16; (data_len as usize / 2).max(1)];
541 let status = unsafe {
542 RegQueryValueExW(
543 hkey,
544 value_name_wide.as_ptr(),
545 std::ptr::null_mut(),
546 std::ptr::null_mut(),
547 buffer.as_mut_ptr().cast(),
548 &mut data_len,
549 )
550 };
551 if status != 0 {
552 return Err(std::io::Error::from_raw_os_error(status as i32));
553 }
554 if let Some(&0) = buffer.last() {
555 buffer.pop();
556 }
557 String::from_utf16(&buffer).map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))
558 }
559
560 fn read_subkey_string_value(parent_key: HKEY, subkey_name: &str, value_name: &str) -> std::io::Result<String> {
561 let subkey_handle = open_registry_key(parent_key, subkey_name, KEY_READ)?;
562 let value = query_registry_string_value(subkey_handle, value_name);
563 unsafe { RegCloseKey(subkey_handle) };
564 value
565 }
566
567 fn delete_registry_tree(parent_key: HKEY, subkey_name: &str) -> std::io::Result<()> {
568 let subkey_wide = to_wide_null(subkey_name);
569 let status = unsafe { RegDeleteTreeW(parent_key, subkey_wide.as_ptr()) };
570 if status != 0 {
571 return Err(std::io::Error::from_raw_os_error(status as i32));
572 }
573 Ok(())
574 }
575
576 let profiles_key = open_registry_key(
577 HKEY_LOCAL_MACHINE,
578 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
579 KEY_ALL_ACCESS,
580 )?;
581 for sub_key_name in enum_registry_subkeys(profiles_key)? {
582 match read_subkey_string_value(profiles_key, &sub_key_name, "ProfileName") {
583 Ok(profile_name) => {
584 if dev_name == profile_name {
585 match delete_registry_tree(profiles_key, &sub_key_name) {
586 Ok(_) => log::info!("Successfully deleted Profiles sub_key: {}", sub_key_name),
587 Err(e) => log::warn!("Failed to delete Profiles sub_key {}: {}", sub_key_name, e),
588 }
589 }
590 }
591 Err(e) => log::warn!("Failed to read ProfileName for sub_key {}: {}", sub_key_name, e),
592 }
593 }
594 unsafe { RegCloseKey(profiles_key) };
595
596 let unmanaged_key = open_registry_key(
597 HKEY_LOCAL_MACHINE,
598 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
599 KEY_ALL_ACCESS,
600 )?;
601 for sub_key_name in enum_registry_subkeys(unmanaged_key)? {
602 match read_subkey_string_value(unmanaged_key, &sub_key_name, "Description") {
603 Ok(description) => {
604 if dev_name == description {
605 match delete_registry_tree(unmanaged_key, &sub_key_name) {
606 Ok(_) => log::info!("Successfully deleted Unmanaged sub_key: {}", sub_key_name),
607 Err(e) => log::warn!("Failed to delete Unmanaged sub_key {}: {}", sub_key_name, e),
608 }
609 }
610 }
611 Err(e) => log::warn!("Failed to read Description for sub_key {}: {}", sub_key_name, e),
612 }
613 }
614 unsafe { RegCloseKey(unmanaged_key) };
615
616 Ok(())
617}
618
619fn resolve_with_retry<T>(mut f: impl FnMut() -> std::io::Result<T>) -> std::io::Result<T> {
620 const NSI_RETRY_ATTEMPTS: usize = 3;
621 const NSI_RETRY_DELAY_MS: u64 = 25;
622
623 for attempt in 1..=NSI_RETRY_ATTEMPTS {
624 match f() {
625 Ok(v) => return Ok(v),
626 Err(e) if e.raw_os_error() == Some(ERROR_NOT_FOUND as i32) => {
627 if attempt == NSI_RETRY_ATTEMPTS {
628 return Err(e);
629 }
630 log::warn!("NSI race, retry {attempt}/{NSI_RETRY_ATTEMPTS}");
631 std::thread::sleep(std::time::Duration::from_millis(NSI_RETRY_DELAY_MS));
632 }
633 Err(e) => return Err(e),
634 }
635 }
636 unreachable!();
637}