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 = "netbsd"
87 ))]
88 pub(crate) packet_information: Option<bool>,
89 #[cfg(target_os = "linux")]
92 pub(crate) offload: Option<bool>,
93 #[cfg(target_os = "linux")]
95 pub(crate) multi_queue: Option<bool>,
96}
97type IPV4 = (
98 io::Result<Ipv4Addr>,
99 io::Result<u8>,
100 Option<io::Result<Ipv4Addr>>,
101);
102#[doc(hidden)]
173pub struct DeviceBuilderGuard<'a>(&'a mut DeviceBuilder);
174
175#[doc(hidden)]
176impl DeviceBuilderGuard<'_> {
177 #[cfg(windows)]
179 pub fn description<S: Into<String>>(&mut self, description: S) -> &mut Self {
180 self.0.description = Some(description.into());
181 self
182 }
183
184 #[cfg(windows)]
186 pub fn mtu_v4(&mut self, mtu: u16) -> &mut Self {
187 self.0.mtu = Some(mtu);
188 self
189 }
190 #[cfg(windows)]
192 pub fn mtu_v6(&mut self, mtu: u16) -> &mut Self {
193 self.0.mtu_v6 = Some(mtu);
194 self
195 }
196 #[cfg(any(
198 target_os = "windows",
199 target_os = "linux",
200 target_os = "freebsd",
201 target_os = "openbsd",
202 target_os = "macos",
203 target_os = "netbsd"
204 ))]
205 pub fn mac_addr(&mut self, mac_addr: [u8; 6]) -> &mut Self {
206 self.0.mac_addr = Some(mac_addr);
207 self
208 }
209
210 #[cfg(windows)]
213 pub fn device_guid(&mut self, device_guid: u128) -> &mut Self {
214 self.0.device_guid = Some(device_guid);
215 self
216 }
217 #[cfg(windows)]
221 pub fn wintun_log(&mut self, wintun_log: bool) -> &mut Self {
222 self.0.wintun_log = Some(wintun_log);
223 self
224 }
225 #[cfg(windows)]
227 pub fn wintun_file(&mut self, wintun_file: String) -> &mut Self {
228 self.0.wintun_file = Some(wintun_file);
229 self
230 }
231 #[cfg(windows)]
235 pub fn ring_capacity(&mut self, ring_capacity: u32) -> &mut Self {
236 self.0.ring_capacity = Some(ring_capacity);
237 self
238 }
239 #[cfg(windows)]
241 pub fn metric(&mut self, metric: u16) -> &mut Self {
242 self.0.metric = Some(metric);
243 self
244 }
245 #[cfg(windows)]
250 pub fn delete_driver(&mut self, delete_driver: bool) -> &mut Self {
251 self.0.delete_driver = Some(delete_driver);
252 self
253 }
254 #[cfg(target_os = "linux")]
256 pub fn tx_queue_len(&mut self, tx_queue_len: u32) -> &mut Self {
257 self.0.tx_queue_len = Some(tx_queue_len);
258 self
259 }
260 #[cfg(target_os = "linux")]
263 pub fn offload(&mut self, offload: bool) -> &mut Self {
264 self.0.offload = Some(offload);
265 self
266 }
267 #[cfg(target_os = "linux")]
269 pub fn multi_queue(&mut self, multi_queue: bool) -> &mut Self {
270 self.0.multi_queue = Some(multi_queue);
271 self
272 }
273 #[cfg(any(
282 target_os = "macos",
283 target_os = "linux",
284 target_os = "freebsd",
285 target_os = "netbsd"
286 ))]
287 pub fn packet_information(&mut self, packet_information: bool) -> &mut Self {
288 self.0.packet_information = Some(packet_information);
289 self
290 }
291 #[cfg(target_os = "macos")]
294 pub fn peer_feth<S: Into<String>>(&mut self, peer_feth: S) -> &mut Self {
295 self.0.peer_feth = Some(peer_feth.into());
296 self
297 }
298 #[cfg(any(
302 target_os = "macos",
303 target_os = "freebsd",
304 target_os = "openbsd",
305 target_os = "netbsd"
306 ))]
307 pub fn associate_route(&mut self, associate_route: bool) -> &mut Self {
308 self.0.associate_route = Some(associate_route);
309 self
310 }
311 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
315 pub fn reuse_dev(&mut self, reuse: bool) -> &mut Self {
316 self.0.reuse_dev = Some(reuse);
317 self
318 }
319 #[cfg(any(target_os = "macos", target_os = "windows"))]
323 pub fn persist(&mut self, persist: bool) -> &mut Self {
324 self.0.persist = Some(persist);
325 self
326 }
327}
328#[derive(Default)]
331pub struct DeviceBuilder {
332 dev_name: Option<String>,
333 #[cfg(windows)]
334 description: Option<String>,
335 #[cfg(target_os = "macos")]
336 peer_feth: Option<String>,
337 #[cfg(any(
338 target_os = "macos",
339 target_os = "freebsd",
340 target_os = "openbsd",
341 target_os = "netbsd"
342 ))]
343 associate_route: Option<bool>,
344 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
345 reuse_dev: Option<bool>,
346 #[cfg(any(target_os = "macos", target_os = "windows"))]
347 persist: Option<bool>,
348 enabled: Option<bool>,
349 mtu: Option<u16>,
350 #[cfg(windows)]
351 mtu_v6: Option<u16>,
352 ipv4: Option<IPV4>,
353 ipv6: Option<Vec<(io::Result<Ipv6Addr>, io::Result<u8>)>>,
354 layer: Option<Layer>,
355 #[cfg(any(
356 target_os = "windows",
357 target_os = "linux",
358 target_os = "freebsd",
359 target_os = "openbsd",
360 target_os = "macos",
361 target_os = "netbsd"
362 ))]
363 mac_addr: Option<[u8; 6]>,
364 #[cfg(windows)]
365 device_guid: Option<u128>,
366 #[cfg(windows)]
367 wintun_log: Option<bool>,
368 #[cfg(windows)]
369 wintun_file: Option<String>,
370 #[cfg(windows)]
371 ring_capacity: Option<u32>,
372 #[cfg(windows)]
373 metric: Option<u16>,
374 #[cfg(windows)]
375 delete_driver: Option<bool>,
376 #[cfg(any(
378 target_os = "macos",
379 target_os = "linux",
380 target_os = "freebsd",
381 target_os = "netbsd"
382 ))]
383 packet_information: Option<bool>,
384 #[cfg(target_os = "linux")]
385 tx_queue_len: Option<u32>,
386 #[cfg(target_os = "linux")]
389 offload: Option<bool>,
390 #[cfg(target_os = "linux")]
392 multi_queue: Option<bool>,
393}
394
395impl DeviceBuilder {
396 pub fn new() -> Self {
398 Self::default()
399 }
400 pub fn name<S: Into<String>>(mut self, dev_name: S) -> Self {
402 self.dev_name = Some(dev_name.into());
403 self
404 }
405 #[cfg(windows)]
407 pub fn description<S: Into<String>>(mut self, description: S) -> Self {
408 self.description = Some(description.into());
409 self
410 }
411 pub fn mtu(mut self, mtu: u16) -> Self {
413 self.mtu = Some(mtu);
414 #[cfg(windows)]
415 {
416 self.mtu_v6 = Some(mtu);
418 }
419 self
420 }
421 #[cfg(windows)]
423 pub fn mtu_v4(mut self, mtu: u16) -> Self {
424 self.mtu = Some(mtu);
425 self
426 }
427 #[cfg(windows)]
429 pub fn mtu_v6(mut self, mtu: u16) -> Self {
430 self.mtu_v6 = Some(mtu);
431 self
432 }
433 #[cfg(any(
435 target_os = "windows",
436 target_os = "linux",
437 target_os = "freebsd",
438 target_os = "openbsd",
439 target_os = "macos",
440 target_os = "netbsd"
441 ))]
442 pub fn mac_addr(mut self, mac_addr: [u8; 6]) -> Self {
443 self.mac_addr = Some(mac_addr);
444 self
445 }
446 pub fn ipv4<IPv4: ToIpv4Address, Netmask: ToIpv4Netmask>(
458 mut self,
459 address: IPv4,
460 mask: Netmask,
461 destination: Option<IPv4>,
462 ) -> Self {
463 self.ipv4 = Some((address.ipv4(), mask.prefix(), destination.map(|v| v.ipv4())));
464 self
465 }
466 pub fn ipv6<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
476 mut self,
477 address: IPv6,
478 mask: Netmask,
479 ) -> Self {
480 if let Some(v) = &mut self.ipv6 {
481 v.push((address.ipv6(), mask.prefix()));
482 } else {
483 self.ipv6 = Some(vec![(address.ipv6(), mask.prefix())]);
484 }
485
486 self
487 }
488 pub fn ipv6_tuple<IPv6: ToIpv6Address, Netmask: ToIpv6Netmask>(
500 mut self,
501 addrs: &[(IPv6, Netmask)],
502 ) -> Self {
503 if let Some(v) = &mut self.ipv6 {
504 for (address, mask) in addrs {
505 v.push((address.ipv6(), mask.prefix()));
506 }
507 } else {
508 self.ipv6 = Some(
509 addrs
510 .iter()
511 .map(|(ip, mask)| (ip.ipv6(), mask.prefix()))
512 .collect(),
513 );
514 }
515 self
516 }
517 pub fn layer(mut self, layer: Layer) -> Self {
522 self.layer = Some(layer);
523 self
524 }
525 #[cfg(windows)]
528 pub fn device_guid(mut self, device_guid: u128) -> Self {
529 self.device_guid = Some(device_guid);
530 self
531 }
532 #[cfg(windows)]
536 pub fn wintun_log(mut self, wintun_log: bool) -> Self {
537 self.wintun_log = Some(wintun_log);
538 self
539 }
540 #[cfg(windows)]
542 pub fn wintun_file(mut self, wintun_file: String) -> Self {
543 self.wintun_file = Some(wintun_file);
544 self
545 }
546 #[cfg(windows)]
550 pub fn ring_capacity(mut self, ring_capacity: u32) -> Self {
551 self.ring_capacity = Some(ring_capacity);
552 self
553 }
554 #[cfg(windows)]
556 pub fn metric(mut self, metric: u16) -> Self {
557 self.metric = Some(metric);
558 self
559 }
560 #[cfg(windows)]
565 pub fn delete_driver(mut self, delete_driver: bool) -> Self {
566 self.delete_driver = Some(delete_driver);
567 self
568 }
569 #[cfg(target_os = "linux")]
571 pub fn tx_queue_len(mut self, tx_queue_len: u32) -> Self {
572 self.tx_queue_len = Some(tx_queue_len);
573 self
574 }
575 #[cfg(target_os = "linux")]
578 pub fn offload(mut self, offload: bool) -> Self {
579 self.offload = Some(offload);
580 self
581 }
582 #[cfg(target_os = "linux")]
584 pub fn multi_queue(mut self, multi_queue: bool) -> Self {
585 self.multi_queue = Some(multi_queue);
586 self
587 }
588 #[cfg(any(
597 target_os = "macos",
598 target_os = "linux",
599 target_os = "freebsd",
600 target_os = "netbsd"
601 ))]
602 pub fn packet_information(mut self, packet_information: bool) -> Self {
603 self.packet_information = Some(packet_information);
604 self
605 }
606 #[cfg(target_os = "macos")]
609 pub fn peer_feth<S: Into<String>>(mut self, peer_feth: S) -> Self {
610 self.peer_feth = Some(peer_feth.into());
611 self
612 }
613 #[cfg(any(
617 target_os = "macos",
618 target_os = "freebsd",
619 target_os = "openbsd",
620 target_os = "netbsd"
621 ))]
622 pub fn associate_route(mut self, associate_route: bool) -> Self {
623 self.associate_route = Some(associate_route);
624 self
625 }
626 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
630 pub fn reuse_dev(mut self, reuse: bool) -> Self {
631 self.reuse_dev = Some(reuse);
632 self
633 }
634 #[cfg(any(target_os = "macos", target_os = "windows"))]
638 pub fn persist(mut self, persist: bool) -> Self {
639 self.persist = Some(persist);
640 self
641 }
642 pub fn enable(mut self, enable: bool) -> Self {
645 self.enabled = Some(enable);
646 self
647 }
648 pub(crate) fn build_config(&mut self) -> DeviceConfig {
649 DeviceConfig {
650 dev_name: self.dev_name.take(),
651 #[cfg(windows)]
652 description: self.description.take(),
653 #[cfg(target_os = "macos")]
654 peer_feth: self.peer_feth.take(),
655 #[cfg(any(
656 target_os = "macos",
657 target_os = "freebsd",
658 target_os = "openbsd",
659 target_os = "netbsd"
660 ))]
661 associate_route: self.associate_route,
662 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "netbsd"))]
663 reuse_dev: self.reuse_dev,
664 #[cfg(any(target_os = "macos", target_os = "windows"))]
665 persist: self.persist,
666 layer: self.layer.take(),
667 #[cfg(windows)]
668 device_guid: self.device_guid.take(),
669 #[cfg(windows)]
670 wintun_log: self.wintun_log.take(),
671 #[cfg(windows)]
672 wintun_file: self.wintun_file.take(),
673 #[cfg(windows)]
674 ring_capacity: self.ring_capacity.take(),
675 #[cfg(windows)]
676 delete_driver: self.delete_driver.take(),
677 #[cfg(windows)]
678 mac_address: self.mac_addr.map(|v| {
679 use std::fmt::Write;
680 v.iter()
681 .fold(String::with_capacity(v.len() * 2), |mut s, b| {
682 write!(&mut s, "{b:02X}").unwrap();
683 s
684 })
685 }),
686 #[cfg(any(
687 target_os = "macos",
688 target_os = "linux",
689 target_os = "freebsd",
690 target_os = "netbsd"
691 ))]
692 packet_information: self.packet_information.take(),
693 #[cfg(target_os = "linux")]
694 offload: self.offload.take(),
695 #[cfg(target_os = "linux")]
696 multi_queue: self.multi_queue.take(),
697 }
698 }
699 pub(crate) fn config(self, device: &DeviceImpl) -> io::Result<()> {
700 if let Some(mtu) = self.mtu {
701 device.set_mtu(mtu)?;
702 }
703 #[cfg(windows)]
704 if let Some(mtu) = self.mtu_v6 {
705 device.set_mtu_v6(mtu)?;
706 }
707 #[cfg(windows)]
708 if let Some(metric) = self.metric {
709 device.set_metric(metric)?;
710 }
711 #[cfg(target_os = "linux")]
712 if let Some(tx_queue_len) = self.tx_queue_len {
713 device.set_tx_queue_len(tx_queue_len)?;
714 }
715 #[cfg(any(
716 target_os = "linux",
717 target_os = "freebsd",
718 target_os = "macos",
719 target_os = "openbsd",
720 target_os = "netbsd"
721 ))]
722 if let Some(mac_addr) = self.mac_addr {
723 device.set_mac_address(mac_addr)?;
724 }
725
726 if let Some((address, prefix, destination)) = self.ipv4 {
727 let prefix = prefix?;
728 let address = address?;
729 let destination = destination.transpose()?;
730 device.set_network_address(address, prefix, destination)?;
731 }
732 if let Some(ipv6) = self.ipv6 {
733 for (address, prefix) in ipv6 {
734 let prefix = prefix?;
735 let address = address?;
736 device.add_address_v6(address, prefix)?;
737 }
738 }
739 device.enabled(self.enabled.unwrap_or(true))?;
740 Ok(())
741 }
742 pub fn build_sync(mut self) -> io::Result<SyncDevice> {
744 let device = DeviceImpl::new(self.build_config())?;
745 self.config(&device)?;
746 Ok(SyncDevice(device))
747 }
748 #[cfg(any(feature = "async_io", feature = "async_tokio"))]
755 pub fn build_async(self) -> io::Result<crate::AsyncDevice> {
756 let sync_device = self.build_sync()?;
757 let device = crate::AsyncDevice::new_dev(sync_device.0)?;
758 Ok(device)
759 }
760 pub fn with<F: FnMut(&mut DeviceBuilderGuard)>(mut self, mut f: F) -> Self {
786 let mut borrow = DeviceBuilderGuard(&mut self);
787 f(&mut borrow);
788 self
789 }
790}
791
792pub trait ToIpv4Address {
794 fn ipv4(&self) -> io::Result<Ipv4Addr>;
797}
798impl ToIpv4Address for Ipv4Addr {
799 fn ipv4(&self) -> io::Result<Ipv4Addr> {
800 Ok(*self)
801 }
802}
803impl ToIpv4Address for IpAddr {
804 fn ipv4(&self) -> io::Result<Ipv4Addr> {
805 match self {
806 IpAddr::V4(ip) => Ok(*ip),
807 IpAddr::V6(_) => Err(io::Error::new(
808 io::ErrorKind::InvalidData,
809 "invalid address",
810 )),
811 }
812 }
813}
814impl ToIpv4Address for String {
815 fn ipv4(&self) -> io::Result<Ipv4Addr> {
816 self.as_str().ipv4()
817 }
818}
819impl ToIpv4Address for &str {
820 fn ipv4(&self) -> io::Result<Ipv4Addr> {
821 match Ipv4Addr::from_str(self) {
822 Ok(ip) => Ok(ip),
823 Err(_e) => Err(io::Error::new(
824 io::ErrorKind::InvalidData,
825 "invalid IPv4 str",
826 )),
827 }
828 }
829}
830
831pub trait ToIpv6Address {
833 fn ipv6(&self) -> io::Result<Ipv6Addr>;
836}
837
838impl ToIpv6Address for Ipv6Addr {
839 fn ipv6(&self) -> io::Result<Ipv6Addr> {
840 Ok(*self)
841 }
842}
843impl ToIpv6Address for IpAddr {
844 fn ipv6(&self) -> io::Result<Ipv6Addr> {
845 match self {
846 IpAddr::V4(_) => Err(io::Error::new(
847 io::ErrorKind::InvalidData,
848 "invalid address",
849 )),
850 IpAddr::V6(ip) => Ok(*ip),
851 }
852 }
853}
854impl ToIpv6Address for String {
855 fn ipv6(&self) -> io::Result<Ipv6Addr> {
856 self.as_str().ipv6()
857 }
858}
859impl ToIpv6Address for &str {
860 fn ipv6(&self) -> io::Result<Ipv6Addr> {
861 match Ipv6Addr::from_str(self) {
862 Ok(ip) => Ok(ip),
863 Err(_e) => Err(io::Error::new(
864 io::ErrorKind::InvalidData,
865 "invalid IPv6 str",
866 )),
867 }
868 }
869}
870pub trait ToIpv4Netmask {
872 fn prefix(&self) -> io::Result<u8>;
874 fn netmask(&self) -> io::Result<Ipv4Addr> {
876 let ip = u32::MAX
877 .checked_shl(32 - self.prefix()? as u32)
878 .unwrap_or(0);
879 Ok(Ipv4Addr::from(ip))
880 }
881}
882
883impl ToIpv4Netmask for u8 {
884 fn prefix(&self) -> io::Result<u8> {
885 if *self > 32 {
886 return Err(io::Error::new(
887 io::ErrorKind::InvalidData,
888 "invalid IP prefix length",
889 ));
890 }
891 Ok(*self)
892 }
893}
894
895impl ToIpv4Netmask for Ipv4Addr {
896 fn prefix(&self) -> io::Result<u8> {
897 let ip = u32::from_be_bytes(self.octets());
898 if ip.leading_ones() != ip.count_ones() {
900 return Err(io::Error::new(
901 io::ErrorKind::InvalidData,
902 "invalid netmask",
903 ));
904 }
905 Ok(ip.leading_ones() as u8)
906 }
907}
908impl ToIpv4Netmask for String {
909 fn prefix(&self) -> io::Result<u8> {
910 ToIpv4Netmask::prefix(&self.as_str())
911 }
912}
913impl ToIpv4Netmask for &str {
914 fn prefix(&self) -> io::Result<u8> {
915 match Ipv4Addr::from_str(self) {
916 Ok(ip) => ip.prefix(),
917 Err(_e) => Err(io::Error::new(
918 io::ErrorKind::InvalidData,
919 "invalid netmask str",
920 )),
921 }
922 }
923}
924pub trait ToIpv6Netmask {
926 fn prefix(&self) -> io::Result<u8>;
928 fn netmask(&self) -> io::Result<Ipv6Addr> {
930 let ip = u128::MAX
931 .checked_shl(128 - self.prefix()? as u32)
932 .unwrap_or(0);
933 Ok(Ipv6Addr::from(ip))
934 }
935}
936
937impl ToIpv6Netmask for u8 {
938 fn prefix(&self) -> io::Result<u8> {
939 if *self > 128 {
940 return Err(io::Error::new(
941 io::ErrorKind::InvalidData,
942 "invalid IP prefix length",
943 ));
944 }
945 Ok(*self)
946 }
947}
948
949impl ToIpv6Netmask for Ipv6Addr {
950 fn prefix(&self) -> io::Result<u8> {
951 let ip = u128::from_be_bytes(self.octets());
952 if ip.leading_ones() != ip.count_ones() {
953 return Err(io::Error::new(
954 io::ErrorKind::InvalidData,
955 "invalid netmask",
956 ));
957 }
958 Ok(ip.leading_ones() as u8)
959 }
960}
961impl ToIpv6Netmask for String {
962 fn prefix(&self) -> io::Result<u8> {
963 ToIpv6Netmask::prefix(&self.as_str())
964 }
965}
966impl ToIpv6Netmask for &str {
967 fn prefix(&self) -> io::Result<u8> {
968 match Ipv6Addr::from_str(self) {
969 Ok(ip) => ip.prefix(),
970 Err(_e) => Err(io::Error::new(
971 io::ErrorKind::InvalidData,
972 "invalid netmask str",
973 )),
974 }
975 }
976}