Skip to content

icmp: workaround for gvisor's fake ICMP echo #142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: n2
Choose a base branch
from

Conversation

Lanius-collaris
Copy link
Contributor

@Lanius-collaris Lanius-collaris commented Mar 22, 2025

Not working. I'm trying inserting code in other positions.

t1 := checksum.Checksumer{}
t1.Add(ipv6Hdr[8:40])
var t2 [8]byte
binary.BigEndian.PutUint32(t2[:4], uint32(len(icmp6Msg)))

Check failure

Code scanning / gosec

integer overflow conversion uint64 -> uint32 Error

integer overflow conversion int -> uint32
@ignoramous
Copy link
Contributor

Thanks.

I wonder if this forceful default handling of ICMP is a bug on gvisor upstream despite having set a ICMP handler? It was working as I'd expect it to in previous (believe a year or so ago) gvisor version.

@ignoramous ignoramous requested a review from Copilot March 22, 2025 15:44
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a workaround for gvisor's fake ICMP echo by modifying the ICMP packet types and recalculating checksums for both ICMPv6 and ICMPv4 before processing.

  • Adds a new ICMPHackTarget and associated Action method for intercepting and modifying ICMP packets.
  • Implements restore functions to revert the experimental packet type changes and adjusts the outbound handler to invoke the hack.
Comments suppressed due to low confidence (2)

intra/netstack/icmp.go:36

  • [nitpick] Consider replacing the magic number 200 with a clearly named constant (e.g., ICMPv6ExperimentalType) for improved readability and maintenance.
icmp6Hdr.SetType(200)

intra/netstack/icmp.go:56

  • [nitpick] Replace the magic number 253 with a named constant (e.g., ICMPv4ExperimentalType) to enhance clarity and consistency.
icmp4Hdr.SetType(253)

@Lanius-collaris
Copy link
Contributor Author

It was working as I'd expect it to in previous (believe a year or so ago) gvisor version.

🤔Will current handler work if these lines are deleted?
https://github.com/google/gvisor/blob/3a9ba17351571e343e16caec2e44215d8adc400f/pkg/tcpip/network/ipv6/icmp.go#L694
https://github.com/google/gvisor/blob/3a9ba17351571e343e16caec2e44215d8adc400f/pkg/tcpip/network/ipv4/icmp.go#L449

@Lanius-collaris
Copy link
Contributor Author

I wonder if this forceful default handling of ICMP is a bug on gvisor upstream despite having set a ICMP handler? It was working as I'd expect it to in previous (believe a year or so ago) gvisor version.

I have a theory that these lines were written for inbound ICMP echo requests (packet sockets can receive them).

@kevinGC
Could you answer ignoramous' question?

@kevinGC
Copy link

kevinGC commented Mar 28, 2025

Sorry, what's the specific question? I'm missing some context and not sure what 'fake' means in the title here.

I don't remember any recent changes to ICMP handling. If you've set a custom handler for ICMP packets and the stack is still doing its own ICMP handling, I think that's because ICMP handling is tightly coupled to the ipv4 and ipv6 packages. Nobody has tried to split them AFAIK, so there's no easy way to turn off just ICMP.

Packet sockets should get ICMP messages regardless of the code in the ipv4 and ipv6 packages; it happens earlier in packaet processing (around nic.go:DeliverLinkPacket).

BTW @nybidari is the gVisor networking lead these days.

@ignoramous
Copy link
Contributor

ignoramous commented Mar 28, 2025

Sorry, what's the specific question? I'm missing some context and not sure what 'fake' means in the title here.

Netstack replies to ICMP messages on its own and does not wait on the Handler set via stack.SetTransportProtocolHandler (unlike for TCP and UDP, for which Netstack processes packets only if the Handler does not).

I should note that Netstack we use is setup with Spoofing and is Promiscuous (ref), in addition to being the default gateway (0.0.0.0 and :: routes); HandleLocal & NICForwarding opts are also set to false (ref).

Packet sockets should get ICMP messages regardless of the code in the ipv4 and ipv6 packages;

This happens even today. The Handler does get those packets, but Netstack replies to those packets before the Handler has had the chance.

Like @Lanius-collaris points out, ICMP is handled internally (here) before being delivered to the Handler (here?)? For us, it is enough if ICMP requests (echo, specifically) (which aren't tied to an existing UDP/TCP sesssion), like those usually coming from ping or equivalent progs, are sent to the Handler before Netstack looks at them.

@Lanius-collaris
Copy link
Contributor Author

I have a theory that these lines were written for inbound ICMP echo requests (packet sockets can receive them).

Packet sockets should get ICMP messages regardless of the code in the ipv4 and ipv6 packages; it happens earlier in packaet processing (around nic.go:DeliverLinkPacket).

"packet sockets" here mean sockets created with socket(AF_PACKET, int socket_type, int protocol) on linux, not tcpip.Endpoint provided by gvisor.dev/gvisor/pkg/tcpip/transport/packet module.

If you've set a custom handler for ICMP packets and the stack is still doing its own ICMP handling, I think that's because ICMP handling is tightly coupled to the ipv4 and ipv6 packages. Nobody has tried to split them AFAIK, so there's no easy way to turn off just ICMP.

I have tried and succeeded. 😆 Stack.IPTables() is powerful.
Lanius-collaris/gvisor-playground@5403bf8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants