1
1
use super :: * ;
2
2
3
- #[ cfg( feature = "socket-icmp" ) ]
4
- use crate :: socket:: icmp;
5
- use crate :: socket:: AnySocket ;
6
-
7
- use crate :: phy:: PacketMeta ;
8
- use crate :: wire:: * ;
9
-
10
3
/// Enum used for the process_hopbyhop function. In some cases, when discarding a packet, an ICMMP
11
4
/// parameter problem message needs to be transmitted to the source of the address. In other cases,
12
5
/// the processing of the IP packet can continue.
@@ -26,6 +19,133 @@ impl Default for HopByHopResponse<'_> {
26
19
}
27
20
28
21
impl InterfaceInner {
22
+ /// Return the IPv6 address that is a candidate source address for the given destination
23
+ /// address, based on RFC 6724.
24
+ #[ allow( unused) ]
25
+ pub ( crate ) fn get_source_address_ipv6 ( & self , dst_addr : & Ipv6Address ) -> Option < Ipv6Address > {
26
+ // See RFC 6724 Section 4: Candidate source address
27
+ fn is_candidate_source_address ( dst_addr : & Ipv6Address , src_addr : & Ipv6Address ) -> bool {
28
+ // For all multicast and link-local destination addresses, the candidate address MUST
29
+ // only be an address from the same link.
30
+ if dst_addr. is_link_local ( ) && !src_addr. is_link_local ( ) {
31
+ return false ;
32
+ }
33
+
34
+ if dst_addr. is_multicast ( )
35
+ && matches ! ( dst_addr. scope( ) , Ipv6AddressScope :: LinkLocal )
36
+ && src_addr. is_multicast ( )
37
+ && !matches ! ( src_addr. scope( ) , Ipv6AddressScope :: LinkLocal )
38
+ {
39
+ return false ;
40
+ }
41
+
42
+ // Loopback addresses and multicast address can not be in the candidate source address
43
+ // list. Except when the destination multicast address has a link-local scope, then the
44
+ // source address can also be link-local multicast.
45
+ if src_addr. is_loopback ( ) || src_addr. is_multicast ( ) {
46
+ return false ;
47
+ }
48
+
49
+ true
50
+ }
51
+
52
+ // See RFC 6724 Section 2.2: Common Prefix Length
53
+ fn common_prefix_length ( dst_addr : & Ipv6Cidr , src_addr : & Ipv6Address ) -> usize {
54
+ let addr = dst_addr. address ( ) ;
55
+ let mut bits = 0 ;
56
+ for ( l, r) in addr. as_bytes ( ) . iter ( ) . zip ( src_addr. as_bytes ( ) . iter ( ) ) {
57
+ if l == r {
58
+ bits += 8 ;
59
+ } else {
60
+ bits += ( l ^ r) . leading_zeros ( ) ;
61
+ break ;
62
+ }
63
+ }
64
+
65
+ bits = bits. min ( dst_addr. prefix_len ( ) as u32 ) ;
66
+
67
+ bits as usize
68
+ }
69
+
70
+ // Get the first address that is a candidate address.
71
+ let mut candidate = self
72
+ . ip_addrs
73
+ . iter ( )
74
+ . filter_map ( |a| match a {
75
+ #[ cfg( feature = "proto-ipv4" ) ]
76
+ IpCidr :: Ipv4 ( _) => None ,
77
+ #[ cfg( feature = "proto-ipv6" ) ]
78
+ IpCidr :: Ipv6 ( a) => Some ( a) ,
79
+ } )
80
+ . find ( |a| is_candidate_source_address ( dst_addr, & a. address ( ) ) )
81
+ . unwrap ( ) ;
82
+
83
+ for addr in self . ip_addrs . iter ( ) . filter_map ( |a| match a {
84
+ #[ cfg( feature = "proto-ipv4" ) ]
85
+ IpCidr :: Ipv4 ( _) => None ,
86
+ #[ cfg( feature = "proto-ipv6" ) ]
87
+ IpCidr :: Ipv6 ( a) => Some ( a) ,
88
+ } ) {
89
+ if !is_candidate_source_address ( dst_addr, & addr. address ( ) ) {
90
+ continue ;
91
+ }
92
+
93
+ // Rule 1: prefer the address that is the same as the output destination address.
94
+ if candidate. address ( ) != * dst_addr && addr. address ( ) == * dst_addr {
95
+ candidate = addr;
96
+ }
97
+
98
+ // Rule 2: prefer appropriate scope.
99
+ if ( candidate. address ( ) . scope ( ) as u8 ) < ( addr. address ( ) . scope ( ) as u8 ) {
100
+ if ( candidate. address ( ) . scope ( ) as u8 ) < ( dst_addr. scope ( ) as u8 ) {
101
+ candidate = addr;
102
+ }
103
+ } else if ( addr. address ( ) . scope ( ) as u8 ) > ( dst_addr. scope ( ) as u8 ) {
104
+ candidate = addr;
105
+ }
106
+
107
+ // Rule 3: avoid deprecated addresses (TODO)
108
+ // Rule 4: prefer home addresses (TODO)
109
+ // Rule 5: prefer outgoing interfaces (TODO)
110
+ // Rule 5.5: prefer addresses in a prefix advertises by the next-hop (TODO).
111
+ // Rule 6: prefer matching label (TODO)
112
+ // Rule 7: prefer temporary addresses (TODO)
113
+ // Rule 8: use longest matching prefix
114
+ if common_prefix_length ( candidate, dst_addr) < common_prefix_length ( addr, dst_addr) {
115
+ candidate = addr;
116
+ }
117
+ }
118
+
119
+ Some ( candidate. address ( ) )
120
+ }
121
+
122
+ /// Determine if the given `Ipv6Address` is the solicited node
123
+ /// multicast address for a IPv6 addresses assigned to the interface.
124
+ /// See [RFC 4291 § 2.7.1] for more details.
125
+ ///
126
+ /// [RFC 4291 § 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
127
+ pub fn has_solicited_node ( & self , addr : Ipv6Address ) -> bool {
128
+ self . ip_addrs . iter ( ) . any ( |cidr| {
129
+ match * cidr {
130
+ IpCidr :: Ipv6 ( cidr) if cidr. address ( ) != Ipv6Address :: LOOPBACK => {
131
+ // Take the lower order 24 bits of the IPv6 address and
132
+ // append those bits to FF02:0:0:0:0:1:FF00::/104.
133
+ addr. as_bytes ( ) [ 14 ..] == cidr. address ( ) . as_bytes ( ) [ 14 ..]
134
+ }
135
+ _ => false ,
136
+ }
137
+ } )
138
+ }
139
+
140
+ /// Get the first IPv6 address if present.
141
+ pub fn ipv6_addr ( & self ) -> Option < Ipv6Address > {
142
+ self . ip_addrs . iter ( ) . find_map ( |addr| match * addr {
143
+ IpCidr :: Ipv6 ( cidr) => Some ( cidr. address ( ) ) ,
144
+ #[ allow( unreachable_patterns) ]
145
+ _ => None ,
146
+ } )
147
+ }
148
+
29
149
pub ( super ) fn process_ipv6 < ' frame > (
30
150
& mut self ,
31
151
sockets : & mut SocketSet ,
@@ -191,13 +311,16 @@ impl InterfaceInner {
191
311
let mut handled_by_icmp_socket = false ;
192
312
193
313
#[ cfg( feature = "socket-icmp" ) ]
194
- for icmp_socket in _sockets
195
- . items_mut ( )
196
- . filter_map ( |i| icmp:: Socket :: downcast_mut ( & mut i. socket ) )
197
314
{
198
- if icmp_socket. accepts ( self , & ip_repr, & icmp_repr. into ( ) ) {
199
- icmp_socket. process ( self , & ip_repr, & icmp_repr. into ( ) ) ;
200
- handled_by_icmp_socket = true ;
315
+ use crate :: socket:: icmp:: Socket as IcmpSocket ;
316
+ for icmp_socket in _sockets
317
+ . items_mut ( )
318
+ . filter_map ( |i| IcmpSocket :: downcast_mut ( & mut i. socket ) )
319
+ {
320
+ if icmp_socket. accepts ( self , & ip_repr, & icmp_repr. into ( ) ) {
321
+ icmp_socket. process ( self , & ip_repr, & icmp_repr. into ( ) ) ;
322
+ handled_by_icmp_socket = true ;
323
+ }
201
324
}
202
325
}
203
326
0 commit comments