1use std::io;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3use std::str::FromStr;
4
5use crate::platform::{DeviceImpl, SyncDevice};
6
7#[derive(Clone, Copy, Default, Debug, Eq, PartialEq)]
12#[non_exhaustive]
13pub enum Layer {
14 #[cfg(any(
16 target_os = "windows",
17 target_os = "linux",
18 target_os = "freebsd",
19 target_os = "macos",
20 target_os = "openbsd",
21 target_os = "netbsd",
22 ))]
23 L2,
24 #[default]
26 L3,
27}
28
29#[derive(Clone, Default, Debug)]
34pub(crate) struct DeviceConfig {
35 pub(crate) dev_name: Option<String>,
37 #[cfg(windows)]
39 pub(crate) description: Option<String>,
40 #[cfg(target_os = "macos")]
42 pub(crate) peer_feth: Option<String>,
43 #[cfg(any(
47 target_os = "macos",
48 target_os = "freebsd",
49 target_os = "openbsd",
50 target_os = "netbsd"
51 ))]
52 pub(crate) associate_route: Option<bool>,
53 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
56 pub(crate) reuse_dev: Option<bool>,
57 #[cfg(any(target_os = "macos", target_os = "windows"))]
60 pub(crate) persist: Option<bool>,
61 #[allow(dead_code)]
63 pub(crate) layer: Option<Layer>,
64 #[cfg(windows)]
66 pub(crate) device_guid: Option<u128>,
67 #[cfg(windows)]
68 pub(crate) wintun_log: Option<bool>,
69 #[cfg(windows)]
71 pub(crate) wintun_file: Option<String>,
72 #[cfg(windows)]
74 pub(crate) ring_capacity: Option<u32>,
75 #[cfg(windows)]
78 pub(crate) delete_driver: Option<bool>,
79 #[cfg(windows)]
80 pub(crate) mac_address: Option<String>,
81 #[cfg(any(
83 target_os = "macos",
84 target_os = "linux",
85 target_os = "freebsd",
86 target_os = "openbsd",
87 target_os = "netbsd"
88 ))]
89 pub(crate) packet_information: Option<bool>,
90 #[cfg(target_os = "linux")]
93 pub(crate) offload: Option<bool>,
94 #[cfg(target_os = "linux")]
96 pub(crate) multi_queue: Option<bool>,
97}
98type IPV4 = (
99 io::Result<Ipv4Addr>,
100 io::Result<u8>,
101 Option<io::Result<Ipv4Addr>>,
102);
103#[doc(hidden)]
174pub struct DeviceBuilderGuard<'a>(&'a mut DeviceBuilder);
175
176#[doc(hidden)]
177impl DeviceBuilderGuard<'_> {
178 #[cfg(windows)]
180 pub fn description<S: Into<String>>(&mut self, description: S) -> &mut Self {
181 self.0.description = Some(description.into());
182 self
183 }
184
185 #[cfg(windows)]
187 pub fn mtu_v4(&mut self, mtu: u16) -> &mut Self {
188 self.0.mtu = Some(mtu);
189 self
190 }
191 #[cfg(windows)]
193 pub fn mtu_v6(&mut self, mtu: u16) -> &mut Self {
194 self.0.mtu_v6 = Some(mtu);
195 self
196 }
197 #[cfg(any(
199 target_os = "windows",
200 target_os = "linux",
201 target_os = "freebsd",
202 target_os = "openbsd",
203 target_os = "macos",
204 target_os = "netbsd"
205 ))]
206 pub fn mac_addr(&mut self, mac_addr: [u8; 6]) -> &mut Self {
207 self.0.mac_addr = Some(mac_addr);
208 self
209 }
210
211 #[cfg(windows)]
214 pub fn device_guid(&mut self, device_guid: u128) -> &mut Self {
215 self.0.device_guid = Some(device_guid);
216 self
217 }
218 #[cfg(windows)]
222 pub fn wintun_log(&mut self, wintun_log: bool) -> &mut Self {
223 self.0.wintun_log = Some(wintun_log);
224 self
225 }
226 #[cfg(windows)]
228 pub fn wintun_file(&mut self, wintun_file: String) -> &mut Self {
229 self.0.wintun_file = Some(wintun_file);
230 self
231 }
232 #[cfg(windows)]
236 pub fn ring_capacity(&mut self, ring_capacity: u32) -> &mut Self {
237 self.0.ring_capacity = Some(ring_capacity);
238 self
239 }
240 #[cfg(windows)]
242 pub fn metric(&mut self, metric: u16) -> &mut Self {
243 self.0.metric = Some(metric);
244 self
245 }
246 #[cfg(windows)]
251 pub fn delete_driver(&mut self, delete_driver: bool) -> &mut Self {
252 self.0.delete_driver = Some(delete_driver);
253 self
254 }
255 #[cfg(target_os = "linux")]
257 pub fn tx_queue_len(&mut self, tx_queue_len: u32) -> &mut Self {
258 self.0.tx_queue_len = Some(tx_queue_len);
259 self
260 }
261 #[cfg(target_os = "linux")]
264 pub fn offload(&mut self, offload: bool) -> &mut Self {
265 self.0.offload = Some(offload);
266 self
267 }
268 #[cfg(target_os = "linux")]
270 pub fn multi_queue(&mut self, multi_queue: bool) -> &mut Self {
271 self.0.multi_queue = Some(multi_queue);
272 self
273 }
274 #[cfg(any(
284 target_os = "macos",
285 target_os = "linux",
286 target_os = "freebsd",
287 target_os = "openbsd",
288 target_os = "netbsd"
289 ))]
290 pub fn packet_information(&mut self, packet_information: bool) -> &mut Self {
291 self.0.packet_information = Some(packet_information);
292 self
293 }
294 #[cfg(target_os = "macos")]
297 pub fn peer_feth<S: Into<String>>(&mut self, peer_feth: S) -> &mut Self {
298 self.0.peer_feth = Some(peer_feth.into());
299 self
300 }
301 #[cfg(any(
305 target_os = "macos",
306 target_os = "freebsd",
307 target_os = "openbsd",
308 target_os = "netbsd"
309 ))]
310 pub fn associate_route(&mut self, associate_route: bool) -> &mut Self {
311 self.0.associate_route = Some(associate_route);
312 self
313 }
314 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
318 pub fn reuse_dev(&mut self, reuse: bool) -> &mut Self {
319 self.0.reuse_dev = Some(reuse);
320 self
321 }
322 #[cfg(any(target_os = "macos", target_os = "windows"))]
326 pub fn persist(&mut self, persist: bool) -> &mut Self {
327 self.0.persist = Some(persist);
328 self
329 }
330}
331#[derive(Default)]
334pub struct DeviceBuilder {
335 dev_name: Option<String>,
336 #[cfg(windows)]
337 description: Option<String>,
338 #[cfg(target_os = "macos")]
339 peer_feth: Option<String>,
340 #[cfg(any(
341 target_os = "macos",
342 target_os = "freebsd",
343 target_os = "openbsd",
344 target_os = "netbsd"
345 ))]
346 associate_route: Option<bool>,
347 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
348 reuse_dev: Option<bool>,
349 #[cfg(any(target_os = "macos", target_os = "windows"))]
350 persist: Option<bool>,
351 enabled: Option<bool>,
352 mtu: Option<u16>,
353 #[cfg(windows)]
354 mtu_v6: Option<u16>,
355 ipv4: Option<IPV4>,
356 ipv6: Option<Vec<(io::Result<Ipv6Addr>, io::Result<u8>)>>,
357 layer: Option<Layer>,
358 #[cfg(any(
359 target_os = "windows",
360 target_os = "linux",
361 target_os = "freebsd",
362 target_os = "openbsd",
363 target_os = "macos",
364 target_os = "netbsd"
365 ))]
366 mac_addr: Option<[u8; 6]>,
367 #[cfg(windows)]
368 device_guid: Option<u128>,
369 #[cfg(windows)]
370 wintun_log: Option<bool>,
371 #[cfg(windows)]
372 wintun_file: Option<String>,
373 #[cfg(windows)]
374 ring_capacity: Option<u32>,
375 #[cfg(windows)]
376 metric: Option<u16>,
377 #[cfg(windows)]
378 delete_driver: Option<bool>,
379 #[cfg(any(
381 target_os = "macos",
382 target_os = "linux",
383 target_os = "freebsd",
384 target_os = "openbsd",
385 target_os = "netbsd"
386 ))]
387 packet_information: Option<bool>,
388 #[cfg(target_os = "linux")]
389 tx_queue_len: Option<u32>,
390 #[cfg(target_os = "linux")]
393 offload: Option<bool>,
394 #[cfg(target_os = "linux")]
396 multi_queue: Option<bool>,
397}
398
399impl DeviceBuilder {
400 pub fn new() -> Self {
402 Self::default().enable(true)
403 }
404 pub fn name<S: Into<String>>(mut self, dev_name: S) -> Self {
406 self.dev_name = Some(dev_name.into());
407 self
408 }
409 #[cfg(windows)]
411 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
412 self.description = Some(description.into());
413 self
414 }
415 pub fn mtu(mut self, mtu: u16) -> Self {
417 self.mtu = Some(mtu);
418 #[cfg(windows)]
419 {
420 self.mtu_v6 = Some(mtu);
422 }
423 self
424 }
425 #[cfg(windows)]
427 pub fn mtu_v4(mut self, mtu: u16) -> Self {
428 self.mtu = Some(mtu);
429 self
430 }
431 #[cfg(windows)]
433 pub fn mtu_v6(mut self, mtu: u16) -> Self {
434 self.mtu_v6 = Some(mtu);
435 self
436 }
437 #[cfg(any(
439 target_os = "windows",
440 target_os = "linux",
441 target_os = "freebsd",
442 target_os = "openbsd",
443 target_os = "macos",
444 target_os = "netbsd"
445 ))]
446 pub fn mac_addr(mut self, mac_addr: [u8; 6]) -> Self {
447 self.mac_addr = Some(mac_addr);
448 self
449 }
450 pub fn ipv4<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
462 mut self,
463 address: IPv4,
464 mask: Netmask,
465 destination: Option<IPv4>,
466 ) -> Self {
467 self.ipv4 = Some((address.ipv4(), mask.prefix(), destination.map(|v| v.ipv4())));
468 self
469 }
470 pub fn ipv6<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
480 mut self,
481 address: IPv6,
482 mask: Netmask,
483 ) -> Self {
484 if let Some(v) = &mut self.ipv6 {
485 v.push((address.ipv6(), mask.prefix()));
486 } else {
487 self.ipv6 = Some(vec![(address.ipv6(), mask.prefix())]);
488 }
489
490 self
491 }
492 pub fn ipv6_tuple<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
504 mut self,
505 addrs: &[(IPv6, Netmask)],
506 ) -> Self {
507 if let Some(v) = &mut self.ipv6 {
508 for (address, mask) in addrs {
509 v.push((address.ipv6(), mask.prefix()));
510 }
511 } else {
512 self.ipv6 = Some(
513 addrs
514 .iter()
515 .map(|(ip, mask)| (ip.ipv6(), mask.prefix()))
516 .collect(),
517 );
518 }
519 self
520 }
521 pub fn layer(mut self, layer: Layer) -> Self {
526 self.layer = Some(layer);
527 self
528 }
529 #[cfg(windows)]
532 pub fn device_guid(mut self, device_guid: u128) -> Self {
533 self.device_guid = Some(device_guid);
534 self
535 }
536 #[cfg(windows)]
540 pub fn wintun_log(mut self, wintun_log: bool) -> Self {
541 self.wintun_log = Some(wintun_log);
542 self
543 }
544 #[cfg(windows)]
546 pub fn wintun_file(mut self, wintun_file: String) -> Self {
547 self.wintun_file = Some(wintun_file);
548 self
549 }
550 #[cfg(windows)]
554 pub fn ring_capacity(mut self, ring_capacity: u32) -> Self {
555 self.ring_capacity = Some(ring_capacity);
556 self
557 }
558 #[cfg(windows)]
560 pub fn metric(mut self, metric: u16) -> Self {
561 self.metric = Some(metric);
562 self
563 }
564 #[cfg(windows)]
569 pub fn delete_driver(mut self, delete_driver: bool) -> Self {
570 self.delete_driver = Some(delete_driver);
571 self
572 }
573 #[cfg(target_os = "linux")]
575 pub fn tx_queue_len(mut self, tx_queue_len: u32) -> Self {
576 self.tx_queue_len = Some(tx_queue_len);
577 self
578 }
579 #[cfg(target_os = "linux")]
582 pub fn offload(mut self, offload: bool) -> Self {
583 self.offload = Some(offload);
584 self
585 }
586 #[cfg(target_os = "linux")]
588 pub fn multi_queue(mut self, multi_queue: bool) -> Self {
589 self.multi_queue = Some(multi_queue);
590 self
591 }
592 #[cfg(any(
602 target_os = "macos",
603 target_os = "linux",
604 target_os = "freebsd",
605 target_os = "openbsd",
606 target_os = "netbsd"
607 ))]
608 pub fn packet_information(mut self, packet_information: bool) -> Self {
609 self.packet_information = Some(packet_information);
610 self
611 }
612 #[cfg(target_os = "macos")]
615 pub fn peer_feth<S: Into<String>>(mut self, peer_feth: S) -> Self {
616 self.peer_feth = Some(peer_feth.into());
617 self
618 }
619 #[cfg(any(
623 target_os = "macos",
624 target_os = "freebsd",
625 target_os = "openbsd",
626 target_os = "netbsd"
627 ))]
628 pub fn associate_route(mut self, associate_route: bool) -> Self {
629 self.associate_route = Some(associate_route);
630 self
631 }
632 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
636 pub fn reuse_dev(mut self, reuse: bool) -> Self {
637 self.reuse_dev = Some(reuse);
638 self
639 }
640 #[cfg(any(target_os = "macos", target_os = "windows"))]
644 pub fn persist(mut self, persist: bool) -> Self {
645 self.persist = Some(persist);
646 self
647 }
648 pub fn enable(mut self, enable: bool) -> Self {
651 self.enabled = Some(enable);
652 self
653 }
654
655 pub fn inherit_enable_state(mut self) -> Self {
660 self.enabled = None;
661 self
662 }
663 pub(crate) fn build_config(&mut self) -> DeviceConfig {
664 DeviceConfig {
665 dev_name: self.dev_name.take(),
666 #[cfg(windows)]
667 description: self.description.take(),
668 #[cfg(target_os = "macos")]
669 peer_feth: self.peer_feth.take(),
670 #[cfg(any(
671 target_os = "macos",
672 target_os = "freebsd",
673 target_os = "openbsd",
674 target_os = "netbsd"
675 ))]
676 associate_route: self.associate_route,
677 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
678 reuse_dev: self.reuse_dev,
679 #[cfg(any(target_os = "macos", target_os = "windows"))]
680 persist: self.persist,
681 layer: self.layer.take(),
682 #[cfg(windows)]
683 device_guid: self.device_guid.take(),
684 #[cfg(windows)]
685 wintun_log: self.wintun_log.take(),
686 #[cfg(windows)]
687 wintun_file: self.wintun_file.take(),
688 #[cfg(windows)]
689 ring_capacity: self.ring_capacity.take(),
690 #[cfg(windows)]
691 delete_driver: self.delete_driver.take(),
692 #[cfg(windows)]
693 mac_address: self.mac_addr.map(|v| {
694 use std::fmt::Write;
695 v.iter()
696 .fold(String::with_capacity(v.len() * 2), |mut s, b| {
697 write!(&mut s, "{b:02X}").unwrap();
698 s
699 })
700 }),
701 #[cfg(any(
702 target_os = "macos",
703 target_os = "linux",
704 target_os = "freebsd",
705 target_os = "openbsd",
706 target_os = "netbsd"
707 ))]
708 packet_information: self.packet_information.take(),
709 #[cfg(target_os = "linux")]
710 offload: self.offload.take(),
711 #[cfg(target_os = "linux")]
712 multi_queue: self.multi_queue.take(),
713 }
714 }
715 pub(crate) fn config(self, device: &DeviceImpl) -> io::Result<()> {
716 if let Some(mtu) = self.mtu {
717 device.set_mtu(mtu)?;
718 }
719 #[cfg(windows)]
720 if let Some(mtu) = self.mtu_v6 {
721 device.set_mtu_v6(mtu)?;
722 }
723 #[cfg(windows)]
724 if let Some(metric) = self.metric {
725 device.set_metric(metric)?;
726 }
727 #[cfg(target_os = "linux")]
728 if let Some(tx_queue_len) = self.tx_queue_len {
729 device.set_tx_queue_len(tx_queue_len)?;
730 }
731 #[cfg(any(
732 target_os = "linux",
733 target_os = "freebsd",
734 target_os = "macos",
735 target_os = "openbsd",
736 target_os = "netbsd"
737 ))]
738 if let Some(mac_addr) = self.mac_addr {
739 device.set_mac_address(mac_addr)?;
740 }
741
742 if let Some((address, prefix, destination)) = self.ipv4 {
743 let prefix = prefix?;
744 let address = address?;
745 let destination = destination.transpose()?;
746 device.set_network_address(address, prefix, destination)?;
747 }
748 if let Some(ipv6) = self.ipv6 {
749 for (address, prefix) in ipv6 {
750 let prefix = prefix?;
751 let address = address?;
752 device.add_address_v6(address, prefix)?;
753 }
754 }
755 if let Some(enabled) = self.enabled {
756 device.enabled(enabled)?;
757 }
758 Ok(())
759 }
760 pub fn build_sync(mut self) -> io::Result<SyncDevice> {
762 let device = DeviceImpl::new(self.build_config())?;
763 self.config(&device)?;
764 Ok(SyncDevice(device))
765 }
766 #[cfg(any(feature = "async_io", feature = "async_tokio"))]
773 pub fn build_async(self) -> io::Result<crate::AsyncDevice> {
774 let sync_device = self.build_sync()?;
775 let device = crate::AsyncDevice::new_dev(sync_device.0)?;
776 Ok(device)
777 }
778 pub fn with<F: FnMut(&mut DeviceBuilderGuard)>(mut self, mut f: F) -> Self {
804 let mut borrow = DeviceBuilderGuard(&mut self);
805 f(&mut borrow);
806 self
807 }
808}
809
810pub trait ToIpv4Address {
812 fn ipv4(&self) -> io::Result<Ipv4Addr>;
815}
816impl ToIpv4Address for Ipv4Addr {
817 fn ipv4(&self) -> io::Result<Ipv4Addr> {
818 Ok(*self)
819 }
820}
821impl ToIpv4Address for IpAddr {
822 fn ipv4(&self) -> io::Result<Ipv4Addr> {
823 match self {
824 IpAddr::V4(ip) => Ok(*ip),
825 IpAddr::V6(_) => Err(io::Error::new(
826 io::ErrorKind::InvalidData,
827 "invalid address",
828 )),
829 }
830 }
831}
832impl ToIpv4Address for String {
833 fn ipv4(&self) -> io::Result<Ipv4Addr> {
834 self.as_str().ipv4()
835 }
836}
837impl ToIpv4Address for &str {
838 fn ipv4(&self) -> io::Result<Ipv4Addr> {
839 match Ipv4Addr::from_str(self) {
840 Ok(ip) => Ok(ip),
841 Err(_e) => Err(io::Error::new(
842 io::ErrorKind::InvalidData,
843 "invalid IPv4 str",
844 )),
845 }
846 }
847}
848
849pub trait ToIpv6Address {
851 fn ipv6(&self) -> io::Result<Ipv6Addr>;
854}
855
856impl ToIpv6Address for Ipv6Addr {
857 fn ipv6(&self) -> io::Result<Ipv6Addr> {
858 Ok(*self)
859 }
860}
861impl ToIpv6Address for IpAddr {
862 fn ipv6(&self) -> io::Result<Ipv6Addr> {
863 match self {
864 IpAddr::V4(_) => Err(io::Error::new(
865 io::ErrorKind::InvalidData,
866 "invalid address",
867 )),
868 IpAddr::V6(ip) => Ok(*ip),
869 }
870 }
871}
872impl ToIpv6Address for String {
873 fn ipv6(&self) -> io::Result<Ipv6Addr> {
874 self.as_str().ipv6()
875 }
876}
877impl ToIpv6Address for &str {
878 fn ipv6(&self) -> io::Result<Ipv6Addr> {
879 match Ipv6Addr::from_str(self) {
880 Ok(ip) => Ok(ip),
881 Err(_e) => Err(io::Error::new(
882 io::ErrorKind::InvalidData,
883 "invalid IPv6 str",
884 )),
885 }
886 }
887}
888pub trait ToIpv4Netmask {
890 fn prefix(&self) -> io::Result<u8>;
892 fn netmask(&self) -> io::Result<Ipv4Addr> {
894 let ip = u32::MAX
895 .checked_shl(32 - self.prefix()? as u32)
896 .unwrap_or(0);
897 Ok(Ipv4Addr::from(ip))
898 }
899}
900
901impl ToIpv4Netmask for u8 {
902 fn prefix(&self) -> io::Result<u8> {
903 if *self > 32 {
904 return Err(io::Error::new(
905 io::ErrorKind::InvalidData,
906 "invalid IP prefix length",
907 ));
908 }
909 Ok(*self)
910 }
911}
912
913impl ToIpv4Netmask for Ipv4Addr {
914 fn prefix(&self) -> io::Result<u8> {
915 let ip = u32::from_be_bytes(self.octets());
916 if ip.leading_ones() != ip.count_ones() {
918 return Err(io::Error::new(
919 io::ErrorKind::InvalidData,
920 "invalid netmask",
921 ));
922 }
923 Ok(ip.leading_ones() as u8)
924 }
925}
926impl ToIpv4Netmask for String {
927 fn prefix(&self) -> io::Result<u8> {
928 ToIpv4Netmask::prefix(&self.as_str())
929 }
930}
931impl ToIpv4Netmask for &str {
932 fn prefix(&self) -> io::Result<u8> {
933 match Ipv4Addr::from_str(self) {
934 Ok(ip) => ip.prefix(),
935 Err(_e) => Err(io::Error::new(
936 io::ErrorKind::InvalidData,
937 "invalid netmask str",
938 )),
939 }
940 }
941}
942pub trait ToIpv6Netmask {
944 fn prefix(&self) -> io::Result<u8>;
946 fn netmask(&self) -> io::Result<Ipv6Addr> {
948 let ip = u128::MAX
949 .checked_shl(128 - self.prefix()? as u32)
950 .unwrap_or(0);
951 Ok(Ipv6Addr::from(ip))
952 }
953}
954
955impl ToIpv6Netmask for u8 {
956 fn prefix(&self) -> io::Result<u8> {
957 if *self > 128 {
958 return Err(io::Error::new(
959 io::ErrorKind::InvalidData,
960 "invalid IP prefix length",
961 ));
962 }
963 Ok(*self)
964 }
965}
966
967impl ToIpv6Netmask for Ipv6Addr {
968 fn prefix(&self) -> io::Result<u8> {
969 let ip = u128::from_be_bytes(self.octets());
970 if ip.leading_ones() != ip.count_ones() {
971 return Err(io::Error::new(
972 io::ErrorKind::InvalidData,
973 "invalid netmask",
974 ));
975 }
976 Ok(ip.leading_ones() as u8)
977 }
978}
979impl ToIpv6Netmask for String {
980 fn prefix(&self) -> io::Result<u8> {
981 ToIpv6Netmask::prefix(&self.as_str())
982 }
983}
984impl ToIpv6Netmask for &str {
985 fn prefix(&self) -> io::Result<u8> {
986 match Ipv6Addr::from_str(self) {
987 Ok(ip) => ip.prefix(),
988 Err(_e) => Err(io::Error::new(
989 io::ErrorKind::InvalidData,
990 "invalid netmask str",
991 )),
992 }
993 }
994}