]>
Commit | Line | Data |
---|---|---|
2eefd9ae DM |
1 | use std::path::Path; |
2 | use std::process::Command; | |
f34d4401 | 3 | use std::collections::HashMap; |
1ec7f8a0 DM |
4 | |
5 | use anyhow::{Error, bail, format_err}; | |
f34d4401 | 6 | use lazy_static::lazy_static; |
1ec7f8a0 DM |
7 | use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; |
8 | use nix::ioctl_read_bad; | |
9 | use regex::Regex; | |
f34d4401 | 10 | |
8b57cd44 DM |
11 | use proxmox::*; // for IP macros |
12 | ||
f34d4401 DM |
13 | pub 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 | ||
49 | lazy_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 |
59 | pub 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 |
97 | pub 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 | |
142 | pub 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 | ||
158 | pub 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 | ||
166 | pub 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 | } |