tun_rs/platform/netbsd/
device.rs

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
19/// A TUN device using the TUN/TAP Linux driver.
20pub 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    /// Create a new `Device` for the given `Configuration`.
48    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        } else {
77            tun.set_ignore_packet_info(false);
78        }
79        Ok(DeviceImpl {
80            name,
81            tun,
82            op_lock: Mutex::new(associate_route),
83        })
84    }
85    fn check_name(layer: Layer, dev_name: &str) -> io::Result<()> {
86        if dev_name.len() > IFNAMSIZ {
87            return Err(io::Error::new(
88                ErrorKind::InvalidInput,
89                "device name too long",
90            ));
91        }
92        let device_prefix = match layer {
93            Layer::L2 => "tap",
94            Layer::L3 => "tun",
95        };
96        if !dev_name.starts_with(device_prefix) {
97            Err(io::Error::new(
98                ErrorKind::InvalidInput,
99                format!("device name must start with {device_prefix}"),
100            ))
101        } else {
102            Ok(())
103        }
104    }
105    fn create_tap(dev_name: Option<String>) -> io::Result<(Fd, String)> {
106        let device_prefix = "tap";
107        if let Some(dev_name) = dev_name {
108            if let Err(e) = DeviceImpl::create_dev(&dev_name) {
109                if e.kind() != ErrorKind::AlreadyExists {
110                    return Err(e);
111                }
112            }
113
114            let if_index = dev_name[3..]
115                .parse::<u32>()
116                .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
117            let device_path = format!("/dev/{device_prefix}{if_index}\0");
118
119            let fd = Self::open_and_makedev_dev(&dev_name, &device_path)?;
120            Ok((fd, dev_name))
121        } else {
122            let device_path = format!("/dev/{device_prefix}\0");
123            let fd =
124                unsafe { libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC) };
125            let fd = Fd::new(fd)?;
126            unsafe {
127                let mut req: ifreq = mem::zeroed();
128                if let Err(err) = tapgifname(fd.as_raw_fd(), &mut req) {
129                    return Err(io::Error::from(err));
130                }
131                let cstr = std::ffi::CStr::from_ptr(req.ifr_name.as_ptr());
132                let dev_name = cstr.to_string_lossy().to_string();
133                Ok((fd, dev_name))
134            }
135        }
136    }
137    fn create_tun(dev_name: Option<String>) -> io::Result<(Fd, String)> {
138        let device_prefix = "tun";
139        if let Some(dev_name) = dev_name {
140            let if_index = dev_name[3..]
141                .parse::<u32>()
142                .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
143            let device_path = format!("/dev/{device_prefix}{if_index}\0");
144            let fd = Self::open_and_makedev_dev(&dev_name, &device_path)?;
145            Ok((fd, dev_name))
146        } else {
147            for index in 0..256 {
148                let dev_name = format!("{device_prefix}{index}");
149                let device_path = format!("/dev/{device_prefix}{index}\0");
150
151                match Self::open_and_makedev_dev(&dev_name, &device_path) {
152                    Ok(dev) => {
153                        return Ok((dev, dev_name));
154                    }
155                    Err(e) => {
156                        if e.raw_os_error() != Some(libc::EBUSY) {
157                            return Err(e);
158                        }
159                    }
160                }
161            }
162            Err(io::Error::last_os_error())
163        }
164    }
165    fn open_and_makedev_dev(dev_name: &str, device_path: &str) -> io::Result<Fd> {
166        let fd = unsafe { libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC) };
167        match Fd::new(fd) {
168            Ok(fd) => Ok(fd),
169            Err(ref e) if e.kind() == ErrorKind::NotFound => {
170                DeviceImpl::makedev_dev(dev_name)?;
171                let fd = unsafe {
172                    libc::open(device_path.as_ptr() as *const _, O_RDWR | libc::O_CLOEXEC)
173                };
174                Ok(Fd::new(fd)?)
175            }
176            Err(e) => Err(e),
177        }
178    }
179    fn makedev_dev(name: &str) -> io::Result<()> {
180        let status = std::process::Command::new("sh")
181            .arg("MAKEDEV")
182            .arg(name)
183            .current_dir("/dev")
184            .status()?;
185
186        if status.success() {
187            Ok(())
188        } else {
189            Err(io::Error::other(format!(
190                "MAKEDEV {} failed with status {:?}",
191                name,
192                status.code()
193            )))
194        }
195    }
196    fn create_dev(name: &str) -> io::Result<()> {
197        unsafe {
198            let mut req: ifreq = mem::zeroed();
199            ptr::copy_nonoverlapping(
200                name.as_ptr() as *const c_char,
201                req.ifr_name.as_mut_ptr(),
202                name.len(),
203            );
204            if let Err(err) = siocifcreate(ctl()?.as_raw_fd(), &req) {
205                return Err(io::Error::from(err));
206            }
207        }
208        Ok(())
209    }
210    fn exists(dev_name: &str) -> io::Result<bool> {
211        unsafe {
212            let mut req: ifreq = mem::zeroed();
213            ptr::copy_nonoverlapping(
214                dev_name.as_ptr() as *const c_char,
215                req.ifr_name.as_mut_ptr(),
216                dev_name.len(),
217            );
218            let ctl = ctl()?;
219            if let Err(err) = siocgifflags(ctl.as_raw_fd(), &mut req) {
220                if err == nix::errno::Errno::ENXIO {
221                    return Ok(false);
222                }
223                Err(io::Error::from(err))
224            } else {
225                Ok(true)
226            }
227        }
228    }
229    pub(crate) fn from_tun(tun: Tun) -> io::Result<Self> {
230        let name = Self::name_of_fd(tun.as_raw_fd())?;
231        if name.starts_with("tap") {
232            // Tap does not have PI
233            tun.set_ignore_packet_info(false);
234        } else {
235            Self::enable_tunsifhead_impl(&tun.fd)?;
236            tun.set_ignore_packet_info(true);
237        }
238        Ok(Self {
239            name,
240            tun,
241            op_lock: Mutex::new(true),
242        })
243    }
244
245    fn enable_tunsifhead_impl(device_fd: &Fd) -> std::io::Result<()> {
246        unsafe {
247            if let Err(err) = sioctunsifhead(device_fd.as_raw_fd(), &1 as *const _) {
248                return Err(io::Error::from(err));
249            }
250        }
251        Ok(())
252    }
253
254    fn calc_dest_addr(&self, addr: IpAddr, netmask: IpAddr) -> io::Result<IpAddr> {
255        let prefix_len = ipnet::ip_mask_to_prefix(netmask)
256            .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
257        Ok(ipnet::IpNet::new(addr, prefix_len)
258            .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?
259            .broadcast())
260    }
261
262    /// Set the IPv4 alias of the device.
263    fn add_address(
264        &self,
265        addr: IpAddr,
266        mask: IpAddr,
267        dest: Option<IpAddr>,
268        associate_route: bool,
269    ) -> io::Result<()> {
270        unsafe {
271            match (addr, mask) {
272                (IpAddr::V4(addr), IpAddr::V4(mask)) => {
273                    let ctl = ctl()?;
274                    let mut req: ifaliasreq = mem::zeroed();
275                    let tun_name = self.name_impl()?;
276                    ptr::copy_nonoverlapping(
277                        tun_name.as_ptr() as *const c_char,
278                        req.ifra_name.as_mut_ptr(),
279                        tun_name.len(),
280                    );
281
282                    req.ifra_addr = crate::platform::unix::sockaddr_union::from((addr, 0)).addr;
283                    if let Some(dest) = dest {
284                        req.ifra_dstaddr =
285                            crate::platform::unix::sockaddr_union::from((dest, 0)).addr;
286                    }
287                    req.ifra_mask = crate::platform::unix::sockaddr_union::from((mask, 0)).addr;
288
289                    if let Err(err) = siocaifaddr(ctl.as_raw_fd(), &req) {
290                        return Err(io::Error::from(err));
291                    }
292                    if let Err(e) = self.add_route(addr.into(), mask.into(), associate_route) {
293                        log::warn!("{e:?}");
294                    }
295                }
296                (IpAddr::V6(addr), IpAddr::V6(mask)) => {
297                    let tun_name = self.name_impl()?;
298                    let mut req: in6_aliasreq = mem::zeroed();
299                    ptr::copy_nonoverlapping(
300                        tun_name.as_ptr() as *const c_char,
301                        req.ifra_name.as_mut_ptr(),
302                        tun_name.len(),
303                    );
304                    req.ifra_addr = sockaddr_union::from((addr, 0)).addr6;
305                    req.ifra_prefixmask = sockaddr_union::from((mask, 0)).addr6;
306                    req.ifra_lifetime.ia6t_vltime = 0xffffffff_u32;
307                    req.ifra_lifetime.ia6t_pltime = 0xffffffff_u32;
308                    // req.ifra_flags = IN6_IFF_NODAD;
309                    if let Err(err) = siocaifaddr_in6(ctl_v6()?.as_raw_fd(), &req) {
310                        return Err(io::Error::from(err));
311                    }
312                }
313                _ => {
314                    unreachable!();
315                }
316            }
317            Ok(())
318        }
319    }
320
321    /// Prepare a new request.
322    unsafe fn request(&self) -> io::Result<ifreq> {
323        let mut req: ifreq = mem::zeroed();
324        let tun_name = self.name_impl()?;
325        ptr::copy_nonoverlapping(
326            tun_name.as_ptr() as *const c_char,
327            req.ifr_name.as_mut_ptr(),
328            tun_name.len(),
329        );
330
331        Ok(req)
332    }
333
334    /// # Safety
335    unsafe fn request_v6(&self) -> io::Result<in6_ifreq> {
336        let tun_name = self.name_impl()?;
337        let mut req: in6_ifreq = mem::zeroed();
338        ptr::copy_nonoverlapping(
339            tun_name.as_ptr() as *const c_char,
340            req.ifra_name.as_mut_ptr(),
341            tun_name.len(),
342        );
343        req.ifr_ifru.ifru_flags = IN6_IFF_NODAD as _;
344        Ok(req)
345    }
346
347    fn add_route(&self, addr: IpAddr, netmask: IpAddr, associate_route: bool) -> io::Result<()> {
348        if !associate_route {
349            return Ok(());
350        }
351        let if_index = self.if_index_impl()?;
352        let prefix_len = ipnet::ip_mask_to_prefix(netmask)
353            .map_err(|e| io::Error::new(ErrorKind::InvalidInput, e))?;
354        let mut manager = route_manager::RouteManager::new()?;
355        let route = route_manager::Route::new(addr, prefix_len).with_if_index(if_index);
356        manager.add(&route)?;
357        Ok(())
358    }
359
360    /// Retrieves the name of the network interface.
361    pub(crate) fn name_impl(&self) -> io::Result<String> {
362        Ok(self.name.clone())
363    }
364    fn name_of_fd(tun: RawFd) -> io::Result<String> {
365        unsafe {
366            let mut req: ifreq = mem::zeroed();
367            if tapgifname(tun, &mut req).is_ok() {
368                let cstr = std::ffi::CStr::from_ptr(req.ifr_name.as_ptr());
369                let dev_name = cstr.to_string_lossy().to_string();
370                // tap
371                return Ok(dev_name);
372            }
373        }
374        let file = unsafe { std::fs::File::from_raw_fd(tun) };
375        let metadata = file.metadata()?;
376        let rdev = metadata.rdev();
377        let index = rdev % 256;
378        std::mem::forget(file); // prevent fd being closed
379        Ok(format!("tun{index}"))
380    }
381
382    fn remove_all_address_v4(&self) -> io::Result<()> {
383        unsafe {
384            let req_v4 = self.request()?;
385            loop {
386                if let Err(err) = siocdifaddr(ctl()?.as_raw_fd(), &req_v4) {
387                    if err == nix::errno::Errno::EADDRNOTAVAIL {
388                        break;
389                    }
390                    return Err(io::Error::from(err));
391                }
392            }
393        }
394        Ok(())
395    }
396}
397
398// Public User Interface
399impl DeviceImpl {
400    /// Retrieves the name of the network interface.
401    pub fn name(&self) -> io::Result<String> {
402        let _guard = self.op_lock.lock().unwrap();
403        self.name_impl()
404    }
405    /// If false, the program will not modify or manage routes in any way, allowing the system to handle all routing natively.
406    /// If true (default), the program will automatically add or remove routes to provide consistent routing behavior across all platforms.
407    /// Set this to be false to obtain the platform's default routing behavior.
408    pub fn set_associate_route(&self, associate_route: bool) {
409        *self.op_lock.lock().unwrap() = associate_route;
410    }
411    /// Retrieve whether route is associated with the IP setting interface, see [`DeviceImpl::set_associate_route`]
412    pub fn associate_route(&self) -> bool {
413        *self.op_lock.lock().unwrap()
414    }
415    /// Enables or disables the network interface.
416    pub fn enabled(&self, value: bool) -> io::Result<()> {
417        let _guard = self.op_lock.lock().unwrap();
418        unsafe {
419            let mut req = self.request()?;
420            let ctl = ctl()?;
421
422            if let Err(err) = siocgifflags(ctl.as_raw_fd(), &mut req) {
423                return Err(io::Error::from(err));
424            }
425
426            if value {
427                req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
428            } else {
429                req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
430            }
431
432            if let Err(err) = siocsifflags(ctl.as_raw_fd(), &req) {
433                return Err(io::Error::from(err));
434            }
435
436            Ok(())
437        }
438    }
439    /// Retrieves the current MTU (Maximum Transmission Unit) for the interface.
440    pub fn mtu(&self) -> io::Result<u16> {
441        let _guard = self.op_lock.lock().unwrap();
442        unsafe {
443            let mut req: ifreq = mem::zeroed();
444            let tun_name = self.name_impl()?;
445            ptr::copy_nonoverlapping(
446                tun_name.as_ptr() as *const c_char,
447                req.ifr_name.as_mut_ptr(),
448                tun_name.len(),
449            );
450            if let Err(err) = siocgifmtu(ctl()?.as_raw_fd(), &mut req) {
451                return Err(io::Error::from(err));
452            }
453
454            let r: u16 = req.ifr_ifru.ifru_mtu.try_into().map_err(io::Error::other)?;
455            Ok(r)
456        }
457    }
458    /// Sets the MTU (Maximum Transmission Unit) for the interface.
459    /// # Note
460    /// The specified value must be less than or equal to `1500`; it's a limitation of NetBSD.
461    pub fn set_mtu(&self, value: u16) -> io::Result<()> {
462        let _guard = self.op_lock.lock().unwrap();
463        unsafe {
464            let mut req: ifreq = mem::zeroed();
465            let tun_name = self.name_impl()?;
466            ptr::copy_nonoverlapping(
467                tun_name.as_ptr() as *const c_char,
468                req.ifr_name.as_mut_ptr(),
469                tun_name.len(),
470            );
471            req.ifr_ifru.ifru_mtu = value as _;
472
473            if let Err(err) = siocsifmtu(ctl()?.as_raw_fd(), &req) {
474                return Err(io::Error::from(err));
475            }
476            Ok(())
477        }
478    }
479    /// Sets the IPv4 network address, netmask, and an optional destination address.
480    /// Remove all previous set IPv4 addresses and set the specified address.
481    pub fn set_network_address<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
482        &self,
483        address: IPv4,
484        netmask: Netmask,
485        destination: Option<IPv4>,
486    ) -> io::Result<()> {
487        let guard = self.op_lock.lock().unwrap();
488        let addr = address.ipv4()?.into();
489        let netmask = netmask.netmask()?.into();
490        let default_dest = self.calc_dest_addr(addr, netmask)?;
491        let dest = destination
492            .map(|d| d.ipv4())
493            .transpose()?
494            .map(|v| v.into())
495            .unwrap_or(default_dest);
496        self.remove_all_address_v4()?;
497        self.add_address(addr, netmask, Some(dest), *guard)?;
498        Ok(())
499    }
500    /// Add IPv4 network address, netmask
501    pub fn add_address_v4<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
502        &self,
503        address: IPv4,
504        netmask: Netmask,
505    ) -> io::Result<()> {
506        let guard = self.op_lock.lock().unwrap();
507        let addr = address.ipv4()?.into();
508        let netmask = netmask.netmask()?.into();
509        let dest = self.calc_dest_addr(addr, netmask)?;
510        self.add_address(addr, netmask, Some(dest), *guard)?;
511        Ok(())
512    }
513    /// Removes an IP address from the interface.
514    pub fn remove_address(&self, addr: IpAddr) -> io::Result<()> {
515        let _guard = self.op_lock.lock().unwrap();
516        unsafe {
517            match addr {
518                IpAddr::V4(addr) => {
519                    let mut req_v4 = self.request()?;
520                    req_v4.ifr_ifru.ifru_addr = sockaddr_union::from((addr, 0)).addr;
521                    if let Err(err) = siocdifaddr(ctl()?.as_raw_fd(), &req_v4) {
522                        return Err(io::Error::from(err));
523                    }
524                }
525                IpAddr::V6(addr) => {
526                    let mut req_v6 = self.request_v6()?;
527                    req_v6.ifr_ifru.ifru_addr = sockaddr_union::from((addr, 0)).addr6;
528                    if let Err(err) = siocdifaddr_in6(ctl_v6()?.as_raw_fd(), &req_v6) {
529                        return Err(io::Error::from(err));
530                    }
531                }
532            }
533            Ok(())
534        }
535    }
536    /// Adds an IPv6 address to the interface.
537    pub fn add_address_v6<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
538        &self,
539        addr: IPv6,
540        netmask: Netmask,
541    ) -> io::Result<()> {
542        let guard = self.op_lock.lock().unwrap();
543        let addr = addr.ipv6()?;
544        let netmask = netmask.netmask()?;
545        self.add_address(addr.into(), netmask.into(), None, *guard)
546    }
547    /// Sets the MAC (hardware) address for the interface.
548    ///
549    /// This function constructs an interface request and copies the provided MAC address
550    /// into the hardware address field. It then applies the change via a system call.
551    /// This operation is typically supported only for TAP devices.
552    pub fn set_mac_address(&self, eth_addr: [u8; ETHER_ADDR_LEN as usize]) -> io::Result<()> {
553        let _guard = self.op_lock.lock().unwrap();
554        unsafe {
555            let mut req: ifaliasreq = mem::zeroed();
556            let tun_name = self.name_impl()?;
557            ptr::copy_nonoverlapping(
558                tun_name.as_ptr() as *const c_char,
559                req.ifra_name.as_mut_ptr(),
560                tun_name.len(),
561            );
562            req.ifra_addr.sa_len = ETHER_ADDR_LEN;
563            req.ifra_addr.sa_family = AF_LINK as u8;
564            req.ifra_addr.sa_data[0..ETHER_ADDR_LEN as usize]
565                .copy_from_slice(eth_addr.map(|c| c as i8).as_slice());
566            if let Err(err) = siocsifphyaddr(ctl()?.as_raw_fd(), &req) {
567                return Err(io::Error::from(err));
568            }
569            Ok(())
570        }
571    }
572    /// Retrieves the MAC (hardware) address of the interface.
573    ///
574    /// This function queries the MAC address by the interface name using a helper function.
575    /// An error is returned if the MAC address cannot be found.
576    pub fn mac_address(&self) -> io::Result<[u8; ETHER_ADDR_LEN as usize]> {
577        let _guard = self.op_lock.lock().unwrap();
578        let name = self.name_impl()?;
579        let interfaces = nix::ifaddrs::getifaddrs()?;
580        let interfaces = interfaces.filter(|item| item.interface_name == name);
581        for addr in interfaces {
582            if let Some(address) = addr.address {
583                if address.family() == Some(nix::sys::socket::AddressFamily::Link) {
584                    // This is a workaround, but it's safe because `SockaddrStorage` is a union whose layout is represented by C.
585                    // So, casting from `SockaddrStorage` to its variant thereof is safe.
586                    // The `if` condition ensures that the dereferencing of the resulting pointer gets a valid value of `LinkAddr`.
587                    // However, it is preferred to use `as_link_addr` once `nix` fixes it.
588                    unsafe {
589                        let link_ptr = &address as *const _ as *const LinkAddr;
590                        if let Some(mac) = (*link_ptr).addr() {
591                            return Ok(mac);
592                        }
593                    }
594                }
595            }
596        }
597        Err(std::io::Error::other("Unable to get Mac address"))
598    }
599    /// In Layer3(i.e. TUN mode), we need to put the tun interface into "multi_af" mode, which will prepend the address
600    /// family to all packets (same as FreeBSD).
601    /// If this is not enabled, the kernel silently drops all IPv6 packets on output and gets confused on input.
602    pub fn enable_tunsifhead(&self) -> io::Result<()> {
603        let _guard = self.op_lock.lock().unwrap();
604        Self::enable_tunsifhead_impl(&self.tun.fd)
605    }
606
607    /// Returns whether the TUN device is set to ignore packet information (PI).
608    ///
609    /// When enabled, the device does not prepend the `struct tun_pi` header
610    /// to packets, which can simplify packet processing in some cases.
611    ///
612    /// # Returns
613    /// * `true` - The TUN device ignores packet information.
614    /// * `false` - The TUN device includes packet information.
615    /// # Note
616    /// Retrieve whether the packet is ignored for the TUN Device; The TAP device always returns `false`.
617    pub fn ignore_packet_info(&self) -> bool {
618        let _guard = self.op_lock.lock().unwrap();
619        self.tun.ignore_packet_info()
620    }
621    /// Sets whether the TUN device should ignore packet information (PI).
622    ///
623    /// When `ignore_packet_info` is set to `true`, the TUN device does not
624    /// prepend the `struct tun_pi` header to packets. This can be useful
625    /// if the additional metadata is not needed.
626    ///
627    /// # Parameters
628    /// * `ign`
629    ///     - If `true`, the TUN device will ignore packet information.
630    ///     - If `false`, it will include packet information.
631    /// # Note
632    /// This only works for a TUN device; The invocation will be ignored if the device is a TAP.
633    pub fn set_ignore_packet_info(&self, ign: bool) {
634        let _guard = self.op_lock.lock().unwrap();
635        if let Ok(name) = self.name_impl() {
636            if name.starts_with("tun") {
637                self.tun.set_ignore_packet_info(ign)
638            }
639        }
640    }
641}
642
643impl From<Layer> for c_short {
644    fn from(layer: Layer) -> Self {
645        match layer {
646            Layer::L2 => 2,
647            Layer::L3 => 3,
648        }
649    }
650}