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 } 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 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 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 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 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 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 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 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); 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
398impl DeviceImpl {
400 pub fn name(&self) -> io::Result<String> {
402 let _guard = self.op_lock.lock().unwrap();
403 self.name_impl()
404 }
405 pub fn set_associate_route(&self, associate_route: bool) {
409 *self.op_lock.lock().unwrap() = associate_route;
410 }
411 pub fn associate_route(&self) -> bool {
413 *self.op_lock.lock().unwrap()
414 }
415 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 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 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 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 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 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 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 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 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 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 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 pub fn ignore_packet_info(&self) -> bool {
618 let _guard = self.op_lock.lock().unwrap();
619 self.tun.ignore_packet_info()
620 }
621 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}