]> git.proxmox.com Git - proxmox-backup.git/blame - src/config/network/helper.rs
ui: add port support for remotes
[proxmox-backup.git] / src / config / network / helper.rs
CommitLineData
2eefd9ae
DM
1use std::path::Path;
2use std::process::Command;
f34d4401 3use std::collections::HashMap;
1ec7f8a0
DM
4
5use anyhow::{Error, bail, format_err};
f34d4401 6use lazy_static::lazy_static;
1ec7f8a0
DM
7use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
8use nix::ioctl_read_bad;
9use regex::Regex;
f34d4401 10
8b57cd44
DM
11use proxmox::*; // for IP macros
12
f34d4401
DM
13pub static IPV4_REVERSE_MASK: &[&'static str] = &[
14 "0.0.0.0",
15 "128.0.0.0",
16 "192.0.0.0",
17 "224.0.0.0",
18 "240.0.0.0",
19 "248.0.0.0",
20 "252.0.0.0",
21 "254.0.0.0",
22 "255.0.0.0",
23 "255.128.0.0",
24 "255.192.0.0",
25 "255.224.0.0",
26 "255.240.0.0",
27 "255.248.0.0",
28 "255.252.0.0",
29 "255.254.0.0",
30 "255.255.0.0",
31 "255.255.128.0",
32 "255.255.192.0",
33 "255.255.224.0",
34 "255.255.240.0",
35 "255.255.248.0",
36 "255.255.252.0",
37 "255.255.254.0",
38 "255.255.255.0",
39 "255.255.255.128",
40 "255.255.255.192",
41 "255.255.255.224",
42 "255.255.255.240",
43 "255.255.255.248",
44 "255.255.255.252",
45 "255.255.255.254",
46 "255.255.255.255",
47];
48
49lazy_static! {
50 pub static ref IPV4_MASK_HASH_LOCALNET: HashMap<&'static str, u8> = {
51 let mut map = HashMap::new();
52 for i in 8..32 {
53 map.insert(IPV4_REVERSE_MASK[i], i as u8);
54 }
55 map
56 };
57}
1ec7f8a0 58
8b57cd44
DM
59pub fn parse_cidr(cidr: &str) -> Result<(String, u8, bool), Error> {
60
61 lazy_static! {
62 pub static ref CIDR_V4_REGEX: Regex = Regex::new(
0c226bc1 63 concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))$")
8b57cd44
DM
64 ).unwrap();
65 pub static ref CIDR_V6_REGEX: Regex = Regex::new(
0c226bc1 66 concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,3}))$")
8b57cd44
DM
67 ).unwrap();
68 }
69
70 if let Some(caps) = CIDR_V4_REGEX.captures(&cidr) {
71 let address = &caps[1];
72 let mask = &caps[2];
73 let mask = u8::from_str_radix(mask, 10)
74 .map(|mask| {
75 if !(mask > 0 && mask <= 32) {
76 bail!("IPv4 mask '{}' is out of range (1..32).", mask);
77 }
78 Ok(mask)
79 })?;
80 return Ok((address.to_string(), mask.unwrap(), false));
81 } else if let Some(caps) = CIDR_V6_REGEX.captures(&cidr) {
82 let address = &caps[1];
83 let mask = &caps[2];
84 let mask = u8::from_str_radix(mask, 10)
85 .map(|mask| {
86 if !(mask >= 1 && mask <= 128) {
87 bail!("IPv6 mask '{}' is out of range (1..128).", mask);
88 }
89 Ok(mask)
90 })?;
91 return Ok((address.to_string(), mask.unwrap(), true));
92 } else {
93 bail!("invalid address/mask '{}'", cidr);
94 }
95}
96
1ec7f8a0
DM
97pub fn get_network_interfaces() -> Result<HashMap<String, bool>, Error> {
98
99 const PROC_NET_DEV: &str = "/proc/net/dev";
100
101 #[repr(C)]
102 pub struct ifreq {
103 ifr_name: [libc::c_uchar; libc::IFNAMSIZ],
104 ifru_flags: libc::c_short,
105 }
106
107 ioctl_read_bad!(get_interface_flags, libc::SIOCGIFFLAGS, ifreq);
108
109 lazy_static!{
110 static ref IFACE_LINE_REGEX: Regex = Regex::new(r"^\s*([^:\s]+):").unwrap();
111 }
112 let raw = std::fs::read_to_string(PROC_NET_DEV)
113 .map_err(|err| format_err!("unable to read {} - {}", PROC_NET_DEV, err))?;
114
115 let lines = raw.lines();
116
117 let sock = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None)
118 .or_else(|_| socket(AddressFamily::Inet6, SockType::Datagram, SockFlag::empty(), None))?;
119
120 let mut interface_list = HashMap::new();
121
122 for line in lines {
123 if let Some(cap) = IFACE_LINE_REGEX.captures(line) {
124 let ifname = &cap[1];
125
126 let mut req = ifreq { ifr_name: *b"0000000000000000", ifru_flags: 0 };
127 for (i, b) in std::ffi::CString::new(ifname)?.as_bytes_with_nul().iter().enumerate() {
128 if i < (libc::IFNAMSIZ-1) { req.ifr_name[i] = *b as libc::c_uchar; }
129 }
130 let res = unsafe { get_interface_flags(sock, &mut req)? };
131 if res != 0 {
132 bail!("ioctl get_interface_flags for '{}' failed ({})", ifname, res);
133 }
134 let is_up = (req.ifru_flags & (libc::IFF_UP as libc::c_short)) != 0;
135 interface_list.insert(ifname.to_string(), is_up);
136 }
137 }
138
139 Ok(interface_list)
140}
2eefd9ae
DM
141
142pub fn compute_file_diff(filename: &str, shadow: &str) -> Result<String, Error> {
143
cbef49bf 144 let output = Command::new("diff")
2eefd9ae
DM
145 .arg("-b")
146 .arg("-u")
147 .arg(filename)
148 .arg(shadow)
149 .output()
150 .map_err(|err| format_err!("failed to execute diff - {}", err))?;
151
143b6545 152 let diff = crate::tools::command_output(output, Some(|c| c == 0 || c == 1))
97fab7aa 153 .map_err(|err| format_err!("diff failed: {}", err))?;
2eefd9ae
DM
154
155 Ok(diff)
156}
157
158pub fn assert_ifupdown2_installed() -> Result<(), Error> {
159 if !Path::new("/usr/share/ifupdown2").exists() {
160 bail!("ifupdown2 is not installed.");
161 }
162
163 Ok(())
164}
165
166pub fn network_reload() -> Result<(), Error> {
167
cbef49bf 168 let output = Command::new("ifreload")
2eefd9ae 169 .arg("-a")
143b6545 170 .output()
cbef49bf 171 .map_err(|err| format_err!("failed to execute 'ifreload' - {}", err))?;
143b6545
DM
172
173 crate::tools::command_output(output, None)
174 .map_err(|err| format_err!("ifreload failed: {}", err))?;
2eefd9ae 175
2eefd9ae
DM
176
177 Ok(())
178}