// Changes IP address with given interface (takes interface's current IP and randomly chooses ip // from it) use ipnet::Ipv4Net; use iprange::IpNet; use rand::{self, Rng}; use std::net::Ipv4Addr; use std::process::{Command, Stdio}; // TODO clean up the unwraps pub fn check(iface: &String) -> Result<(), Box> { // Check we have ip, grep, awk let which_chk = Command::new("which") // Check if which exists .arg("awk") .output()?; if std::str::from_utf8(&which_chk.stdout).expect("Not valid UTF8 output :(") == "" { return Err("The awk binary does not exsist!".into()); } let arp_chk = Command::new("which") // Check if which exists .arg("arp") .output()?; if std::str::from_utf8(&arp_chk.stdout).expect("Not valid UTF8 output :(") == "" { return Err("The arp binary does not exsist!".into()); } let ip_chk = Command::new("which") // Check if which exists .arg("ip") .output()?; if std::str::from_utf8(&ip_chk.stdout).expect("Not valid UTF8 output :(") == "" { return Err("The ip binary does not exsist!".into()); } let grep_chk = Command::new("which") // Check if which exists .arg("grep") .output()?; if std::str::from_utf8(&grep_chk.stdout).expect("Not valid UTF8 output :(") == "" { return Err("The grep binary does not exsist!".into()); } // Check interface let ip_child = Command::new("ip") // `ps` command... .arg("a") // with argument `axww`... .stdout(Stdio::piped()) // of which we will pipe the output. .spawn()?; // Once configured, we actually spawn the command... and assert everything went right. let grep_child_one = Command::new("grep") .arg(&iface) .stdin(Stdio::from(ip_child.stdout.unwrap())) // Pipe through. .stdout(Stdio::piped()) .spawn()?; let output = grep_child_one.wait_with_output().unwrap(); let int_chk = std::str::from_utf8(&output.stdout).unwrap(); if int_chk == "" { return Err("The given interface does not exsist!".into()); } Ok(()) } // Changes IP address of given interface pub fn change(iface: &String,network: &String) -> Result<(), Box> { // Change interface with ip commands // Get current subnet // ip a | grep docker0 | awk '/inet / { print $2 }' // Make sure `ip`,`grep`,`awk` exsist first!!!! let ip_child = Command::new("ip") // `ps` command... .arg("a") // with argument `axww`... .stdout(Stdio::piped()) // of which we will pipe the output. .spawn()?; // Once configured, we actually spawn the command... and assert everything went right. let grep_child_one = Command::new("grep") .arg(&iface) .stdin(Stdio::from(ip_child.stdout.unwrap())) // Pipe through. .stdout(Stdio::piped()) .spawn()?; let grep_child_two = Command::new("awk").arg("/inet / { print $2 }").stdin(Stdio::from(grep_child_one.stdout.unwrap())).stdout(Stdio::piped()).spawn()?; let output = grep_child_two.wait_with_output().unwrap(); let mut cidr = std::str::from_utf8(&output.stdout).unwrap().replace("\n", ""); if cidr == "" { if network == "" { return Err("Interface has no assigned IP address or it doesn't exsist!\n Try using the `-net` flag and tell it what network to use, I'm not sure why this breaks...".into()); } else { // INSTEAD of breaking here, lets pull one from the user cidr = network.to_string(); } } let m: Vec<_> = cidr.split("/").collect(); if m.len() != 2 { return Err(format!("Please use the format '192.168.1.0/24' for example.\nFound : {:?}", m).into()); } let a_net: Ipv4Net = cidr.replace("\n", "").parse().unwrap(); let mut rng = rand::thread_rng(); let mut ip: Ipv4Addr; loop { ip = a_net .prefix_bits() .enumerate() .map(|(i, b)| (i as u8, b)) .chain((a_net.prefix_len()..32).map(|i| (i, rng.gen::()))) .filter(|(_, b)| *b) .map(|(i, _)| 2_u32.pow((31 - i) as u32)) .fold(0_u32, |prev, i| prev + i) .into(); // Courtesy of zwerdlds (thank you!!!) println!("Trying randomized ip -> {}", &ip); // ENSURE IP IS FREE AND NOT RESERVERD BROADCAST OR ANYTHING ELSE // ARP ping instead of ICMP!!! let arp_child = Command::new("arp").arg(format!("{}", &ip)).stdout(Stdio::piped()).spawn()?; let grep_arr = format!("incomplete\\|no entry"); let grep_arp = Command::new("grep") .arg(&grep_arr) .stdin(Stdio::from(arp_child.stdout.unwrap())) // Pipe through. .stdout(Stdio::piped()) .spawn()?; let output = grep_arp.wait_with_output().unwrap(); let arp_out = std::str::from_utf8(&output.stdout).unwrap().replace("\n", ""); let last_ip: Ipv4Addr = m[0].parse().unwrap(); if ip != last_ip // if we somehow landed on the same ip address as ours && arp_out != "" // if grep did not find incomplete (the ip is not taken) && ip.octets()[3] != 0 && ip.octets()[3] != 255 && ip.is_loopback() == false && ip.is_link_local() == false && ip.is_reserved() == false && ip.is_broadcast() == false && ip.is_multicast() == false && ip.is_private() == true { break; } } let ip = format!("{:?}", ip) + "/" + m[1]; // ip addr add 172.17.0.69/16 dev docker0 let cc = format!("{}", &ip.replace("\n", "")); let add_ip = Command::new("ip") // Check if which exists .args(["addr", "add", &cc, "dev", &iface]) .output()?; if std::str::from_utf8(&add_ip.stderr)? == "RTNETLINK answers: Operation not permitted\n" { return Err("Run the program with sudo or as root so the ip can change!".into()); } // ip addr del 172.17.0.1/16 dev docker0 let add_ip = Command::new("ip") // Check if which exists .args(["addr", "del", &cidr, "dev", &iface]) .output()?; if std::str::from_utf8(&add_ip.stderr)? == "RTNETLINK answers: Operation not permitted\n" { return Err("Run the program with sudo or as root so the ip can change!".into()); } // ip addr add broadcast 172.17.0.255 dev docker0 let brd: Ipv4Addr = a_net .prefix_bits() .enumerate() .map(|(i, b)| (i as u8, b)) .chain((a_net.prefix_len()..32).map(|i| (i, true))) .filter(|(_, b)| *b) .map(|(i, _)| 2_u32.pow((31 - i) as u32)) .fold(0_u32, |prev, i| prev + i) .into(); // Courtesy of zwerdlds (thank you!!!) println!("Generated broadcast address : {brd}"); let brd: String = format!("{}", brd); let add_ip = Command::new("ip") // Check if which exists .args(["addr", "del", &brd, "dev", &iface]) .output()?; if std::str::from_utf8(&add_ip.stderr)? == "RTNETLINK answers: Operation not permitted\n" { return Err("Run the program with sudo or as root so the ip can change!".into()); } println!("IP address for {iface} is now {}", ip); Ok(()) }