@@ -209,6 +209,22 @@ type bucket struct {
209209 tuples tupleList
210210}
211211
212+ func getEmbeddedNetAndTransHeaders (pkt * PacketBuffer , netHdrLength int , netHdrFunc func ([]byte ) header.Network ) (header.Network , header.ChecksummableTransport , bool ) {
213+ switch pkt .tuple .id ().transProto {
214+ case header .TCPProtocolNumber :
215+ if netAndTransHeader , ok := pkt .Data ().PullUp (netHdrLength + header .TCPMinimumSize ); ok {
216+ netHeader := netHdrFunc (netAndTransHeader )
217+ return netHeader , header .TCP (netHeader .Payload ()), true
218+ }
219+ case header .UDPProtocolNumber :
220+ if netAndTransHeader , ok := pkt .Data ().PullUp (netHdrLength + header .UDPMinimumSize ); ok {
221+ netHeader := netHdrFunc (netAndTransHeader )
222+ return netHeader , header .UDP (netHeader .Payload ()), true
223+ }
224+ }
225+ return nil , nil , false
226+ }
227+
212228func getHeaders (pkt * PacketBuffer ) (netHdr header.Network , transHdr header.ChecksummableTransport , isICMPError bool , ok bool ) {
213229 switch pkt .TransportProtocolNumber {
214230 case header .TCPProtocolNumber :
@@ -225,29 +241,31 @@ func getHeaders(pkt *PacketBuffer) (netHdr header.Network, transHdr header.Check
225241 panic (fmt .Sprintf ("should have a valid IPv4 packet; only have %d bytes, want at least %d bytes" , pkt .Data ().Size (), header .IPv4MinimumSize ))
226242 }
227243
228- ipv4 := header .IPv4 (h )
229- if ipv4 .HeaderLength () > header .IPv4MinimumSize {
244+ if header .IPv4 (h ).HeaderLength () > header .IPv4MinimumSize {
230245 // TODO(https://gvisor.dev/issue/6765): Handle IPv4 options.
231246 panic ("should have dropped packets with IPv4 options" )
232247 }
233248
234- switch pkt .tuple .id ().transProto {
235- case header .TCPProtocolNumber :
236- // TODO(https://gvisor.dev/issue/6765): Handle IPv4 options.
237- netAndTransHeader , ok := pkt .Data ().PullUp (header .IPv4MinimumSize + header .TCPMinimumSize )
238- if ! ok {
239- return nil , nil , false , false
240- }
241- netHeader := header .IPv4 (netAndTransHeader )
242- return netHeader , header .TCP (netHeader .Payload ()), true , true
243- case header .UDPProtocolNumber :
244- // TODO(https://gvisor.dev/issue/6765): Handle IPv4 options.
245- netAndTransHeader , ok := pkt .Data ().PullUp (header .IPv4MinimumSize + header .UDPMinimumSize )
246- if ! ok {
247- return nil , nil , false , false
248- }
249- netHeader := header .IPv4 (netAndTransHeader )
250- return netHeader , header .UDP (netHeader .Payload ()), true , true
249+ if netHdr , transHdr , ok := getEmbeddedNetAndTransHeaders (pkt , header .IPv4MinimumSize , func (b []byte ) header.Network { return header .IPv4 (b ) }); ok {
250+ return netHdr , transHdr , true , true
251+ }
252+ case header .ICMPv6ProtocolNumber :
253+ h , ok := pkt .Data ().PullUp (header .IPv6MinimumSize )
254+ if ! ok {
255+ panic (fmt .Sprintf ("should have a valid IPv6 packet; only have %d bytes, want at least %d bytes" , pkt .Data ().Size (), header .IPv6MinimumSize ))
256+ }
257+
258+ // We do not support extension headers in ICMP errors so the next header
259+ // in the IPv6 packet should be a tracked protocol if we reach this point.
260+ //
261+ // TODO(https://gvisor.dev/issue/6789): Support extension headers.
262+ transProto := pkt .tuple .id ().transProto
263+ if got := header .IPv6 (h ).TransportProtocol (); got != transProto {
264+ panic (fmt .Sprintf ("got TransportProtocol() = %d, want = %d" , got , transProto ))
265+ }
266+
267+ if netHdr , transHdr , ok := getEmbeddedNetAndTransHeaders (pkt , header .IPv6MinimumSize , func (b []byte ) header.Network { return header .IPv6 (b ) }); ok {
268+ return netHdr , transHdr , true , true
251269 }
252270 }
253271
@@ -265,15 +283,37 @@ func getTupleIDForRegularPacket(netHdr header.Network, netProto tcpip.NetworkPro
265283 }
266284}
267285
268- func getTupleIDForPacketInICMPError (netHdr header.Network , netProto tcpip.NetworkProtocolNumber , transHdr header.Transport , transProto tcpip.TransportProtocolNumber ) tupleID {
269- return tupleID {
270- srcAddr : netHdr .DestinationAddress (),
271- srcPort : transHdr .DestinationPort (),
272- dstAddr : netHdr .SourceAddress (),
273- dstPort : transHdr .SourcePort (),
274- transProto : transProto ,
275- netProto : netProto ,
286+ func getTupleIDForPacketInICMPError (pkt * PacketBuffer , netHdrFunc func ([]byte ) header.Network , netProto tcpip.NetworkProtocolNumber , netLen int , transProto tcpip.TransportProtocolNumber ) (tupleID , bool ) {
287+ switch transProto {
288+ case header .TCPProtocolNumber :
289+ if netAndTransHeader , ok := pkt .Data ().PullUp (netLen + header .TCPMinimumSize ); ok {
290+ netHdr := netHdrFunc (netAndTransHeader )
291+ transHdr := header .TCP (netHdr .Payload ())
292+ return tupleID {
293+ srcAddr : netHdr .DestinationAddress (),
294+ srcPort : transHdr .DestinationPort (),
295+ dstAddr : netHdr .SourceAddress (),
296+ dstPort : transHdr .SourcePort (),
297+ transProto : transProto ,
298+ netProto : netProto ,
299+ }, true
300+ }
301+ case header .UDPProtocolNumber :
302+ if netAndTransHeader , ok := pkt .Data ().PullUp (netLen + header .UDPMinimumSize ); ok {
303+ netHdr := netHdrFunc (netAndTransHeader )
304+ transHdr := header .UDP (netHdr .Payload ())
305+ return tupleID {
306+ srcAddr : netHdr .DestinationAddress (),
307+ srcPort : transHdr .DestinationPort (),
308+ dstAddr : netHdr .SourceAddress (),
309+ dstPort : transHdr .SourcePort (),
310+ transProto : transProto ,
311+ netProto : netProto ,
312+ }, true
313+ }
276314 }
315+
316+ return tupleID {}, false
277317}
278318
279319func getTupleID (pkt * PacketBuffer ) (tid tupleID , isICMPError bool , ok bool ) {
@@ -308,17 +348,30 @@ func getTupleID(pkt *PacketBuffer) (tid tupleID, isICMPError bool, ok bool) {
308348 // TODO(https://gvisor.dev/issue/6765): Handle IPv4 options.
309349 return tupleID {}, false , false
310350 }
311- switch ipv4 .TransportProtocol () {
312- case header .TCPProtocolNumber :
313- if netAndTransHeader , ok := pkt .Data ().PullUp (header .IPv4MinimumSize + header .TCPMinimumSize ); ok {
314- netHdr := header .IPv4 (netAndTransHeader )
315- return getTupleIDForPacketInICMPError (netHdr , header .IPv4ProtocolNumber , header .TCP (netHdr .Payload ()), header .TCPProtocolNumber ), true , true
316- }
317- case header .UDPProtocolNumber :
318- if netAndTransHeader , ok := pkt .Data ().PullUp (header .IPv4MinimumSize + header .UDPMinimumSize ); ok {
319- netHdr := header .IPv4 (netAndTransHeader )
320- return getTupleIDForPacketInICMPError (netHdr , header .IPv4ProtocolNumber , header .UDP (netHdr .Payload ()), header .UDPProtocolNumber ), true , true
321- }
351+
352+ if tid , ok := getTupleIDForPacketInICMPError (pkt , func (b []byte ) header.Network { return header .IPv4 (b ) }, header .IPv4ProtocolNumber , header .IPv4MinimumSize , ipv4 .TransportProtocol ()); ok {
353+ return tid , true , true
354+ }
355+ case header .ICMPv6ProtocolNumber :
356+ icmp := header .ICMPv6 (pkt .TransportHeader ().View ())
357+ if len (icmp ) < header .ICMPv6MinimumSize {
358+ return tupleID {}, false , false
359+ }
360+
361+ switch icmp .Type () {
362+ case header .ICMPv6DstUnreachable , header .ICMPv6PacketTooBig , header .ICMPv6TimeExceeded , header .ICMPv6ParamProblem :
363+ default :
364+ return tupleID {}, false , false
365+ }
366+
367+ h , ok := pkt .Data ().PullUp (header .IPv6MinimumSize )
368+ if ! ok {
369+ return tupleID {}, false , false
370+ }
371+
372+ // TODO(https://gvisor.dev/issue/6789): Handle extension headers.
373+ if tid , ok := getTupleIDForPacketInICMPError (pkt , func (b []byte ) header.Network { return header .IPv6 (b ) }, header .IPv6ProtocolNumber , header .IPv6MinimumSize , header .IPv6 (h ).TransportProtocol ()); ok {
374+ return tid , true , true
322375 }
323376 }
324377
@@ -624,6 +677,33 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool {
624677 } else {
625678 network .SetSourceAddressWithChecksumUpdate (tid .dstAddr )
626679 }
680+ case header .ICMPv6ProtocolNumber :
681+ network := header .IPv6 (pkt .NetworkHeader ().View ())
682+ srcAddr := network .SourceAddress ()
683+ dstAddr := network .DestinationAddress ()
684+ if dnat {
685+ dstAddr = tid .srcAddr
686+ } else {
687+ srcAddr = tid .dstAddr
688+ }
689+
690+ icmp := header .ICMPv6 (pkt .TransportHeader ().View ())
691+ // TODO(https://gvisor.dev/issue/6788): Incrementally update ICMP checksum.
692+ icmp .SetChecksum (0 )
693+ payload := pkt .Data ()
694+ icmp .SetChecksum (header .ICMPv6Checksum (header.ICMPv6ChecksumParams {
695+ Header : icmp ,
696+ Src : srcAddr ,
697+ Dst : dstAddr ,
698+ PayloadCsum : payload .AsRange ().Checksum (),
699+ PayloadLen : payload .Size (),
700+ }))
701+
702+ if dnat {
703+ network .SetDestinationAddress (dstAddr )
704+ } else {
705+ network .SetSourceAddress (srcAddr )
706+ }
627707 }
628708
629709 return true
0 commit comments