1use crate::{
2 builder::{DeviceConfig, Layer},
3 platform::netbsd::sys::*,
4 platform::{
5 unix::{sockaddr_union, Fd, Tun},
6 ETHER_ADDR_LEN,
7 },
8 ToIpv4Address, ToIpv4Netmask, ToIpv6Address, ToIpv6Netmask,
9};
10
11use crate::platform::unix::device::{ctl, ctl_v6};
12use libc::{self, c_char, c_short, AF_LINK, IFF_RUNNING, IFF_UP, IFNAMSIZ, O_RDWR};
13use nix::sys::socket::{LinkAddr, SockaddrLike};
14use std::io::ErrorKind;
15use std::os::fd::{FromRawFd, IntoRawFd, RawFd};
16use std::os::unix::fs::MetadataExt;
17use std::{io, mem, net::IpAddr, os::unix::io::AsRawFd, ptr, sync::Mutex};
18
19pub struct DeviceImpl {
21 name: String,
22 pub(crate) tun: Tun,
23 pub(crate) op_lock: Mutex<bool>,
24}
25impl IntoRawFd for DeviceImpl {
26 fn into_raw_fd(mut self) -> RawFd {
27 let fd = self.tun.fd.inner;
28 self.tun.fd.inner = -1;
29 fd
30 }
31}
32impl Drop for DeviceImpl {
33 fn drop(&mut self) {
34 if self.tun.fd.inner < 0 {
35 return;
36 }
37 unsafe {
38 if let (Ok(ctl), Ok(req)) = (ctl(), self.request()) {
39 libc::close(self.tun.fd.inner);
40 self.tun.fd.inner = -1;
41 _ = siocifdestroy(ctl.as_raw_fd(), &req);
42 }
43 }
44 }
45}
46impl DeviceImpl {
47 pub(crate) fn new(config: DeviceConfig) -> io::Result<Self> {
49 let layer = config.layer.unwrap_or(Layer::L3);
50 let associate_route = if layer == Layer::L3 {
51 config.associate_route.unwrap_or(true)
52 } else {
53 false
54 };
55 if let Some(dev_name) = config.dev_name.as_ref() {
56 Self::check_name(layer, dev_name)?;
57 if !config.reuse_dev.unwrap_or(true) {
58 let exists = Self::exists(dev_name)?;
59 if exists {
60 return Err(io::Error::new(
61 ErrorKind::AlreadyExists,
62 format!("device {dev_name} already exists"),
63 ));
64 }
65 }
66 }
67 let (dev_fd, name) = match layer {
68 Layer::L2 => Self::create_tap(config.dev_name)?,
69 Layer::L3 => Self::create_tun(config.dev_name)?,
70 };
71
72 let tun = Tun::new(dev_fd);
73 if matches!(layer, Layer::L3) {
74 Self::enable_tunsifhead_impl(&tun.fd)?;
75 tun.set_ignore_packet_info(!config.packet_information.unwrap_or(false));
76 }
77 Ok(DeviceImpl {
78 name,
79 tun,
80 op_lock: Mutex::new(associate_route),
81 })
82 }
83 fn check_name(layer: Layer, dev_name: &str) -> io::Result<()> {
84 if dev_name.len() > IFNAMSIZ {
85 return Err(io::Error::new(
86 ErrorKind::InvalidInput,
87 "device name too long",
88 ));
89 }
90 let device_prefix = match layer {
91 Layer::L2 => "tap",
92 Layer::L3 => "tun",
93 };
94 if !dev_name.starts_with(device_prefix) {
95 Err(io::Error::new(
96 ErrorKind::InvalidInput,
97 format!("device name must start with {device_prefix}"),
98 ))
99 } else {
100 Ok(())
101 }
102 }
103 fn create_tap(dev_name: Option<String>) -> io::Result<(Fd, String)> {
104 let device_prefix = "tap";
105 if let Some(dev_name) = dev_name {
106 if let Err(e) = DeviceImpl::create_dev(&dev_name) {
107 if e.kind() != ErrorKind::AlreadyExists {
108 return Err(e);
109 }
110 }
111
112 let if_index = dev_name[3..]
113 .parse::<u32>()
114 .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
115 let device_path = format!("/dev/{device_prefix}{if_index}\0");
116
117 let fd = Self::open_and_makedev_dev(&dev_name, &device_path)?;
118 Ok((fd, dev_name))
119 } else {
120 let device_path = format!("/dev/{device_prefix}\0");
121 let fd =
122 unsafe { libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC) };
123 let fd = Fd::new(fd)?;
124 unsafe {
125 let mut req: ifreq = mem::zeroed();
126 if let Err(err) = tapgifname(fd.as_raw_fd(), &mut req) {
127 return Err(io::Error::from(err));
128 }
129 let cstr = std::ffi::CStr::from_ptr(req.ifr_name.as_ptr());
130 let dev_name = cstr.to_string_lossy().to_string();
131 Ok((fd, dev_name))
132 }
133 }
134 }
135 fn create_tun(dev_name: Option<String>) -> io::Result<(Fd, String)> {
136 let device_prefix = "tun";
137 if let Some(dev_name) = dev_name {
138 let if_index = dev_name[3..]
139 .parse::<u32>()
140 .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
141 let device_path = format!("/dev/{device_prefix}{if_index}\0");
142 let fd = Self::open_and_makedev_dev(&dev_name, &device_path)?;
143 Ok((fd, dev_name))
144 } else {
145 for index in 0..256 {
146 let dev_name = format!("{device_prefix}{index}");
147 let device_path = format!("/dev/{device_prefix}{index}\0");
148
149 match Self::open_and_makedev_dev(&dev_name, &device_path) {
150 Ok(dev) => {
151 return Ok((dev, dev_name));
152 }
153 Err(e) => {
154 if e.raw_os_error() != Some(libc::EBUSY) {
155 return Err(e);
156 }
157 }
158 }
159 }
160 Err(io::Error::last_os_error())
161 }
162 }
163 fn open_and_makedev_dev(dev_name: &str, device_path: &str) -> io::Result<Fd> {
164 let fd = unsafe { libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC) };
165 match Fd::new(fd) {
166 Ok(fd) => Ok(fd),
167 Err(ref e) if e.kind() == ErrorKind::NotFound => {
168 DeviceImpl::makedev_dev(dev_name)?;
169 let fd = unsafe {
170 libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC)
171 };
172 Ok(Fd::new(fd)?)
173 }
174 Err(e) => Err(e),
175 }
176 }
177 fn makedev_dev(name: &str) -> io::Result<()> {
178 let status = std::process::Command::new("sh")
179 .arg("MAKEDEV")
180 .arg(name)
181 .current_dir("/dev")
182 .status()?;
183
184 if status.success() {
185 Ok(())
186 } else {
187 Err(io::Error::other(format!(
188 "MAKEDEV {} failed with status {:?}",
189 name,
190 status.code()
191 )))
192 }
193 }
194 fn create_dev(name: &str) -> io::Result<()> {
195 unsafe {
196 let mut req: ifreq = mem::zeroed();
197 ptr::copy_nonoverlapping(
198 name.as_ptr() as *const c_char,
199 req.ifr_name.as_mut_ptr(),
200 name.len(),
201 );
202 if let Err(err) = siocifcreate(ctl()?.as_raw_fd(), &req) {
203 return Err(io::Error::from(err));
204 }
205 }
206 Ok(())
207 }
208 fn exists(dev_name: &str) -> io::Result<bool> {
209 unsafe {
210 let mut req: ifreq = mem::zeroed();
211 ptr::copy_nonoverlapping(
212 dev_name.as_ptr() as *const c_char,
213 req.ifr_name.as_mut_ptr(),
214 dev_name.len(),
215 );
216 let ctl = ctl()?;
217 if let Err(err) = siocgifflags(ctl.as_raw_fd(), &mut req) {
218 if err == nix::errno::Errno::ENXIO {
219 return Ok(false);
220 }
221 Err(io::Error::from(err))
222 } else {
223 Ok(true)
224 }
225 }
226 }
227 pub(crate) fn from_tun(tun: Tun) -> io::Result<Self> {
228 let name = Self::name_of_fd(tun.as_raw_fd())?;
229 Ok(Self {
230 name,
231 tun,
232 op_lock: Mutex::new(true),
233 })
234 }
235
236 fn enable_tunsifhead_impl(device_fd: &Fd) -> std::io::Result<()> {
237 unsafe {
238 if let Err(err) = sioctunsifhead(device_fd.as_raw_fd(), &1 as *const _) {
239 return Err(io::Error::from(err));
240 }
241 }
242 Ok(())
243 }
244
245 fn calc_dest_addr(&self, addr: IpAddr, netmask: IpAddr) -> io::Result<IpAddr> {
246 let prefix_len = ipnet::ip_mask_to_prefix(netmask)
247 .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
248 Ok(ipnet::IpNet::new(addr, prefix_len)
249 .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?
250 .broadcast())
251 }
252
253 fn add_address(
255 &self,
256 addr: IpAddr,
257 mask: IpAddr,
258 dest: Option<IpAddr>,
259 associate_route: bool,
260 ) -> io::Result<()> {
261 unsafe {
262 match (addr, mask) {
263 (IpAddr::V4(addr), IpAddr::V4(mask)) => {
264 let ctl = ctl()?;
265 let mut req: ifaliasreq = mem::zeroed();
266 let tun_name = self.name_impl()?;
267 ptr::copy_nonoverlapping(
268 tun_name.as_ptr() as *const c_char,
269 req.ifra_name.as_mut_ptr(),
270 tun_name.len(),
271 );
272
273 req.ifra_addr = crate::platform::unix::sockaddr_union::from((addr, 0)).addr;
274 if let Some(dest) = dest {
275 req.ifra_dstaddr =
276 crate::platform::unix::sockaddr_union::from((dest, 0)).addr;
277 }
278 req.ifra_mask = crate::platform::unix::sockaddr_union::from((mask, 0)).addr;
279
280 if let Err(err) = siocaifaddr(ctl.as_raw_fd(), &req) {
281 return Err(io::Error::from(err));
282 }
283 if let Err(e) = self.add_route(addr.into(), mask.into(), associate_route) {
284 log::warn!("{e:?}");
285 }
286 }
287 (IpAddr::V6(addr), IpAddr::V6(mask)) => {
288 let tun_name = self.name_impl()?;
289 let mut req: in6_aliasreq = mem::zeroed();
290 ptr::copy_nonoverlapping(
291 tun_name.as_ptr() as *const c_char,
292 req.ifra_name.as_mut_ptr(),
293 tun_name.len(),
294 );
295 req.ifra_addr = sockaddr_union::from((addr, 0)).addr6;
296 req.ifra_prefixmask = sockaddr_union::from((mask, 0)).addr6;
297 req.ifra_lifetime.ia6t_vltime = 0xffffffff_u32;
298 req.ifra_lifetime.ia6t_pltime = 0xffffffff_u32;
299 if let Err(err) = siocaifaddr_in6(ctl_v6()?.as_raw_fd(), &req) {
301 return Err(io::Error::from(err));
302 }
303 }
304 _ => {
305 unreachable!();
306 }
307 }
308 Ok(())
309 }
310 }
311
312 unsafe fn request(&self) -> io::Result<ifreq> {
314 let mut req: ifreq = mem::zeroed();
315 let tun_name = self.name_impl()?;
316 ptr::copy_nonoverlapping(
317 tun_name.as_ptr() as *const c_char,
318 req.ifr_name.as_mut_ptr(),
319 tun_name.len(),
320 );
321
322 Ok(req)
323 }
324
325 unsafe fn request_v6(&self) -> io::Result<in6_ifreq> {
327 let tun_name = self.name_impl()?;
328 let mut req: in6_ifreq = mem::zeroed();
329 ptr::copy_nonoverlapping(
330 tun_name.as_ptr() as *const c_char,
331 req.ifra_name.as_mut_ptr(),
332 tun_name.len(),
333 );
334 req.ifr_ifru.ifru_flags = IN6_IFF_NODAD as _;
335 Ok(req)
336 }
337
338 fn add_route(&self, addr: IpAddr, netmask: IpAddr, associate_route: bool) -> io::Result<()> {
339 if !associate_route {
340 return Ok(());
341 }
342 let if_index = self.if_index_impl()?;
343 let prefix_len = ipnet::ip_mask_to_prefix(netmask)
344 .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
345 let mut manager = route_manager::RouteManager::new()?;
346 let route = route_manager::Route::new(addr, prefix_len).with_if_index(if_index);
347 manager.add(&route)?;
348 Ok(())
349 }
350
351 pub(crate) fn name_impl(&self) -> io::Result<String> {
353 Ok(self.name.clone())
354 }
355 fn name_of_fd(tun: RawFd) -> io::Result<String> {
356 unsafe {
357 let mut req: ifreq = mem::zeroed();
358 if tapgifname(tun, &mut req).is_ok() {
359 let cstr = std::ffi::CStr::from_ptr(req.ifr_name.as_ptr());
360 let dev_name = cstr.to_string_lossy().to_string();
361 return Ok(dev_name);
363 }
364 }
365 let file = unsafe { std::fs::File::from_raw_fd(tun) };
366 let metadata = file.metadata()?;
367 let rdev = metadata.rdev();
368 let index = rdev % 256;
369 std::mem::forget(file); Ok(format!("tun{index}"))
371 }
372
373 fn remove_all_address_v4(&self) -> io::Result<()> {
374 unsafe {
375 let req_v4 = self.request()?;
376 loop {
377 if let Err(err) = siocdifaddr(ctl()?.as_raw_fd(), &req_v4) {
378 if err == nix::errno::Errno::EADDRNOTAVAIL {
379 break;
380 }
381 return Err(io::Error::from(err));
382 }
383 }
384 }
385 Ok(())
386 }
387}
388
389impl DeviceImpl {
391 pub fn name(&self) -> io::Result<String> {
393 let _guard = self.op_lock.lock().unwrap();
394 self.name_impl()
395 }
396 pub fn set_associate_route(&self, associate_route: bool) {
400 *self.op_lock.lock().unwrap() = associate_route;
401 }
402 pub fn associate_route(&self) -> bool {
404 *self.op_lock.lock().unwrap()
405 }
406 pub fn enabled(&self, value: bool) -> io::Result<()> {
408 let _guard = self.op_lock.lock().unwrap();
409 unsafe {
410 let mut req = self.request()?;
411 let ctl = ctl()?;
412
413 if let Err(err) = siocgifflags(ctl.as_raw_fd(), &mut req) {
414 return Err(io::Error::from(err));
415 }
416
417 if value {
418 req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
419 } else {
420 req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
421 }
422
423 if let Err(err) = siocsifflags(ctl.as_raw_fd(), &req) {
424 return Err(io::Error::from(err));
425 }
426
427 Ok(())
428 }
429 }
430 pub fn mtu(&self) -> io::Result<u16> {
432 let _guard = self.op_lock.lock().unwrap();
433 unsafe {
434 let mut req: ifreq = mem::zeroed();
435 let tun_name = self.name_impl()?;
436 ptr::copy_nonoverlapping(
437 tun_name.as_ptr() as *const c_char,
438 req.ifr_name.as_mut_ptr(),
439 tun_name.len(),
440 );
441 if let Err(err) = siocgifmtu(ctl()?.as_raw_fd(), &mut req) {
442 return Err(io::Error::from(err));
443 }
444
445 let r: u16 = req.ifr_ifru.ifru_mtu.try_into().map_err(io::Error::other)?;
446 Ok(r)
447 }
448 }
449 pub fn set_mtu(&self, value: u16) -> io::Result<()> {
453 let _guard = self.op_lock.lock().unwrap();
454 unsafe {
455 let mut req: ifreq = mem::zeroed();
456 let tun_name = self.name_impl()?;
457 ptr::copy_nonoverlapping(
458 tun_name.as_ptr() as *const c_char,
459 req.ifr_name.as_mut_ptr(),
460 tun_name.len(),
461 );
462 req.ifr_ifru.ifru_mtu = value as _;
463
464 if let Err(err) = siocsifmtu(ctl()?.as_raw_fd(), &req) {
465 return Err(io::Error::from(err));
466 }
467 Ok(())
468 }
469 }
470 pub fn set_network_address<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
473 &self,
474 address: IPv4,
475 netmask: Netmask,
476 destination: Option<IPv4>,
477 ) -> io::Result<()> {
478 let guard = self.op_lock.lock().unwrap();
479 let addr = address.ipv4()?.into();
480 let netmask = netmask.netmask()?.into();
481 let default_dest = self.calc_dest_addr(addr, netmask)?;
482 let dest = destination
483 .map(|d| d.ipv4())
484 .transpose()?
485 .map(|v| v.into())
486 .unwrap_or(default_dest);
487 self.remove_all_address_v4()?;
488 self.add_address(addr, netmask, Some(dest), *guard)?;
489 Ok(())
490 }
491 pub fn add_address_v4<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
493 &self,
494 address: IPv4,
495 netmask: Netmask,
496 ) -> io::Result<()> {
497 let guard = self.op_lock.lock().unwrap();
498 let addr = address.ipv4()?.into();
499 let netmask = netmask.netmask()?.into();
500 let dest = self.calc_dest_addr(addr, netmask)?;
501 self.add_address(addr, netmask, Some(dest), *guard)?;
502 Ok(())
503 }
504 pub fn remove_address(&self, addr: IpAddr) -> io::Result<()> {
506 let _guard = self.op_lock.lock().unwrap();
507 unsafe {
508 match addr {
509 IpAddr::V4(addr) => {
510 let mut req_v4 = self.request()?;
511 req_v4.ifr_ifru.ifru_addr = sockaddr_union::from((addr, 0)).addr;
512 if let Err(err) = siocdifaddr(ctl()?.as_raw_fd(), &req_v4) {
513 return Err(io::Error::from(err));
514 }
515 }
516 IpAddr::V6(addr) => {
517 let mut req_v6 = self.request_v6()?;
518 req_v6.ifr_ifru.ifru_addr = sockaddr_union::from((addr, 0)).addr6;
519 if let Err(err) = siocdifaddr_in6(ctl_v6()?.as_raw_fd(), &req_v6) {
520 return Err(io::Error::from(err));
521 }
522 }
523 }
524 Ok(())
525 }
526 }
527 pub fn add_address_v6<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
529 &self,
530 addr: IPv6,
531 netmask: Netmask,
532 ) -> io::Result<()> {
533 let guard = self.op_lock.lock().unwrap();
534 let addr = addr.ipv6()?;
535 let netmask = netmask.netmask()?;
536 self.add_address(addr.into(), netmask.into(), None, *guard)
537 }
538 pub fn set_mac_address(&self, eth_addr: [u8; ETHER_ADDR_LEN as usize]) -> io::Result<()> {
544 let _guard = self.op_lock.lock().unwrap();
545 unsafe {
546 let mut req: ifaliasreq = mem::zeroed();
547 let tun_name = self.name_impl()?;
548 ptr::copy_nonoverlapping(
549 tun_name.as_ptr() as *const c_char,
550 req.ifra_name.as_mut_ptr(),
551 tun_name.len(),
552 );
553 req.ifra_addr.sa_len = ETHER_ADDR_LEN;
554 req.ifra_addr.sa_family = AF_LINK as u8;
555 req.ifra_addr.sa_data[0..ETHER_ADDR_LEN as usize]
556 .copy_from_slice(eth_addr.map(|c| c as i8).as_slice());
557 if let Err(err) = siocsifphyaddr(ctl()?.as_raw_fd(), &req) {
558 return Err(io::Error::from(err));
559 }
560 Ok(())
561 }
562 }
563 pub fn mac_address(&self) -> io::Result<[u8; ETHER_ADDR_LEN as usize]> {
568 let _guard = self.op_lock.lock().unwrap();
569 let name = self.name_impl()?;
570 let interfaces = nix::ifaddrs::getifaddrs()?;
571 let interfaces = interfaces.filter(|item| item.interface_name == name);
572 for addr in interfaces {
573 if let Some(address) = addr.address {
574 if address.family() == Some(nix::sys::socket::AddressFamily::Link) {
575 unsafe {
580 let link_ptr = &address as *const _ as *const LinkAddr;
581 if let Some(mac) = (*link_ptr).addr() {
582 return Ok(mac);
583 }
584 }
585 }
586 }
587 }
588 Err(std::io::Error::other("Unable to get Mac address"))
589 }
590 pub fn enable_tunsifhead(&self) -> io::Result<()> {
594 let _guard = self.op_lock.lock().unwrap();
595 Self::enable_tunsifhead_impl(&self.tun.fd)
596 }
597
598 pub fn ignore_packet_info(&self) -> bool {
607 let _guard = self.op_lock.lock().unwrap();
608 self.tun.ignore_packet_info()
609 }
610 pub fn set_ignore_packet_info(&self, ign: bool) {
621 let _guard = self.op_lock.lock().unwrap();
622 if let Ok(name) = self.name_impl() {
623 if name.starts_with("tun") {
624 self.tun.set_ignore_packet_info(ign)
625 }
626 }
627 }
628}
629
630impl From<Layer> for c_short {
631 fn from(layer: Layer) -> Self {
632 match layer {
633 Layer::L2 => 2,
634 Layer::L3 => 3,
635 }
636 }
637}