1mod arp;
18mod dhcp;
19mod dhcpv6;
20#[cfg_attr(unix, path = "dns_unix.rs")]
21#[cfg_attr(windows, path = "dns_windows.rs")]
22mod dns;
23mod dns_resolver;
24mod icmp;
25mod local_addr_map;
26mod ndp;
27mod tcp;
28mod udp;
29
30mod unix;
31mod windows;
32
33const DNS_PORT: u16 = 53;
35
36const DEFAULT_TCP_BUFFER_BOUNDS: TcpBufferBounds = TcpBufferBounds {
39 initial: 16 * 1024,
40 max: 4 * 1024 * 1024,
41};
42
43pub use dns_resolver::StaticDnsRecord;
44pub use dns_resolver::StaticDnsRecordError;
45use inspect::Inspect;
46use inspect::InspectMut;
47use pal_async::driver::Driver;
48use smoltcp::phy::Checksum;
49use smoltcp::phy::ChecksumCapabilities;
50use smoltcp::wire::DhcpMessageType;
51use smoltcp::wire::EthernetAddress;
52use smoltcp::wire::EthernetFrame;
53use smoltcp::wire::EthernetProtocol;
54use smoltcp::wire::EthernetRepr;
55use smoltcp::wire::IPV4_HEADER_LEN;
56use smoltcp::wire::Icmpv6Message;
57use smoltcp::wire::Icmpv6Packet;
58use smoltcp::wire::IpAddress;
59use smoltcp::wire::IpProtocol;
60pub use smoltcp::wire::IpVersion;
61use smoltcp::wire::Ipv4Address;
62use smoltcp::wire::Ipv4Packet;
63use smoltcp::wire::Ipv6Address;
64use smoltcp::wire::Ipv6Packet;
65use std::net::IpAddr;
66use std::net::Ipv4Addr;
67use std::net::SocketAddr;
68use std::net::SocketAddrV4;
69use std::net::SocketAddrV6;
70use std::task::Context;
71use std::time::Duration;
72use thiserror::Error;
73
74#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
75struct FourTuple {
76 src: SocketAddr,
77 dst: SocketAddr,
78}
79
80impl core::fmt::Display for FourTuple {
81 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82 write!(f, "{}-{}", self.src, self.dst)
83 }
84}
85
86#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
87struct PortForwardKey {
88 family: IpVersion,
89 guest_port: u16,
90}
91
92impl PortForwardKey {
93 fn new(family: IpVersion, guest_port: u16) -> Self {
94 Self { family, guest_port }
95 }
96
97 fn from_socket_addr(addr: SocketAddr, guest_port: u16) -> Self {
98 let family = match addr {
99 SocketAddr::V4(_) => IpVersion::Ipv4,
100 SocketAddr::V6(_) => IpVersion::Ipv6,
101 };
102 Self::new(family, guest_port)
103 }
104}
105
106impl core::fmt::Display for PortForwardKey {
107 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108 write!(f, "{}:{}", self.family, self.guest_port)
109 }
110}
111
112#[derive(InspectMut)]
114pub struct Consomme {
115 state: ConsommeState,
116 #[inspect(mut)]
117 tcp: tcp::Tcp,
118 #[inspect(mut)]
119 udp: udp::Udp,
120 icmp: icmp::Icmp,
121 dns: dns_resolver::DnsResolver,
122 host_has_ipv6: bool,
123}
124
125#[derive(Inspect)]
126struct ConsommeState {
127 params: ConsommeParams,
128 #[inspect(skip)]
129 buffer: Box<[u8]>,
130 local_addr_map: local_addr_map::LocalAddrMap,
131}
132
133#[derive(Inspect, Clone)]
135pub struct ConsommeParams {
136 #[inspect(display)]
138 pub net_mask: Ipv4Address,
139 #[inspect(display)]
141 pub gateway_ip: Ipv4Address,
142 #[inspect(display)]
144 pub gateway_mac: EthernetAddress,
145 #[inspect(display)]
147 pub client_ip: Ipv4Address,
148 #[inspect(display)]
150 pub client_mac: EthernetAddress,
151 #[inspect(with = "|x| inspect::iter_by_index(x).map_value(inspect::AsDisplay)")]
153 pub nameservers: Vec<IpAddress>,
154 pub prefix_len_ipv6: u8,
156 pub advertise_routable_ipv6: bool,
159 #[inspect(display)]
161 pub gateway_mac_ipv6: EthernetAddress,
162 #[inspect(display)]
167 pub gateway_link_local_ipv6: Ipv6Address,
168 #[inspect(with = "|x| x.map(inspect::AsDisplay)")]
174 pub client_ip_ipv6: Option<Ipv6Address>,
175 #[inspect(with = "|x| x.map(inspect::AsDisplay)")]
179 pub client_ip_ipv6_routable: Option<Ipv6Address>,
180 pub udp_timeout: Duration,
182 pub tcp_close_timeout: Duration,
187 pub skip_ipv6_checks: bool,
190 pub allow_host_local_access: bool,
193 pub tcp_rx_buffer: TcpBufferBounds,
195 pub tcp_tx_buffer: TcpBufferBounds,
197}
198
199#[derive(Inspect, Clone, Copy, Debug, PartialEq, Eq)]
211pub struct TcpBufferBounds {
212 pub initial: usize,
214 pub max: usize,
216}
217
218impl TcpBufferBounds {
219 pub const fn fixed(n: usize) -> Self {
221 Self { initial: n, max: n }
222 }
223}
224
225#[derive(Debug, Error)]
227#[error("invalid CIDR")]
228pub struct InvalidCidr;
229
230impl ConsommeParams {
231 pub fn new() -> Result<Self, Error> {
238 let nameservers = dns::nameservers()?;
239 let gateway_mac_ipv6 = EthernetAddress([0x52, 0x55, 0x0A, 0x00, 0x01, 0x02]);
240
241 Ok(Self {
242 gateway_ip: Ipv4Address::new(10, 0, 0, 1),
243 gateway_mac: EthernetAddress([0x52, 0x55, 10, 0, 0, 1]),
244 client_ip: Ipv4Address::new(10, 0, 0, 2),
245 client_mac: EthernetAddress([0x0, 0x0, 0x0, 0x0, 0x1, 0x0]),
246 net_mask: Ipv4Address::new(255, 255, 255, 0),
247 nameservers,
248 prefix_len_ipv6: 64,
249 advertise_routable_ipv6: true,
250 gateway_mac_ipv6,
251 gateway_link_local_ipv6: Self::compute_link_local_address(gateway_mac_ipv6),
252 client_ip_ipv6: None,
253 client_ip_ipv6_routable: None,
254 udp_timeout: Duration::from_secs(300),
256 tcp_close_timeout: Duration::from_secs(60),
258 skip_ipv6_checks: false,
259 allow_host_local_access: false,
260 tcp_rx_buffer: DEFAULT_TCP_BUFFER_BOUNDS,
261 tcp_tx_buffer: DEFAULT_TCP_BUFFER_BOUNDS,
262 })
263 }
264
265 pub fn set_cidr(&mut self, cidr: &str) -> Result<(), InvalidCidr> {
270 let cidr: smoltcp::wire::Ipv4Cidr = cidr.parse().map_err(|()| InvalidCidr)?;
271 let base_address = cidr.network().address();
272 let mut gateway_octets = base_address.octets();
273 gateway_octets[3] += 1;
274 self.gateway_ip = Ipv4Address::from(gateway_octets);
275 let mut client_octets = base_address.octets();
276 client_octets[3] += 2;
277 self.client_ip = Ipv4Address::from(client_octets);
278 self.net_mask = cidr.netmask();
279 Ok(())
280 }
281
282 pub fn compute_link_local_address(mac: EthernetAddress) -> Ipv6Address {
292 const LINK_LOCAL_PREFIX: [u8; 8] = [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
293
294 let mut addr = [0u8; 16];
295
296 addr[0..8].copy_from_slice(&LINK_LOCAL_PREFIX);
298
299 addr[8] = mac.0[0] ^ 0x02; addr[9] = mac.0[1];
304 addr[10] = mac.0[2];
305 addr[11] = 0xFF;
306 addr[12] = 0xFE;
307 addr[13] = mac.0[3];
308 addr[14] = mac.0[4];
309 addr[15] = mac.0[5];
310
311 Ipv6Address::from_octets(addr)
312 }
313
314 pub(crate) fn infer_client_link_local_from_routable(
323 &mut self,
324 routable: Ipv6Address,
325 source: &'static str,
326 ) {
327 if self.client_ip_ipv6.is_some() {
329 return;
330 }
331
332 let link_local = Self::compute_link_local_address(self.client_mac);
333 if routable.octets()[8..] != link_local.octets()[8..] {
334 return;
335 }
336
337 tracing::debug!(
338 client_ipv6 = %link_local,
339 client_ipv6_routable = %routable,
340 source,
341 "inferred client link-local IPv6 address from routable SLAAC address"
342 );
343 self.client_ip_ipv6 = Some(link_local);
344 }
345
346 pub fn filtered_ipv6_nameservers(&self) -> Vec<Ipv6Address> {
353 self.nameservers
354 .iter()
355 .filter_map(|ip| match ip {
356 IpAddress::Ipv6(addr) => Some(*addr),
357 _ => None,
358 })
359 .filter(|addr| {
360 let octets = addr.octets();
361 !(addr.is_unspecified()
362 || addr.is_loopback()
363 || addr.is_multicast()
364 || matches!(octets[0], 0xfc | 0xfd) || octets.starts_with(&[0xfe, 0xc0])) })
367 .collect()
368 }
369
370 fn internal_nameservers(&self, host_has_ipv6: bool) -> Vec<IpAddress> {
374 let mut ns = vec![self.gateway_ip.into()];
375 if host_has_ipv6 {
376 ns.push(self.gateway_link_local_ipv6.into());
377 }
378 ns
379 }
380
381 fn is_local_address(&self, addr: &SocketAddr) -> bool {
382 match addr {
383 SocketAddr::V4(v4) => v4.ip().is_loopback() || v4.ip() == &self.client_ip,
384 SocketAddr::V6(v6) => {
385 v6.ip().is_loopback()
386 || self.client_ip_ipv6.is_some_and(|ip| v6.ip() == &ip)
387 || self
388 .client_ip_ipv6_routable
389 .is_some_and(|ip| v6.ip() == &ip)
390 }
391 }
392 }
393}
394
395impl ConsommeState {
396 fn try_ft_from_remote_address(
397 &mut self,
398 remote_addr: &SocketAddr,
399 dst_port: u16,
400 ) -> Option<FourTuple> {
401 Self::translate_remote_address(
402 &self.params,
403 &mut self.local_addr_map,
404 remote_addr,
405 dst_port,
406 )
407 }
408
409 fn translate_remote_address(
410 params: &ConsommeParams,
411 local_addr_map: &mut local_addr_map::LocalAddrMap,
412 remote_addr: &SocketAddr,
413 dst_port: u16,
414 ) -> Option<FourTuple> {
415 let dst = match remote_addr {
417 SocketAddr::V4(_) => SocketAddr::V4(SocketAddrV4::new(params.client_ip, dst_port)),
418 SocketAddr::V6(v6) => {
419 let client_ipv6 = if !v6.ip().is_unicast_link_local()
420 && let Some(routable) = params.client_ip_ipv6_routable
421 {
422 routable
423 } else if let Some(ipv6) = params.client_ip_ipv6 {
424 ipv6
425 } else if let Some(routable) = params.client_ip_ipv6_routable {
426 routable
427 } else {
428 tracelimit::warn_ratelimited!(addr = %remote_addr, "Client IPv6 address is not known, dropping packet");
429 return None;
430 };
431
432 SocketAddr::V6(SocketAddrV6::new(client_ipv6, dst_port, 0, 0))
433 }
434 };
435
436 let is_loopback_adapter = params.client_ip.is_loopback();
448 let src = match remote_addr {
449 SocketAddr::V4(v4) if params.is_local_address(remote_addr) && !is_loopback_adapter => {
450 let subnet_base =
451 Ipv4Addr::from(u32::from(params.gateway_ip) & u32::from(params.net_mask));
452 let virtual_ip = local_addr_map.get_or_allocate_v4(
453 *v4.ip(),
454 subnet_base,
455 params.net_mask,
456 params.gateway_ip,
457 params.client_ip,
458 );
459 match virtual_ip {
460 Some(ip) => SocketAddr::V4(SocketAddrV4::new(ip, v4.port())),
461 None => {
462 SocketAddr::V4(SocketAddrV4::new(params.gateway_ip, v4.port()))
464 }
465 }
466 }
467 SocketAddr::V6(v6) if params.is_local_address(remote_addr) && !is_loopback_adapter => {
468 let virtual_ip = local_addr_map.get_or_allocate_v6(
469 *v6.ip(),
470 params.gateway_link_local_ipv6,
471 params.client_ip_ipv6,
472 params.client_ip_ipv6_routable,
473 );
474 match virtual_ip {
475 Some(ip) => SocketAddr::V6(SocketAddrV6::new(ip, v6.port(), 0, 0)),
476 None => {
477 SocketAddr::V6(SocketAddrV6::new(
479 params.gateway_link_local_ipv6,
480 v6.port(),
481 0,
482 0,
483 ))
484 }
485 }
486 }
487 SocketAddr::V6(v6) => {
488 SocketAddr::V6(SocketAddrV6::new(*v6.ip(), v6.port(), 0, 0))
490 }
491 _ => *remote_addr,
492 };
493
494 Some(FourTuple { src, dst })
495 }
496
497 fn resolve_destination(&self, addr: &SocketAddr) -> SocketAddr {
501 let ip = addr.ip();
502 if let Some(real_ip) = self.local_addr_map.resolve_virtual(&ip) {
503 SocketAddr::new(real_ip, addr.port())
504 } else {
505 *addr
506 }
507 }
508}
509
510pub struct Access<'a, T> {
512 inner: &'a mut Consomme,
513 client: &'a mut T,
514}
515
516pub trait Client {
518 fn driver(&self) -> &dyn Driver;
523
524 fn recv(&mut self, data: &[u8], checksum: &ChecksumState);
532
533 fn recv_segments(&mut self, segments: &[&[u8]], checksum: &ChecksumState) {
545 if let [segment] = segments {
546 self.recv(segment, checksum);
547 return;
548 }
549 let total = segments.iter().map(|s| s.len()).sum();
550 let mut data = Vec::with_capacity(total);
551 for segment in segments {
552 data.extend_from_slice(segment);
553 }
554 self.recv(&data, checksum);
555 }
556
557 fn rx_mtu(&mut self) -> usize;
565}
566
567#[derive(Debug, Copy, Clone)]
569pub struct ChecksumState {
570 pub ipv4: bool,
573 pub tcp: bool,
576 pub udp: bool,
579 pub tso: Option<u16>,
584 pub gso: Option<u16>,
587}
588
589impl ChecksumState {
590 const NONE: Self = Self {
591 ipv4: false,
592 tcp: false,
593 udp: false,
594 tso: None,
595 gso: None,
596 };
597 const IPV4_ONLY: Self = Self {
598 ipv4: true,
599 tcp: false,
600 udp: false,
601 tso: None,
602 gso: None,
603 };
604 const TCP4: Self = Self {
605 ipv4: true,
606 tcp: true,
607 udp: false,
608 tso: None,
609 gso: None,
610 };
611 const UDP4: Self = Self {
612 ipv4: true,
613 tcp: false,
614 udp: true,
615 tso: None,
616 gso: None,
617 };
618 const TCP6: Self = Self {
619 ipv4: false,
620 tcp: true,
621 udp: false,
622 tso: None,
623 gso: None,
624 };
625
626 fn caps(&self) -> ChecksumCapabilities {
627 let mut caps = ChecksumCapabilities::default();
628 if self.ipv4 {
629 caps.ipv4 = Checksum::None;
630 }
631 if self.tcp {
632 caps.tcp = Checksum::None;
633 }
634 if self.udp {
635 caps.udp = Checksum::None;
636 }
637 caps
638 }
639}
640
641pub const MIN_MTU: usize = 1514;
644
645#[derive(Debug, Error)]
647pub enum DropReason {
648 #[error("packet parsing error")]
650 Packet(#[from] smoltcp::wire::Error),
651 #[error("unsupported ethertype {0}")]
653 UnsupportedEthertype(EthernetProtocol),
654 #[error("unsupported ip protocol {0}")]
656 UnsupportedIpProtocol(IpProtocol),
657 #[error("unsupported icmpv6 message type {0}")]
659 UnsupportedIcmpv6(Icmpv6Message),
660 #[error("unsupported dhcp message type {0:?}")]
662 UnsupportedDhcp(DhcpMessageType),
663 #[error("unsupported arp type")]
665 UnsupportedArp,
666 #[error("ipv4 checksum failure")]
668 Ipv4Checksum,
669 #[error("send buffer full")]
671 SendBufferFull,
672 #[error("io error")]
674 Io(#[source] std::io::Error),
675 #[error("bad tcp state")]
677 BadTcpState(#[from] tcp::TcpError),
678 #[error("unsupported dhcpv6 message type {0:?}")]
680 UnsupportedDhcpv6(dhcpv6::MessageType),
681 #[error("unsupported ndp message type {0:?}")]
683 UnsupportedNdp(ndp::NdpMessageType),
684 #[error("packet is malformed")]
687 MalformedPacket,
688 #[error("ip length mismatch")]
690 IpLengthMismatch,
691 #[error("packet fragmentation is not supported")]
694 FragmentedPacket,
695 #[error("destination address not allowed")]
698 DestinationNotAllowed,
699}
700
701#[derive(Debug, Error)]
703pub enum BindError {
704 #[error("port {0} is already bound")]
706 PortAlreadyBound(u16),
707 #[error("port is not bound")]
709 PortNotBound,
710 #[error(transparent)]
712 Io(std::io::Error),
713}
714
715#[derive(Debug, Error)]
717pub enum Error {
718 #[error("failed to initialize nameservers")]
720 Dns(#[from] dns::Error),
721}
722
723#[derive(Debug)]
724struct Ipv4Addresses {
725 src_addr: Ipv4Address,
726 dst_addr: Ipv4Address,
727}
728
729#[derive(Debug)]
730struct Ipv6Addresses {
731 src_addr: Ipv6Address,
732 dst_addr: Ipv6Address,
733}
734
735#[derive(Debug)]
736enum IpAddresses {
737 V4(Ipv4Addresses),
738 V6(Ipv6Addresses),
739}
740
741impl IpAddresses {
742 fn src_addr(&self) -> IpAddress {
743 match self {
744 IpAddresses::V4(addrs) => IpAddress::Ipv4(addrs.src_addr),
745 IpAddresses::V6(addrs) => IpAddress::Ipv6(addrs.src_addr),
746 }
747 }
748
749 fn dst_addr(&self) -> IpAddress {
750 match self {
751 IpAddresses::V4(addrs) => IpAddress::Ipv4(addrs.dst_addr),
752 IpAddresses::V6(addrs) => IpAddress::Ipv6(addrs.dst_addr),
753 }
754 }
755}
756
757fn is_blocked_host_local_ipv4(addr: Ipv4Address) -> bool {
761 addr.is_loopback() || addr.is_unspecified() || addr.is_link_local()
762}
763
764fn is_blocked_host_local_ipv6(addr: Ipv6Address) -> bool {
768 addr.is_loopback() || addr.is_unspecified() || addr.is_unicast_link_local()
769}
770
771pub(crate) fn is_same_ipv4_subnet(
773 addr1: Ipv4Address,
774 addr2: Ipv4Address,
775 subnet_mask: Ipv4Address,
776) -> bool {
777 let subnet_mask = subnet_mask.to_bits();
778 (addr1.to_bits() & subnet_mask) == (addr2.to_bits() & subnet_mask)
779}
780
781pub(crate) fn is_same_ipv6_subnet(addr1: Ipv6Address, addr2: Ipv6Address, prefix_len: u8) -> bool {
783 if prefix_len == 0 {
784 return true;
785 }
786 if prefix_len >= 128 {
787 return addr1 == addr2;
788 }
789 let mask = u128::MAX << (128 - prefix_len);
790 (addr1.to_bits() & mask) == (addr2.to_bits() & mask)
791}
792
793fn is_routable_ipv6(addr: &std::net::Ipv6Addr) -> bool {
796 !addr.is_loopback() && !addr.is_unspecified() && !addr.is_unicast_link_local()
797}
798
799impl Consomme {
800 pub fn new(mut params: ConsommeParams) -> Self {
802 let host_has_ipv6 = if params.skip_ipv6_checks {
803 true
804 } else {
805 #[cfg(windows)]
806 let host_has_ipv6_result = windows::host_has_ipv6_address().map_err(|e| e.to_string());
807 #[cfg(unix)]
808 let host_has_ipv6_result = unix::host_has_ipv6_address().map_err(|e| e.to_string());
809
810 match host_has_ipv6_result {
811 Ok(has_ipv6) => has_ipv6,
812 Err(e) => {
813 tracelimit::warn_ratelimited!(
814 "failed to check for host IPv6 address, assuming no IPv6 support: {e}"
815 );
816 false
817 }
818 }
819 };
820 let dns =
821 match dns_resolver::DnsResolver::new(dns_resolver::DEFAULT_MAX_PENDING_DNS_REQUESTS) {
822 Ok(dns) => {
823 params.nameservers = params.internal_nameservers(host_has_ipv6);
825 dns
826 }
827 Err(_) => {
828 tracelimit::warn_ratelimited!(
829 "failed to initialize DNS resolver, falling back to using host DNS settings"
830 );
831 dns_resolver::DnsResolver::without_backend(
832 dns_resolver::DEFAULT_MAX_PENDING_DNS_REQUESTS,
833 )
834 }
835 };
836 let tcp_rx_buffer = params.tcp_rx_buffer;
837 let tcp_tx_buffer = params.tcp_tx_buffer;
838 let udp_timeout = params.udp_timeout;
839 Self {
840 state: ConsommeState {
841 params,
842 buffer: Box::new([0; 65536]),
843 local_addr_map: local_addr_map::LocalAddrMap::new(),
844 },
845 tcp: tcp::Tcp::new(tcp_rx_buffer, tcp_tx_buffer),
846 udp: udp::Udp::new(udp_timeout),
847 icmp: icmp::Icmp::new(),
848 dns,
849 host_has_ipv6,
850 }
851 }
852
853 pub fn params_mut(&mut self) -> &mut ConsommeParams {
858 &mut self.state.params
859 }
860
861 pub fn clear_local_addr_map(&mut self) {
868 self.state.local_addr_map.clear();
869 }
870
871 pub fn add_dns_record(
874 &mut self,
875 record: StaticDnsRecord,
876 name: &str,
877 ) -> Result<(), StaticDnsRecordError> {
878 self.dns.add_static_record(record, name)
879 }
880
881 pub fn create_virtual_address(&mut self, destination: IpAddr) -> Option<IpAddr> {
885 match destination {
886 IpAddr::V4(destination) => {
887 let net_mask = self.state.params.net_mask;
888 let gateway_ip = self.state.params.gateway_ip;
889 let client_ip = self.state.params.client_ip;
890 let subnet_base = Ipv4Addr::from(u32::from(gateway_ip) & u32::from(net_mask));
891 self.state
892 .local_addr_map
893 .get_or_allocate_v4(destination, subnet_base, net_mask, gateway_ip, client_ip)
894 .map(IpAddr::V4)
895 }
896 IpAddr::V6(destination) => {
897 let gateway_ll = self.state.params.gateway_link_local_ipv6;
898 let client_ll = self.state.params.client_ip_ipv6;
899 let client_routable = self.state.params.client_ip_ipv6_routable;
900 self.state
901 .local_addr_map
902 .get_or_allocate_v6(destination, gateway_ll, client_ll, client_routable)
903 .map(IpAddr::V6)
904 }
905 }
906 }
907
908 pub fn access<'a, T: Client>(&'a mut self, client: &'a mut T) -> Access<'a, T> {
910 Access {
911 inner: self,
912 client,
913 }
914 }
915}
916
917impl<T: Client> Access<'_, T> {
918 pub fn get(&self) -> &Consomme {
920 self.inner
921 }
922
923 pub fn get_mut(&mut self) -> &mut Consomme {
925 self.inner
926 }
927
928 pub fn poll(&mut self, cx: &mut Context<'_>) {
930 self.poll_udp(cx);
931 self.poll_tcp(cx);
932 self.poll_icmp(cx);
933 }
934
935 pub fn refresh_driver(&mut self) {
939 self.refresh_tcp_driver();
940 self.refresh_udp_driver();
941 }
942
943 pub fn send(&mut self, data: &[u8], checksum: &ChecksumState) -> Result<(), DropReason> {
973 let frame_packet = EthernetFrame::new_unchecked(data);
974 let frame = EthernetRepr::parse(&frame_packet)?;
975 match frame.ethertype {
976 EthernetProtocol::Ipv4 => self.handle_ipv4(&frame, frame_packet.payload(), checksum)?,
977 EthernetProtocol::Ipv6 => {
978 if self.inner.host_has_ipv6 {
979 self.handle_ipv6(&frame, frame_packet.payload(), checksum)?
980 }
981 }
982 EthernetProtocol::Arp => self.handle_arp(&frame, frame_packet.payload())?,
983 _ => return Err(DropReason::UnsupportedEthertype(frame.ethertype)),
984 }
985 Ok(())
986 }
987
988 fn handle_ipv4(
989 &mut self,
990 frame: &EthernetRepr,
991 payload: &[u8],
992 checksum: &ChecksumState,
993 ) -> Result<(), DropReason> {
994 let ipv4 = Ipv4Packet::new_unchecked(payload);
995 if payload.len() < IPV4_HEADER_LEN
996 || ipv4.version() != 4
997 || payload.len() < ipv4.header_len().into()
998 {
999 return Err(DropReason::MalformedPacket);
1000 }
1001
1002 let segmentation_offload = checksum.tso.is_some() || checksum.gso.is_some();
1007 if !segmentation_offload && payload.len() < ipv4.total_len().into() {
1008 return Err(DropReason::IpLengthMismatch);
1009 }
1010
1011 let total_len = if segmentation_offload {
1012 payload.len()
1013 } else {
1014 ipv4.total_len().into()
1015 };
1016 if total_len < ipv4.header_len().into() {
1017 return Err(DropReason::MalformedPacket);
1018 }
1019
1020 if ipv4.more_frags() || ipv4.frag_offset() != 0 {
1021 return Err(DropReason::FragmentedPacket);
1022 }
1023
1024 if !checksum.ipv4 && !ipv4.verify_checksum() {
1025 return Err(DropReason::Ipv4Checksum);
1026 }
1027
1028 if !self.inner.state.params.allow_host_local_access
1030 && is_blocked_host_local_ipv4(ipv4.dst_addr())
1031 {
1032 return Err(DropReason::DestinationNotAllowed);
1033 }
1034
1035 let addresses = Ipv4Addresses {
1036 src_addr: ipv4.src_addr(),
1037 dst_addr: ipv4.dst_addr(),
1038 };
1039
1040 let inner = &payload[ipv4.header_len().into()..total_len];
1041
1042 match ipv4.next_header() {
1043 IpProtocol::Tcp => self.handle_tcp(&IpAddresses::V4(addresses), inner, checksum)?,
1044 IpProtocol::Udp => {
1045 self.handle_udp(frame, &IpAddresses::V4(addresses), inner, checksum)?
1046 }
1047 IpProtocol::Icmp => {
1048 self.handle_icmp(frame, &addresses, inner, checksum, ipv4.hop_limit())?
1049 }
1050 p => return Err(DropReason::UnsupportedIpProtocol(p)),
1051 };
1052 Ok(())
1053 }
1054
1055 fn handle_ipv6(
1056 &mut self,
1057 frame: &EthernetRepr,
1058 payload: &[u8],
1059 checksum: &ChecksumState,
1060 ) -> Result<(), DropReason> {
1061 let ipv6 = Ipv6Packet::new_unchecked(payload);
1062 if payload.len() < smoltcp::wire::IPV6_HEADER_LEN || ipv6.version() != 6 {
1063 return Err(DropReason::MalformedPacket);
1064 }
1065
1066 let segmentation_offload = checksum.tso.is_some() || checksum.gso.is_some();
1070 if !segmentation_offload {
1071 let required_len = smoltcp::wire::IPV6_HEADER_LEN + ipv6.payload_len() as usize;
1072 if payload.len() < required_len {
1073 return Err(DropReason::MalformedPacket);
1074 }
1075 }
1076
1077 if !self.inner.state.params.allow_host_local_access
1079 && is_blocked_host_local_ipv6(ipv6.dst_addr())
1080 {
1081 return Err(DropReason::DestinationNotAllowed);
1082 }
1083
1084 let next_header = ipv6.next_header();
1085 let src_addr = ipv6.src_addr();
1086 let inner = &payload[smoltcp::wire::IPV6_HEADER_LEN..];
1087 let addresses = Ipv6Addresses {
1088 src_addr,
1089 dst_addr: ipv6.dst_addr(),
1090 };
1091
1092 if src_addr.is_unicast_link_local()
1095 && self.inner.state.params.client_ip_ipv6 != Some(src_addr)
1096 {
1097 tracing::debug!(
1098 client_ipv6 = %src_addr,
1099 "learned client link-local IPv6 address from outgoing traffic"
1100 );
1101 self.inner.state.params.client_ip_ipv6 = Some(src_addr);
1102 }
1103
1104 if !src_addr.is_unspecified()
1108 && !src_addr.is_multicast()
1109 && !src_addr.is_unicast_link_local()
1110 && self.inner.state.params.client_ip_ipv6_routable != Some(src_addr)
1111 {
1112 tracing::debug!(
1113 client_ipv6_routable = %src_addr,
1114 "learned client routable IPv6 address from outgoing traffic"
1115 );
1116 self.inner.state.params.client_ip_ipv6_routable = Some(src_addr);
1117 self.inner
1118 .state
1119 .params
1120 .infer_client_link_local_from_routable(src_addr, "outgoing traffic");
1121 }
1122
1123 match next_header {
1124 IpProtocol::Udp => {
1125 self.handle_udp(frame, &IpAddresses::V6(addresses), inner, checksum)?
1126 }
1127 IpProtocol::Tcp => self.handle_tcp(&IpAddresses::V6(addresses), inner, checksum)?,
1128 IpProtocol::Icmpv6 => {
1129 let icmpv6_packet = Icmpv6Packet::new_unchecked(inner);
1131 let msg_type = icmpv6_packet.msg_type();
1132
1133 if msg_type.is_ndisc() {
1134 self.handle_ndp(frame, inner, ipv6.src_addr())?;
1135 } else {
1136 tracing::trace!(
1137 icmpv6_type = %msg_type,
1138 src_addr = %src_addr,
1139 dst_addr = %addresses.dst_addr,
1140 "unsupported ICMPv6 message"
1141 );
1142 return Err(DropReason::UnsupportedIcmpv6(msg_type));
1143 }
1144 }
1145
1146 p => return Err(DropReason::UnsupportedIpProtocol(p)),
1147 };
1148 Ok(())
1149 }
1150
1151 pub fn update_dns_nameservers(&mut self) {
1153 if self.inner.dns.is_available() {
1154 self.inner.state.params.nameservers = self
1155 .inner
1156 .state
1157 .params
1158 .internal_nameservers(self.inner.host_has_ipv6);
1159 }
1160 }
1161}
1162
1163#[cfg(test)]
1164mod tests;