@@ -11,7 +11,6 @@ import (
1111 "github.com/celzero/firestack/intra/settings"
1212 "gvisor.dev/gvisor/pkg/buffer"
1313 "gvisor.dev/gvisor/pkg/tcpip"
14- "gvisor.dev/gvisor/pkg/tcpip/checksum"
1514 "gvisor.dev/gvisor/pkg/tcpip/header"
1615 "gvisor.dev/gvisor/pkg/tcpip/stack"
1716)
@@ -144,38 +143,54 @@ func (r *icmpResponder) handle(b buffer.Buffer) (handled bool) {
144143func (r * icmpResponder ) process (h GICMPHandler , pkt * wire.Parsed , src , dst netip.AddrPort ) {
145144 defer wire .Pool .Put (pkt )
146145
147- payload := pkt .Transport ()
148- if len ( payload ) == 0 {
146+ payload , ok := pkt .Payload ()
147+ if ! ok {
149148 return
150149 }
151150
152- if ! h . Ping ( payload , src , dst ) {
153- // Ping failed; nothing to inject back.
151+ icmpMsg := pkt . Transport ()
152+ if len ( icmpMsg ) == 0 {
154153 return
155154 }
156155
157- var resp []byte
158- var proto tcpip.NetworkProtocolNumber
159- var err error
156+ pinged := h .Ping (icmpMsg , src , dst )
160157
158+ resp , proto , err := r .makeReply (pkt , payload , pinged )
159+ if err != nil || len (resp ) == 0 {
160+ log .W ("icmp: responder: reply %s <= %s (sz: %d); ping? %t; err? %v" ,
161+ src , dst , len (resp ), pinged , err )
162+ return
163+ }
164+
165+ // github.com/tailscale/tailscale/blob/7de1b0b33082cc/wgengine/netstack/netstack.go#L1201-L1212
166+ r .inject (proto , resp )
167+ }
168+
169+ func (r * icmpResponder ) makeReply (pkt * wire.Parsed , payload []byte , ok bool ) ([]byte , tcpip.NetworkProtocolNumber , error ) {
161170 switch pkt .IPVersion {
162171 case 4 :
163- resp , err = buildICMPv4Reply (pkt , payload )
164- proto = header .IPv4ProtocolNumber
172+ ipHdr := pkt .IP4Header ()
173+ ipHdr .ToResponse ()
174+ if ! ok {
175+ icmpHdr := wire.ICMP4Header {IP4Header : ipHdr , Type : wire .ICMP4Unreachable , Code : wire .ICMP4HostUnreachable }
176+ return wire .Generate (icmpHdr , payload ), header .IPv4ProtocolNumber , nil
177+ }
178+ icmpHdr := wire.ICMP4Header {IP4Header : ipHdr }
179+ icmpHdr .ToResponse ()
180+ return wire .Generate (icmpHdr , payload ), header .IPv4ProtocolNumber , nil
165181 case 6 :
166- resp , err = buildICMPv6Reply (pkt , payload )
167- proto = header .IPv6ProtocolNumber
182+ ipHdr := pkt .IP6Header ()
183+ ipHdr .ToResponse ()
184+ if ! ok {
185+ icmpHdr := wire.ICMP6Header {IP6Header : ipHdr , Type : wire .ICMP6Unreachable , Code : wire .ICMP6NoRoute }
186+ return wire .Generate (icmpHdr , payload ), header .IPv6ProtocolNumber , nil
187+ }
188+ icmpHdr := wire.ICMP6Header {IP6Header : ipHdr }
189+ icmpHdr .ToResponse ()
190+ return wire .Generate (icmpHdr , payload ), header .IPv6ProtocolNumber , nil
168191 default :
169- return
192+ return nil , 0 , fmt . Errorf ( "unsupported ip version: %d" , pkt . IPVersion )
170193 }
171-
172- if err != nil || len (resp ) <= 0 {
173- log .W ("icmp: responder: build reply %s <= %s (sz: %d); err? %v" ,
174- src , dst , len (resp ), err )
175- return
176- }
177-
178- r .inject (proto , resp )
179194}
180195
181196func (r * icmpResponder ) inject (proto tcpip.NetworkProtocolNumber , packet []byte ) {
@@ -195,66 +210,5 @@ func (r *icmpResponder) inject(proto tcpip.NetworkProtocolNumber, packet []byte)
195210
196211 sz := pkt .Size ()
197212 n , err := r .ep .WritePackets (list )
198- logeif (e (err ))("icmp: responder: inject to tun (n: %d; sz: %d); err? %v" , n , sz , err )
199- }
200-
201- func buildICMPv4Reply (p * wire.Parsed , req []byte ) ([]byte , error ) {
202- if len (req ) < header .ICMPv4MinimumSize {
203- return nil , fmt .Errorf ("icmp: responder: v4 payload too small: %d" , len (req ))
204- }
205-
206- reply := make ([]byte , len (req ))
207- copy (reply , req )
208-
209- icmpHdr := header .ICMPv4 (reply )
210- icmpHdr .SetType (header .ICMPv4EchoReply )
211- icmpHdr .SetCode (0 )
212- icmpHdr .SetChecksum (0 )
213- payload := reply [header .ICMPv4MinimumSize :]
214- payloadSum := checksum .Checksum (payload , 0 )
215- icmpHdr .SetChecksum (header .ICMPv4Checksum (icmpHdr , payloadSum ))
216-
217- ipHdr := p .IP4Header ()
218- ipHdr .ToResponse ()
219-
220- packet := make ([]byte , wire .IP4HeaderLength + len (reply ))
221- copy (packet [wire .IP4HeaderLength :], reply )
222- if err := ipHdr .Marshal (packet ); err != nil {
223- return nil , err
224- }
225- return packet , nil
226- }
227-
228- func buildICMPv6Reply (p * wire.Parsed , req []byte ) ([]byte , error ) {
229- if len (req ) < header .ICMPv6MinimumSize {
230- return nil , fmt .Errorf ("icmp: responder: v6 payload too small: %d" , len (req ))
231- }
232-
233- reply := make ([]byte , len (req ))
234- copy (reply , req )
235-
236- icmpHdr := header .ICMPv6 (reply )
237- icmpHdr .SetType (header .ICMPv6EchoReply )
238- icmpHdr .SetCode (0 )
239- icmpHdr .SetChecksum (0 )
240-
241- ipHdr := p .IP6Header ()
242- ipHdr .ToResponse ()
243-
244- payload := reply [header .ICMPv6MinimumSize :]
245- payloadSum := checksum .Checksum (payload , 0 )
246- icmpHdr .SetChecksum (header .ICMPv6Checksum (header.ICMPv6ChecksumParams {
247- Header : icmpHdr ,
248- Src : tcpip .AddrFrom16 (ipHdr .Src .As16 ()),
249- Dst : tcpip .AddrFrom16 (ipHdr .Dst .As16 ()),
250- PayloadCsum : payloadSum ,
251- PayloadLen : len (payload ),
252- }))
253-
254- packet := make ([]byte , wire .IP6HeaderLength + len (reply ))
255- copy (packet [wire .IP6HeaderLength :], reply )
256- if err := ipHdr .Marshal (packet ); err != nil {
257- return nil , err
258- }
259- return packet , nil
213+ logeif (e (err ))("icmp: responder: inject %d to tun (n: %d; sz: %d); err? %v" , proto , n , sz , err )
260214}
0 commit comments