🛂 Check for required permissions

On Linux, checks for the `CAP_NET_ADMIN` capability.
On macOS, checks for root.
This commit is contained in:
Malted 2023-06-10 17:25:08 +01:00 committed by Ben
parent 6bd8051c78
commit 40cc0ba049
7 changed files with 60 additions and 5 deletions

12
Cargo.lock generated
View file

@ -141,7 +141,9 @@ checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
name = "burrow" name = "burrow"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"caps",
"clap", "clap",
"nix",
"tokio", "tokio",
"tun", "tun",
] ]
@ -179,6 +181,16 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "caps"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b"
dependencies = [
"libc",
"thiserror",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.0.79"

View file

@ -10,3 +10,9 @@ crate-type = ["lib", "staticlib"]
tokio = { version = "1.21", features = ["rt", "macros"] } tokio = { version = "1.21", features = ["rt", "macros"] }
tun = { version = "0.1", path = "../tun" } tun = { version = "0.1", path = "../tun" }
clap = { version = "4.3.2", features = ["derive"] } clap = { version = "4.3.2", features = ["derive"] }
[target.'cfg(target_os = "linux")'.dependencies]
caps = "0.5.5"
[target.'cfg(target_os = "macos")'.dependencies]
nix = { version = "0.26.2" }

35
burrow/src/ensureroot.rs Normal file
View file

@ -0,0 +1,35 @@
// Check capabilities on Linux
#[cfg(target_os = "linux")]
pub fn ensure_root() {
use caps::{has_cap, CapSet, Capability};
let cap_net_admin = Capability::CAP_NET_ADMIN;
if let Ok(has_cap) = has_cap(None, CapSet::Effective, cap_net_admin) {
if !has_cap {
eprintln!(
"This action needs the CAP_NET_ADMIN permission. Did you mean to run it as root?"
);
std::process::exit(77);
}
} else {
eprintln!("Failed to check capabilities. Please file a bug report!");
std::process::exit(71);
}
}
// Check for root user on macOS
#[cfg(target_os = "macos")]
pub fn ensure_root() {
use nix::unistd::Uid;
let current_uid = Uid::current();
if !current_uid.is_root() {
eprintln!("This action must be run as root!");
std::process::exit(77);
}
}
#[cfg(target_family = "windows")]
pub fn ensure_root() {
todo!()
}

View file

@ -1,3 +1 @@
pub fn hello_world() { pub mod ensureroot;
println!("Hello, world!");
}

View file

@ -23,6 +23,8 @@ enum Commands {
struct StartArgs {} struct StartArgs {}
async fn try_main() -> Result<()> { async fn try_main() -> Result<()> {
burrow::ensureroot::ensure_root();
let iface = TunInterface::new()?; let iface = TunInterface::new()?;
println!("{:?}", iface.name()); println!("{:?}", iface.name());
@ -31,6 +33,8 @@ async fn try_main() -> Result<()> {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
println!("Platform: {}", std::env::consts::OS);
let cli = Cli::parse(); let cli = Cli::parse();
match &cli.command { match &cli.command {
Commands::Start(..) => { Commands::Start(..) => {

View file

@ -6,7 +6,7 @@ use std::io::{IoSlice, Write};
use std::net::{Ipv4Addr, SocketAddrV4}; use std::net::{Ipv4Addr, SocketAddrV4};
use std::os::fd::{AsRawFd, RawFd}; use std::os::fd::{AsRawFd, RawFd};
use std::{ use std::{
io::{Error, Read}, io::{Error},
mem, mem,
}; };

View file

@ -71,7 +71,7 @@ mod test {
use super::*; use super::*;
use std::io::Write; use std::io::Write;
use std::io::{self, BufRead};
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
#[throws] #[throws]