@@ -50,7 +50,7 @@ impl IcmpSocket {
5050impl SocketTrait for IcmpSocket {
5151 fn send_to ( & self , buffer : & mut [ u8 ] , to : & SocketAddr ) -> io:: Result < usize > {
5252 let buffer_with_header = unsafe { slice_sub ( buffer, ICMP_HEADER_LEN ) } ;
53- craft_icmp_packet ( buffer_with_header, & self . udp_socket_addr , to) ;
53+ craft_icmp_packet ( buffer_with_header, & self . udp_socket_addr , to, true ) ;
5454 let mut to_addr = * to;
5555 // in linux `send_to` on icmpv6 socket requires destination port to be zero
5656 to_addr. set_port ( 0 ) ;
@@ -70,7 +70,7 @@ impl SocketTrait for IcmpSocket {
7070 . socket
7171 . recv_from ( cast_maybe_uninit ( buffer_with_header) ) ?;
7272 let icmp_packet = & mut buffer_with_header[ icmp_header_offset..size] ;
73- let Some ( packet) = parse_icmp_packet ( icmp_packet, local_addr. is_ipv6 ( ) ) else {
73+ let Some ( packet) = parse_icmp_packet ( icmp_packet, local_addr. is_ipv6 ( ) , false ) else {
7474 continue ;
7575 } ;
7676 if packet. dst_port != local_addr. port ( ) {
@@ -120,6 +120,7 @@ impl NonBlockingSocketTrait for NonBlockingIcmpSocket {
120120 buffer_with_header,
121121 & self . icmp_socket . udp_socket_addr ,
122122 & dst_addr,
123+ false ,
123124 ) ;
124125 self . icmp_socket . socket . send ( buffer_with_header)
125126 }
@@ -140,21 +141,37 @@ impl NonBlockingSocketTrait for NonBlockingIcmpSocket {
140141
141142fn craft_icmp_packet (
142143 buffer_with_header : & mut [ u8 ] ,
143- source_addr : & SocketAddr ,
144+ src_addr : & SocketAddr ,
144145 dst_addr : & SocketAddr ,
146+ is_echo_reply : bool ,
145147) {
146148 let mut icmp_packet = Icmpv4Packet :: new_unchecked ( buffer_with_header) ;
147- icmp_packet. set_echo_ident ( dst_addr. port ( ) ) ;
148- icmp_packet. set_echo_seq_no ( source_addr. port ( ) ) ;
149+ // point of this is to make sure echo ident of request and corresponding reply
150+ // remains the same, so nat could figure out who are we talking to
151+ let ( ident, seq) = if is_echo_reply {
152+ ( dst_addr. port ( ) , src_addr. port ( ) )
153+ } else {
154+ ( src_addr. port ( ) , dst_addr. port ( ) )
155+ } ;
156+ icmp_packet. set_echo_ident ( ident) ;
157+ icmp_packet. set_echo_seq_no ( seq) ;
149158 icmp_packet. set_msg_code ( 0 ) ;
150159
151- if source_addr. is_ipv4 ( ) {
152- icmp_packet. set_msg_type ( Icmpv4Message :: EchoRequest ) ;
160+ if src_addr. is_ipv4 ( ) {
161+ icmp_packet. set_msg_type ( if is_echo_reply {
162+ Icmpv4Message :: EchoReply
163+ } else {
164+ Icmpv4Message :: EchoRequest
165+ } ) ;
153166 icmp_packet. fill_checksum ( ) ;
154167 } else {
155168 let mut icmp_packet = Icmpv6Packet :: new_unchecked ( icmp_packet. into_inner ( ) ) ;
156- icmp_packet. set_msg_type ( Icmpv6Message :: EchoRequest ) ;
157- icmp_packet. fill_checksum ( as_ipv6 ( & source_addr. ip ( ) ) , as_ipv6 ( & dst_addr. ip ( ) ) ) ;
169+ icmp_packet. set_msg_type ( if is_echo_reply {
170+ Icmpv6Message :: EchoReply
171+ } else {
172+ Icmpv6Message :: EchoRequest
173+ } ) ;
174+ icmp_packet. fill_checksum ( as_ipv6 ( & src_addr. ip ( ) ) , as_ipv6 ( & dst_addr. ip ( ) ) ) ;
158175 }
159176}
160177
@@ -163,14 +180,22 @@ pub struct IcmpPacket {
163180 pub dst_port : u16 ,
164181}
165182
166- pub fn parse_icmp_packet ( packet : & [ u8 ] , is_ipv6 : bool ) -> Option < IcmpPacket > {
183+ pub fn parse_icmp_packet ( packet : & [ u8 ] , is_ipv6 : bool , is_echo_reply : bool ) -> Option < IcmpPacket > {
167184 let icmp_packet = Icmpv4Packet :: new_checked ( packet) . ok ( ) ?;
168185
169186 // we only work with icmp echo requests so if any other type of icmp
170187 // packet we receive we just ignore it
188+ // TODO: maybe always check for both reply or request
171189 let correct_type = if is_ipv6 {
172- // icmpv6 echo request
173- Icmpv4Message :: Unknown ( 0x80 )
190+ if is_echo_reply {
191+ // icmpv6 echo reply
192+ Icmpv4Message :: Unknown ( 0x81 )
193+ } else {
194+ // icmpv6 echo request
195+ Icmpv4Message :: Unknown ( 0x80 )
196+ }
197+ } else if is_echo_reply {
198+ Icmpv4Message :: EchoReply
174199 } else {
175200 Icmpv4Message :: EchoRequest
176201 } ;
@@ -180,8 +205,14 @@ pub fn parse_icmp_packet(packet: &[u8], is_ipv6: bool) -> Option<IcmpPacket> {
180205
181206 // icmp is on layer 3 so it has no idea about ports
182207 // we use identifier and sequence number of icmp packet as ports
183- let dst_port = icmp_packet. echo_ident ( ) ;
184- let src_port = icmp_packet. echo_seq_no ( ) ;
208+ let ident = icmp_packet. echo_ident ( ) ;
209+ let seq = icmp_packet. echo_seq_no ( ) ;
210+
211+ let ( src_port, dst_port) = if is_echo_reply {
212+ ( seq, ident)
213+ } else {
214+ ( ident, seq)
215+ } ;
185216 Some ( IcmpPacket { src_port, dst_port } )
186217}
187218
0 commit comments