burrow/tun/build.rs
2023-12-17 19:53:20 -08:00

146 lines
4.4 KiB
Rust

#[cfg(not(windows))]
fn main() {
println!("cargo:rerun-if-changed=build.rs");
}
#[cfg(windows)]
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
let out_dir = std::env::var("OUT_DIR")?;
let path = std::path::PathBuf::from(out_dir);
generate(&path).await?;
println!("cargo:rerun-if-changed=build.rs");
Ok(())
}
#[cfg(windows)]
async fn generate(out_dir: &std::path::Path) -> anyhow::Result<()> {
use std::{fs::File, io::Write};
use anyhow::Context;
let bindings_path = out_dir.join("wintun.rs");
let binary_path = out_dir.join("wintun.dll");
println!("cargo:rerun-if-changed={}", bindings_path.to_str().unwrap());
println!("cargo:rerun-if-changed={}", binary_path.to_str().unwrap());
if let (Ok(..), Ok(..)) = (File::open(&bindings_path), File::open(&binary_path)) {
return Ok(())
};
let archive = download(out_dir)
.await
.context("Failed to download wintun")?;
let (bindings, binary) = parse(archive).context("Failed to parse wintun archive")?;
bindings
.write_to_file(bindings_path)
.context("Failed to write bindings")?;
let mut file = std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(binary_path)
.context("Failed to write binary")?;
file.write_all(&binary)?;
Ok(())
}
#[cfg(windows)]
async fn download(directory: &std::path::Path) -> anyhow::Result<std::fs::File> {
use std::{io::Write, str::FromStr};
let path = directory.join(WINTUN_FILENAME);
let mut file = match std::fs::OpenOptions::new().read(true).open(&path) {
Ok(existing) => return Ok(existing),
Err(_e) => std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)?,
};
let mut url = reqwest::Url::from_str("https://www.wintun.net/builds")?;
url.path_segments_mut().unwrap().push(WINTUN_FILENAME);
let body = reqwest::get(url).await?.bytes().await?;
ssri::IntegrityChecker::new(WINTUN_INTEGRITY.parse()?)
.chain(&body)
.result()?;
file.set_len(0)?;
file.write_all(&body)?;
Ok(file)
}
#[cfg(windows)]
fn parse(file: std::fs::File) -> anyhow::Result<(bindgen::Bindings, Vec<u8>)> {
use std::io::Read;
use anyhow::Context;
let reader = std::io::BufReader::new(file);
let mut archive = zip::ZipArchive::new(reader)?;
let mut header = String::new();
archive
.by_name("wintun/include/wintun.h")?
.read_to_string(&mut header)?;
header.push_str(WINTUN_BINDINGS_PREAMBLE);
let bindings = bindgen::Builder::default()
.header_contents("wintun.h", &header)
.allowlist_function("Wintun.*")
.allowlist_type("WINTUN_.*")
.dynamic_library_name("wintun")
.dynamic_link_require_all(true)
.generate()
.context("Failed to generate bindings from wintun archive")
.unwrap();
let mut binary = Vec::new();
let target = std::env::var("TARGET")?;
let arch = match target.split('-').next() {
Some("i686") => "x86",
Some("x86_64") => "amd64",
Some("aarch64") => "arm64",
Some("thumbv7a") => "arm",
Some(a) => panic!("{} is not a supported architecture", a),
None => unreachable!(),
};
archive
.by_name(&format!("wintun/bin/{}/wintun.dll", arch))?
.read_to_end(&mut binary)
.context("Failed to read binary from wintun archive")?;
Ok((bindings, binary))
}
#[cfg(windows)]
const WINTUN_FILENAME: &str = "wintun-0.14.1.zip";
#[cfg(windows)]
const WINTUN_INTEGRITY: &str = "sha256-B8JWGF1u42UuCfpVwLZz4mJLVl4CxLkJHHnKfS8k71E=";
#[cfg(windows)]
const WINTUN_BINDINGS_PREAMBLE: &str = r#"
WINTUN_CLOSE_ADAPTER_FUNC WintunCloseAdapter;
WINTUN_OPEN_ADAPTER_FUNC WintunOpenAdapter;
WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID;
WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC WintunGetRunningDriverVersion;
WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver;
WINTUN_SET_LOGGER_FUNC WintunSetLogger;
WINTUN_START_SESSION_FUNC WintunStartSession;
WINTUN_END_SESSION_FUNC WintunEndSession;
WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent;
WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket;
WINTUN_RELEASE_RECEIVE_PACKET_FUNC WintunReleaseReceivePacket;
WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket;
WINTUN_SEND_PACKET_FUNC WintunSendPacket;
"#;