mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-08 19:06:14 -08:00
119 lines
4.2 KiB
Rust
119 lines
4.2 KiB
Rust
//
|
|
// Port supporting code for wireguard-nt from wireguard-windows v0.5.3 to Rust
|
|
// This file replicates the functionality of wireguard-windows/tunnel/winipcfg/netsh.go
|
|
//
|
|
|
|
use std::{
|
|
net::{Ipv4Addr, Ipv6Addr},
|
|
process::{Command, Stdio},
|
|
};
|
|
use winapi::shared::ws2def::{ADDRESS_FAMILY, AF_INET, AF_INET6};
|
|
|
|
pub fn flush_dns(family: ADDRESS_FAMILY, if_index: u32) -> Result<(), String> {
|
|
let proto_name = match family as i32 {
|
|
AF_INET => "ipv4",
|
|
AF_INET6 => "ipv6",
|
|
_ => {
|
|
return Err(String::from("Invalid address family"));
|
|
}
|
|
};
|
|
|
|
//let netsh_params = format!("interface {proto} set dnsservers name={itf} source=static address=none validate=no register=both", proto=proto_name, itf=ip_itf.InterfaceIndex);
|
|
let ret_netsh = Command::new("netsh.exe")
|
|
.arg("interface")
|
|
.arg(proto_name)
|
|
.arg("set")
|
|
.arg("dnsservers")
|
|
.arg(format!("name={}", if_index))
|
|
.arg("source=static")
|
|
.arg("address=none")
|
|
.arg("validate=no")
|
|
.arg("register=both")
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.output();
|
|
match ret_netsh {
|
|
Ok(output) => {
|
|
// netsh.exe returns error messages only and is silent upon success. BUT then it will return \r\n, so we need to look at the lines.
|
|
if let Ok(stdout_str) = String::from_utf8(output.stdout) {
|
|
if stdout_str.is_empty() || stdout_str == "\r\n" {
|
|
Ok(())
|
|
} else {
|
|
// TODO: ignore "There are no Domain Name Servers (DNS) configured on this computer."
|
|
// Is this string localized?
|
|
Err(stdout_str)
|
|
}
|
|
} else {
|
|
Err(String::from("Could not parse netsh output"))
|
|
}
|
|
}
|
|
Err(_) => Err(String::from("Failed to execute command")),
|
|
}
|
|
}
|
|
|
|
// Please execute flush_dns() first, as written in the original source code.
|
|
fn add_dns(family: ADDRESS_FAMILY, if_index: u32, dnses: &[String]) -> Result<(), String> {
|
|
let proto_name = match family as i32 {
|
|
AF_INET => "ipv4",
|
|
AF_INET6 => "ipv6",
|
|
_ => {
|
|
return Err(String::from("Invalid address family"));
|
|
}
|
|
};
|
|
|
|
// "interface ipv4 add dnsservers name=%d address=%s validate=no"
|
|
let ret_netsh = Command::new("netsh.exe")
|
|
.arg("interface")
|
|
.arg(proto_name)
|
|
.arg("add")
|
|
.arg("dnsservers")
|
|
.arg(format!("name={}", if_index))
|
|
.arg(format!(
|
|
"address={}",
|
|
dnses
|
|
.iter()
|
|
.map(|x| x.to_string())
|
|
.collect::<Vec<_>>()
|
|
.join(",")
|
|
))
|
|
.arg("validate=no")
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.output();
|
|
match ret_netsh {
|
|
Ok(output) => {
|
|
// netsh.exe returns error messages only and is silent upon success. BUT then it will return \r\n, so we need to look at the lines.
|
|
if let Ok(stdout_str) = String::from_utf8(output.stdout) {
|
|
if stdout_str.is_empty() || stdout_str == "\r\n" {
|
|
Ok(())
|
|
} else {
|
|
// TODO: ignore "There are no Domain Name Servers (DNS) configured on this computer."
|
|
// Is this string localized?
|
|
Err(stdout_str)
|
|
}
|
|
} else {
|
|
Err(String::from("Could not parse netsh output"))
|
|
}
|
|
}
|
|
Err(_) => Err(String::from("Failed to execute command")),
|
|
}
|
|
}
|
|
|
|
pub fn add_dns_ipv4(if_index: u32, dnses: &[Ipv4Addr]) -> Result<(), String> {
|
|
flush_dns(AF_INET as _, if_index)?;
|
|
if dnses.is_empty() {
|
|
return Ok(());
|
|
}
|
|
let dnses_str: Vec<String> = dnses.iter().map(|addr| addr.to_string()).collect();
|
|
add_dns(AF_INET as _, if_index, &dnses_str)
|
|
}
|
|
|
|
pub fn add_dns_ipv6(if_index: u32, dnses: &[Ipv6Addr]) -> Result<(), String> {
|
|
flush_dns(AF_INET6 as _, if_index)?;
|
|
if dnses.is_empty() {
|
|
return Ok(());
|
|
}
|
|
let dnses_str: Vec<String> = dnses.iter().map(|addr| addr.to_string()).collect();
|
|
add_dns(AF_INET6 as _, if_index, &dnses_str)
|
|
}
|