-
Notifications
You must be signed in to change notification settings - Fork 20
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
base: n2
Are you sure you want to change the base?
Changes from 1 commit
2cc55a2
de2a7f2
eff90d9
212044f
92b44ef
3788d23
7097a63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -7,6 +7,7 @@ | |||
package netstack | ||||
|
||||
import ( | ||||
"encoding/binary" | ||||
"math" | ||||
|
||||
"github.com/celzero/firestack/intra/core" | ||||
|
@@ -19,6 +20,79 @@ | |||
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp" | ||||
) | ||||
|
||||
type ICMPHackTarget struct{} | ||||
|
||||
func (t *ICMPHackTarget) Action(pkt *stack.PacketBuffer, hook stack.Hook, r *stack.Route, _ stack.AddressableEndpoint) (stack.RuleVerdict, int) { | ||||
transportHdr := pkt.TransportHeader() | ||||
if len(transportHdr.Slice()) < 8 { | ||||
return stack.RuleDrop, 0 | ||||
} | ||||
switch pkt.TransportProtocolNumber { | ||||
case header.ICMPv6ProtocolNumber: | ||||
icmp6Hdr := header.ICMPv6(transportHdr.Slice()) | ||||
if icmp6Hdr.Type() == header.ICMPv6EchoRequest { | ||||
//https://www.rfc-editor.org/rfc/rfc4443.html#section-2.1 | ||||
//200 Private experimentation | ||||
icmp6Hdr.SetType(200) | ||||
icmp6Hdr.SetChecksum(0) | ||||
|
||||
ipv6Hdr := pkt.NetworkHeader().Slice() | ||||
icmp6Msg := stack.PayloadSince(transportHdr).AsSlice() | ||||
t1 := checksum.Checksumer{} | ||||
t1.Add(ipv6Hdr[8:40]) | ||||
var t2 [8]byte | ||||
binary.BigEndian.PutUint32(t2[:4], uint32(len(icmp6Msg))) | ||||
t2[7] = uint8(header.ICMPv6ProtocolNumber) | ||||
t1.Add(t2[:]) | ||||
t1.Add(icmp6Msg) | ||||
|
||||
icmp6Hdr.SetChecksum(t1.Checksum()) | ||||
} | ||||
case header.ICMPv4ProtocolNumber: | ||||
icmp4Hdr := header.ICMPv4(transportHdr.Slice()) | ||||
if icmp4Hdr.Type() == header.ICMPv4Echo { | ||||
//https://www.rfc-editor.org/rfc/rfc4727.html#section-4 | ||||
//253 RFC3692-style Experiment 1 | ||||
icmp4Hdr.SetType(253) | ||||
icmp4Hdr.SetChecksum(0) | ||||
icmp4Msg := stack.PayloadSince(transportHdr).AsSlice() | ||||
icmp4Hdr.SetChecksum(checksum.Checksum(icmp4Msg, 0)) | ||||
} | ||||
} | ||||
return stack.RuleAccept, 0 | ||||
} | ||||
|
||||
func restoreICMPv6Type(h header.ICMPv6) { | ||||
if h.Type() == 200 { | ||||
h.SetType(header.ICMPv6EchoRequest) | ||||
} | ||||
} | ||||
func restoreICMPv4Type(h header.ICMPv4) { | ||||
if h.Type() == 253 { | ||||
h.SetType(header.ICMPv4Echo) | ||||
} | ||||
} | ||||
|
||||
func ICMPHack(s *stack.Stack, target stack.Target) { | ||||
ipt := s.IPTables() | ||||
|
||||
table := ipt.GetTable(stack.MangleID, true) | ||||
index := table.BuiltinChains[stack.Prerouting] | ||||
rules := table.Rules | ||||
rules[index].Filter.Protocol = header.ICMPv6ProtocolNumber | ||||
rules[index].Filter.CheckProtocol = true | ||||
rules[index].Target = target | ||||
ipt.ReplaceTable(stack.MangleID, table, true) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried bumping gvisor for my gvisor-playground, found that new gvisor requires ForceReplaceTable() to work. All rules in iptables become useless if shouldSkipOrPopulateTables() returns true…… There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying, for the current changes to work, firestack would have to be pinned to its current gvisor@go version Line 27 in 96bf8e8
(I never really got the hang of the gvisor/netstack internals at all...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I mean that |
||||
|
||||
table = ipt.GetTable(stack.MangleID, false) | ||||
index = table.BuiltinChains[stack.Prerouting] | ||||
rules = table.Rules | ||||
rules[index].Filter.Protocol = header.ICMPv4ProtocolNumber | ||||
rules[index].Filter.CheckProtocol = true | ||||
rules[index].Target = target | ||||
ipt.ReplaceTable(stack.MangleID, table, false) | ||||
} | ||||
|
||||
type GICMPHandler interface { | ||||
GBaseConnHandler | ||||
GEchoConnHandler | ||||
|
@@ -33,6 +107,8 @@ | |||
// github.com/google/gvisor/blob/738e1d995f/pkg/tcpip/network/ipv4/icmp.go | ||||
// github.com/google/gvisor/blob/738e1d995f/pkg/tcpip/network/ipv6/icmp.go | ||||
func OutboundICMP(id string, s *stack.Stack, hdl GICMPHandler) { | ||||
ICMPHack(s, &ICMPHackTarget{}) | ||||
|
||||
// remove default handlers | ||||
s.SetTransportProtocolHandler(icmp.ProtocolNumber4, nil) | ||||
s.SetTransportProtocolHandler(icmp.ProtocolNumber6, nil) | ||||
|
@@ -69,6 +145,7 @@ | |||
|
||||
// ref: github.com/google/gvisor/blob/acf460d0d735/pkg/tcpip/stack/conntrack.go#L933 | ||||
hdr := header.ICMPv4(pkt.TransportHeader().Slice()) | ||||
restoreICMPv4Type(hdr) | ||||
if hdr.Type() != header.ICMPv4Echo { | ||||
// netstack handles other msgs except echo / ping | ||||
log.D("icmp: v4: %s: type %v passthrough", f.o, hdr.Type()) | ||||
|
@@ -166,6 +243,7 @@ | |||
} | ||||
|
||||
hdr := header.ICMPv6(pkt.TransportHeader().Slice()) | ||||
restoreICMPv6Type(hdr) | ||||
if hdr.Type() != header.ICMPv6EchoRequest { | ||||
log.D("icmp: v6: %s: type %v/%v passthrough", f.o, hdr.Type(), hdr.Code()) | ||||
return // netstack to handle other msgs except echo / ping | ||||
|
Uh oh!
There was an error while loading. Please reload this page.