mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support REJECT hook
PiperOrigin-RevId: 420174647
This commit is contained in:
committed by
gVisor bot
parent
d7dbf65873
commit
381a17d923
@@ -102,13 +102,17 @@ const (
|
||||
ICMPv4ReassemblyTimeout ICMPv4Code = 1
|
||||
)
|
||||
|
||||
// ICMP codes for ICMPv4 Destination Unreachable messages as defined in RFC 792.
|
||||
// ICMP codes for ICMPv4 Destination Unreachable messages as defined in RFC 792,
|
||||
// RFC 1122 section 3.2.2.1 and RFC 1812 section 5.2.7.1.
|
||||
const (
|
||||
ICMPv4NetUnreachable ICMPv4Code = 0
|
||||
ICMPv4HostUnreachable ICMPv4Code = 1
|
||||
ICMPv4ProtoUnreachable ICMPv4Code = 2
|
||||
ICMPv4PortUnreachable ICMPv4Code = 3
|
||||
ICMPv4FragmentationNeeded ICMPv4Code = 4
|
||||
ICMPv4NetProhibited ICMPv4Code = 9
|
||||
ICMPv4HostProhibited ICMPv4Code = 10
|
||||
ICMPv4AdminProhibited ICMPv4Code = 13
|
||||
)
|
||||
|
||||
// ICMPv4UnusedCode is a code to use in ICMP messages where no code is needed.
|
||||
|
||||
@@ -410,6 +410,24 @@ type icmpReason interface {
|
||||
isICMPReason()
|
||||
}
|
||||
|
||||
// icmpReasonNetworkProhibited is an error where the destination network is
|
||||
// prohibited.
|
||||
type icmpReasonNetworkProhibited struct{}
|
||||
|
||||
func (*icmpReasonNetworkProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonHostProhibited is an error where the destination host is
|
||||
// prohibited.
|
||||
type icmpReasonHostProhibited struct{}
|
||||
|
||||
func (*icmpReasonHostProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonAdministrativelyProhibited is an error where the destination is
|
||||
// administratively prohibited.
|
||||
type icmpReasonAdministrativelyProhibited struct{}
|
||||
|
||||
func (*icmpReasonAdministrativelyProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type icmpReasonPortUnreachable struct{}
|
||||
@@ -560,6 +578,12 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv
|
||||
sent := netEP.stats.icmp.packetsSent
|
||||
icmpType, icmpCode, counter, pointer := func() (header.ICMPv4Type, header.ICMPv4Code, tcpip.MultiCounterStat, byte) {
|
||||
switch reason := reason.(type) {
|
||||
case *icmpReasonNetworkProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4NetProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonHostProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4HostProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonAdministrativelyProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4AdminProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonPortUnreachable:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4PortUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonProtoUnreachable:
|
||||
|
||||
@@ -1129,6 +1129,7 @@ func (e *endpoint) Stats() stack.NetworkEndpointStats {
|
||||
}
|
||||
|
||||
var _ stack.NetworkProtocol = (*protocol)(nil)
|
||||
var _ stack.RejectIPv4WithHandler = (*protocol)(nil)
|
||||
var _ fragmentation.TimeoutHandler = (*protocol)(nil)
|
||||
|
||||
type protocol struct {
|
||||
@@ -1285,6 +1286,26 @@ func (p *protocol) allowICMPReply(icmpType header.ICMPv4Type, code header.ICMPv4
|
||||
return true
|
||||
}
|
||||
|
||||
// SendRejectionError implements stack.RejectIPv4WithHandler.
|
||||
func (p *protocol) SendRejectionError(pkt *stack.PacketBuffer, rejectWith stack.RejectIPv4WithICMPType, inputHook bool) tcpip.Error {
|
||||
switch rejectWith {
|
||||
case stack.RejectIPv4WithICMPNetUnreachable:
|
||||
return p.returnError(&icmpReasonNetworkUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv4WithICMPHostUnreachable:
|
||||
return p.returnError(&icmpReasonHostUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv4WithICMPPortUnreachable:
|
||||
return p.returnError(&icmpReasonPortUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv4WithICMPNetProhibited:
|
||||
return p.returnError(&icmpReasonNetworkProhibited{}, pkt, inputHook)
|
||||
case stack.RejectIPv4WithICMPHostProhibited:
|
||||
return p.returnError(&icmpReasonHostProhibited{}, pkt, inputHook)
|
||||
case stack.RejectIPv4WithICMPAdminProhibited:
|
||||
return p.returnError(&icmpReasonAdministrativelyProhibited{}, pkt, inputHook)
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled %[1]T = %[1]d", rejectWith))
|
||||
}
|
||||
}
|
||||
|
||||
// calculateNetworkMTU calculates the network-layer payload MTU based on the
|
||||
// link-layer payload mtu.
|
||||
func calculateNetworkMTU(linkMTU, networkHeaderSize uint32) (uint32, tcpip.Error) {
|
||||
|
||||
@@ -678,7 +678,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r
|
||||
})
|
||||
defer replyPkt.DecRef()
|
||||
icmp := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
replyPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
copy(icmp, h)
|
||||
icmp.SetType(header.ICMPv6EchoReply)
|
||||
dataRange := replyPkt.Data().AsRange()
|
||||
@@ -964,6 +964,16 @@ func (p *icmpReasonParameterProblem) respondsToMulticast() bool {
|
||||
return p.respondToMulticast
|
||||
}
|
||||
|
||||
// icmpReasonAdministrativelyProhibited is an error where the destination is
|
||||
// administratively prohibited.
|
||||
type icmpReasonAdministrativelyProhibited struct{}
|
||||
|
||||
func (*icmpReasonAdministrativelyProhibited) isICMPReason() {}
|
||||
|
||||
func (*icmpReasonAdministrativelyProhibited) respondsToMulticast() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// icmpReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type icmpReasonPortUnreachable struct{}
|
||||
@@ -1104,6 +1114,8 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv
|
||||
switch reason := reason.(type) {
|
||||
case *icmpReasonParameterProblem:
|
||||
return header.ICMPv6ParamProblem, reason.code, sent.paramProblem, reason.pointer
|
||||
case *icmpReasonAdministrativelyProhibited:
|
||||
return header.ICMPv6DstUnreachable, header.ICMPv6Prohibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonPortUnreachable:
|
||||
return header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonNetUnreachable:
|
||||
|
||||
@@ -1899,6 +1899,7 @@ func (e *endpoint) Stats() stack.NetworkEndpointStats {
|
||||
}
|
||||
|
||||
var _ stack.NetworkProtocol = (*protocol)(nil)
|
||||
var _ stack.RejectIPv6WithHandler = (*protocol)(nil)
|
||||
var _ fragmentation.TimeoutHandler = (*protocol)(nil)
|
||||
|
||||
type protocol struct {
|
||||
@@ -2124,6 +2125,22 @@ func (p *protocol) allowICMPReply(icmpType header.ICMPv6Type) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// SendRejectionError implements stack.RejectIPv6WithHandler.
|
||||
func (p *protocol) SendRejectionError(pkt *stack.PacketBuffer, rejectWith stack.RejectIPv6WithICMPType, inputHook bool) tcpip.Error {
|
||||
switch rejectWith {
|
||||
case stack.RejectIPv6WithICMPNoRoute:
|
||||
return p.returnError(&icmpReasonNetUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv6WithICMPAddrUnreachable:
|
||||
return p.returnError(&icmpReasonHostUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv6WithICMPPortUnreachable:
|
||||
return p.returnError(&icmpReasonPortUnreachable{}, pkt, inputHook)
|
||||
case stack.RejectIPv6WithICMPAdminProhibited:
|
||||
return p.returnError(&icmpReasonAdministrativelyProhibited{}, pkt, inputHook)
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled %[1]T = %[1]d", rejectWith))
|
||||
}
|
||||
}
|
||||
|
||||
// calculateNetworkMTU calculates the network-layer payload MTU based on the
|
||||
// link-layer payload MTU and the length of every IPv6 header.
|
||||
// Note that this is different than the Payload Length field of the IPv6 header,
|
||||
|
||||
@@ -45,6 +45,88 @@ func (*DropTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (Rul
|
||||
return RuleDrop, 0
|
||||
}
|
||||
|
||||
// RejectIPv4WithHandler handles rejecting a packet.
|
||||
type RejectIPv4WithHandler interface {
|
||||
// SendRejectionError sends an error packet in response to the packet.
|
||||
SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv4WithICMPType, inputHook bool) tcpip.Error
|
||||
}
|
||||
|
||||
// RejectIPv4WithICMPType indicates the type of ICMP error that should be sent.
|
||||
type RejectIPv4WithICMPType int
|
||||
|
||||
// The types of errors that may be returned when rejecting IPv4 packets.
|
||||
const (
|
||||
_ RejectIPv4WithICMPType = iota
|
||||
RejectIPv4WithICMPNetUnreachable
|
||||
RejectIPv4WithICMPHostUnreachable
|
||||
RejectIPv4WithICMPPortUnreachable
|
||||
RejectIPv4WithICMPNetProhibited
|
||||
RejectIPv4WithICMPHostProhibited
|
||||
RejectIPv4WithICMPAdminProhibited
|
||||
)
|
||||
|
||||
// RejectIPv4Target drops packets and sends back an error packet in response to the
|
||||
// matched packet.
|
||||
type RejectIPv4Target struct {
|
||||
Handler RejectIPv4WithHandler
|
||||
RejectWith RejectIPv4WithICMPType
|
||||
}
|
||||
|
||||
// Action implements Target.Action.
|
||||
func (rt *RejectIPv4Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) {
|
||||
switch hook {
|
||||
case Input, Forward, Output:
|
||||
// There is nothing reasonable for us to do in response to an error here;
|
||||
// we already drop the packet.
|
||||
_ = rt.Handler.SendRejectionError(pkt, rt.RejectWith, hook == Input)
|
||||
return RuleDrop, 0
|
||||
case Prerouting, Postrouting:
|
||||
panic(fmt.Sprintf("%s hook not supported for REDIRECT", hook))
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled hook = %s", hook))
|
||||
}
|
||||
}
|
||||
|
||||
// RejectIPv6WithHandler handles rejecting a packet.
|
||||
type RejectIPv6WithHandler interface {
|
||||
// SendRejectionError sends an error packet in response to the packet.
|
||||
SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv6WithICMPType, forwardingHook bool) tcpip.Error
|
||||
}
|
||||
|
||||
// RejectIPv6WithICMPType indicates the type of ICMP error that should be sent.
|
||||
type RejectIPv6WithICMPType int
|
||||
|
||||
// The types of errors that may be returned when rejecting IPv6 packets.
|
||||
const (
|
||||
_ RejectIPv6WithICMPType = iota
|
||||
RejectIPv6WithICMPNoRoute
|
||||
RejectIPv6WithICMPAddrUnreachable
|
||||
RejectIPv6WithICMPPortUnreachable
|
||||
RejectIPv6WithICMPAdminProhibited
|
||||
)
|
||||
|
||||
// RejectIPv6Target drops packets and sends back an error packet in response to the
|
||||
// matched packet.
|
||||
type RejectIPv6Target struct {
|
||||
Handler RejectIPv6WithHandler
|
||||
RejectWith RejectIPv6WithICMPType
|
||||
}
|
||||
|
||||
// Action implements Target.Action.
|
||||
func (rt *RejectIPv6Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) {
|
||||
switch hook {
|
||||
case Input, Forward, Output:
|
||||
// There is nothing reasonable for us to do in response to an error here;
|
||||
// we already drop the packet.
|
||||
_ = rt.Handler.SendRejectionError(pkt, rt.RejectWith, hook == Input)
|
||||
return RuleDrop, 0
|
||||
case Prerouting, Postrouting:
|
||||
panic(fmt.Sprintf("%s hook not supported for REDIRECT", hook))
|
||||
default:
|
||||
panic(fmt.Sprintf("unhandled hook = %s", hook))
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorTarget logs an error and drops the packet. It represents a target that
|
||||
// should be unreachable.
|
||||
type ErrorTarget struct {
|
||||
|
||||
@@ -3037,3 +3037,295 @@ func TestLocallyRoutedPackets(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type icmpv4Matcher struct {
|
||||
icmpType header.ICMPv4Type
|
||||
}
|
||||
|
||||
func (m *icmpv4Matcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
|
||||
if pkt.NetworkProtocolNumber != header.IPv4ProtocolNumber {
|
||||
return false, false
|
||||
}
|
||||
|
||||
if pkt.TransportProtocolNumber != header.ICMPv4ProtocolNumber {
|
||||
return false, false
|
||||
}
|
||||
|
||||
return header.ICMPv4(pkt.TransportHeader().View()).Type() == m.icmpType, false
|
||||
}
|
||||
|
||||
type icmpv6Matcher struct {
|
||||
icmpType header.ICMPv6Type
|
||||
}
|
||||
|
||||
func (m *icmpv6Matcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
|
||||
if pkt.NetworkProtocolNumber != header.IPv6ProtocolNumber {
|
||||
return false, false
|
||||
}
|
||||
|
||||
if pkt.TransportProtocolNumber != header.ICMPv6ProtocolNumber {
|
||||
return false, false
|
||||
}
|
||||
|
||||
return header.ICMPv6(pkt.TransportHeader().View()).Type() == m.icmpType, false
|
||||
}
|
||||
|
||||
func TestRejectWith(t *testing.T) {
|
||||
type natHook struct {
|
||||
hook stack.Hook
|
||||
dstAddr tcpip.Address
|
||||
matcher stack.Matcher
|
||||
|
||||
errorICMPDstAddr tcpip.Address
|
||||
errorICMPPayload buffer.View
|
||||
}
|
||||
|
||||
type rejectWithVal struct {
|
||||
name string
|
||||
val int
|
||||
errorICMPCode uint8
|
||||
}
|
||||
|
||||
rxICMPv4EchoRequest := func(dst tcpip.Address) buffer.View {
|
||||
return utils.ICMPv4Echo(utils.Host1IPv4Addr.AddressWithPrefix.Address, dst, ttl, header.ICMPv4Echo)
|
||||
}
|
||||
|
||||
rxICMPv6EchoRequest := func(dst tcpip.Address) buffer.View {
|
||||
return utils.ICMPv6Echo(utils.Host1IPv6Addr.AddressWithPrefix.Address, dst, ttl, header.ICMPv6EchoRequest)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
netProto tcpip.NetworkProtocolNumber
|
||||
rxICMPEchoRequest func(tcpip.Address) buffer.View
|
||||
icmpChecker func(*testing.T, buffer.View, tcpip.Address, uint8, uint8, buffer.View)
|
||||
|
||||
natHooks []natHook
|
||||
|
||||
rejectTarget func(*testing.T, stack.NetworkProtocol, int) stack.Target
|
||||
rejectWithVals []rejectWithVal
|
||||
errorICMPType uint8
|
||||
}{
|
||||
{
|
||||
name: "IPv4",
|
||||
netProto: header.IPv4ProtocolNumber,
|
||||
rxICMPEchoRequest: rxICMPv4EchoRequest,
|
||||
|
||||
icmpChecker: func(t *testing.T, v buffer.View, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload buffer.View) {
|
||||
t.Helper()
|
||||
|
||||
checker.IPv4(t, v,
|
||||
checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(dstAddr),
|
||||
checker.ICMPv4(
|
||||
checker.ICMPv4Checksum(),
|
||||
checker.ICMPv4Type(header.ICMPv4Type(icmpType)),
|
||||
checker.ICMPv4Code(header.ICMPv4Code(icmpCode)),
|
||||
checker.ICMPv4Payload(origPayload),
|
||||
),
|
||||
)
|
||||
},
|
||||
natHooks: []natHook{
|
||||
{
|
||||
hook: stack.Input,
|
||||
dstAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv4Matcher{icmpType: header.ICMPv4Echo},
|
||||
errorICMPDstAddr: utils.Host1IPv4Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: rxICMPv4EchoRequest(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address),
|
||||
},
|
||||
{
|
||||
hook: stack.Forward,
|
||||
dstAddr: utils.Host2IPv4Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv4Matcher{icmpType: header.ICMPv4Echo},
|
||||
errorICMPDstAddr: utils.Host1IPv4Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: rxICMPv4EchoRequest(utils.Host2IPv4Addr.AddressWithPrefix.Address),
|
||||
},
|
||||
{
|
||||
hook: stack.Output,
|
||||
dstAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv4Matcher{icmpType: header.ICMPv4EchoReply},
|
||||
errorICMPDstAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: utils.ICMPv4Echo(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address, utils.Host1IPv4Addr.AddressWithPrefix.Address, ttl, header.ICMPv4EchoReply),
|
||||
},
|
||||
},
|
||||
rejectTarget: func(t *testing.T, netProto stack.NetworkProtocol, rejectWith int) stack.Target {
|
||||
handler, ok := netProto.(stack.RejectIPv4WithHandler)
|
||||
if !ok {
|
||||
t.Fatalf("expected %T to implement %T", netProto, handler)
|
||||
}
|
||||
|
||||
return &stack.RejectIPv4Target{
|
||||
Handler: handler,
|
||||
RejectWith: stack.RejectIPv4WithICMPType(rejectWith),
|
||||
}
|
||||
},
|
||||
rejectWithVals: []rejectWithVal{
|
||||
{
|
||||
name: "ICMP Network Unreachable",
|
||||
val: int(stack.RejectIPv4WithICMPNetUnreachable),
|
||||
errorICMPCode: uint8(header.ICMPv4NetUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Host Unreachable",
|
||||
val: int(stack.RejectIPv4WithICMPHostUnreachable),
|
||||
errorICMPCode: uint8(header.ICMPv4HostUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Port Unreachable",
|
||||
val: int(stack.RejectIPv4WithICMPPortUnreachable),
|
||||
errorICMPCode: uint8(header.ICMPv4PortUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Network Prohibited",
|
||||
val: int(stack.RejectIPv4WithICMPNetProhibited),
|
||||
errorICMPCode: uint8(header.ICMPv4NetProhibited),
|
||||
},
|
||||
{
|
||||
name: "ICMP Host Prohibited",
|
||||
val: int(stack.RejectIPv4WithICMPHostProhibited),
|
||||
errorICMPCode: uint8(header.ICMPv4HostProhibited),
|
||||
},
|
||||
{
|
||||
name: "ICMP Administratively Prohibited",
|
||||
val: int(stack.RejectIPv4WithICMPAdminProhibited),
|
||||
errorICMPCode: uint8(header.ICMPv4AdminProhibited),
|
||||
},
|
||||
},
|
||||
errorICMPType: uint8(header.ICMPv4DstUnreachable),
|
||||
},
|
||||
{
|
||||
name: "IPv6",
|
||||
netProto: header.IPv6ProtocolNumber,
|
||||
rxICMPEchoRequest: rxICMPv6EchoRequest,
|
||||
|
||||
icmpChecker: func(t *testing.T, v buffer.View, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload buffer.View) {
|
||||
t.Helper()
|
||||
|
||||
checker.IPv6(t, v,
|
||||
checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(dstAddr),
|
||||
checker.ICMPv6(
|
||||
checker.ICMPv6Type(header.ICMPv6Type(icmpType)),
|
||||
checker.ICMPv6Code(header.ICMPv6Code(icmpCode)),
|
||||
checker.ICMPv6Payload(origPayload),
|
||||
),
|
||||
)
|
||||
},
|
||||
natHooks: []natHook{
|
||||
{
|
||||
hook: stack.Input,
|
||||
dstAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv6Matcher{icmpType: header.ICMPv6EchoRequest},
|
||||
errorICMPDstAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: rxICMPv6EchoRequest(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address),
|
||||
},
|
||||
{
|
||||
hook: stack.Forward,
|
||||
dstAddr: utils.Host2IPv6Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv6Matcher{icmpType: header.ICMPv6EchoRequest},
|
||||
errorICMPDstAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: rxICMPv6EchoRequest(utils.Host2IPv6Addr.AddressWithPrefix.Address),
|
||||
},
|
||||
{
|
||||
hook: stack.Output,
|
||||
dstAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
|
||||
matcher: &icmpv6Matcher{icmpType: header.ICMPv6EchoReply},
|
||||
errorICMPDstAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
|
||||
errorICMPPayload: utils.ICMPv6Echo(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address, utils.Host1IPv6Addr.AddressWithPrefix.Address, ttl, header.ICMPv6EchoReply),
|
||||
},
|
||||
},
|
||||
rejectTarget: func(t *testing.T, netProto stack.NetworkProtocol, rejectWith int) stack.Target {
|
||||
handler, ok := netProto.(stack.RejectIPv6WithHandler)
|
||||
if !ok {
|
||||
t.Fatalf("expected %T to implement %T", netProto, handler)
|
||||
}
|
||||
|
||||
return &stack.RejectIPv6Target{
|
||||
Handler: handler,
|
||||
RejectWith: stack.RejectIPv6WithICMPType(rejectWith),
|
||||
}
|
||||
},
|
||||
rejectWithVals: []rejectWithVal{
|
||||
{
|
||||
name: "ICMP No Route",
|
||||
val: int(stack.RejectIPv6WithICMPNoRoute),
|
||||
errorICMPCode: uint8(header.ICMPv6NetworkUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Address Unreachable",
|
||||
val: int(stack.RejectIPv6WithICMPAddrUnreachable),
|
||||
errorICMPCode: uint8(header.ICMPv6AddressUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Port Unreachable",
|
||||
val: int(stack.RejectIPv6WithICMPPortUnreachable),
|
||||
errorICMPCode: uint8(header.ICMPv6PortUnreachable),
|
||||
},
|
||||
{
|
||||
name: "ICMP Administratively Prohibited",
|
||||
val: int(stack.RejectIPv6WithICMPAdminProhibited),
|
||||
errorICMPCode: uint8(header.ICMPv6Prohibited),
|
||||
},
|
||||
},
|
||||
errorICMPType: uint8(header.ICMPv6DstUnreachable),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
for _, natHook := range test.natHooks {
|
||||
t.Run(natHook.hook.String(), func(t *testing.T) {
|
||||
for _, rejectWith := range test.rejectWithVals {
|
||||
t.Run(rejectWith.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol, tcp.NewProtocol},
|
||||
})
|
||||
|
||||
ep1 := channel.New(1, header.IPv6MinimumMTU, "")
|
||||
ep2 := channel.New(1, header.IPv6MinimumMTU, "")
|
||||
utils.SetupRouterStack(t, s, ep1, ep2)
|
||||
|
||||
{
|
||||
ipv6 := test.netProto == ipv6.ProtocolNumber
|
||||
ipt := s.IPTables()
|
||||
filter := ipt.GetTable(stack.FilterID, ipv6)
|
||||
ruleIdx := filter.BuiltinChains[natHook.hook]
|
||||
filter.Rules[ruleIdx].Matchers = []stack.Matcher{natHook.matcher}
|
||||
filter.Rules[ruleIdx].Target = test.rejectTarget(t, s.NetworkProtocolInstance(test.netProto), rejectWith.val)
|
||||
// Make sure the packet is not dropped by the next rule.
|
||||
filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
|
||||
if err := ipt.ReplaceTable(stack.FilterID, filter, ipv6); err != nil {
|
||||
t.Fatalf("ipt.ReplaceTable(%d, _, %t): %s", stack.FilterID, ipv6, err)
|
||||
}
|
||||
}
|
||||
|
||||
func() {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: test.rxICMPEchoRequest(natHook.dstAddr).ToVectorisedView(),
|
||||
})
|
||||
defer pkt.DecRef()
|
||||
ep1.InjectInbound(test.netProto, pkt)
|
||||
}()
|
||||
|
||||
{
|
||||
pkt := ep1.Read()
|
||||
if pkt == nil {
|
||||
t.Fatal("expected to read a packet on ep1")
|
||||
}
|
||||
test.icmpChecker(
|
||||
t,
|
||||
stack.PayloadSince(pkt.NetworkHeader()),
|
||||
natHook.errorICMPDstAddr,
|
||||
test.errorICMPType,
|
||||
rejectWith.errorICMPCode,
|
||||
natHook.errorICMPPayload,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +353,8 @@ func SetupRoutedStacks(t *testing.T, host1Stack, routerStack, host2Stack *stack.
|
||||
})
|
||||
}
|
||||
|
||||
func rxICMPv4Echo(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8, ty header.ICMPv4Type) {
|
||||
// ICMPv4Echo returns an ICMPv4 echo packet.
|
||||
func ICMPv4Echo(src, dst tcpip.Address, ttl uint8, ty header.ICMPv4Type) buffer.View {
|
||||
totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
|
||||
@@ -370,27 +371,31 @@ func rxICMPv4Echo(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8, ty hea
|
||||
DstAddr: dst,
|
||||
})
|
||||
ip.SetChecksum(^ip.CalculateChecksum())
|
||||
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv4ProtocolNumber, newPkt)
|
||||
return hdr.View()
|
||||
}
|
||||
|
||||
// RxICMPv4EchoRequest constructs and injects an ICMPv4 echo request packet on
|
||||
// the provided endpoint.
|
||||
func RxICMPv4EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) {
|
||||
rxICMPv4Echo(e, src, dst, ttl, header.ICMPv4Echo)
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: ICMPv4Echo(src, dst, ttl, header.ICMPv4Echo).ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv4ProtocolNumber, newPkt)
|
||||
}
|
||||
|
||||
// RxICMPv4EchoReply constructs and injects an ICMPv4 echo reply packet on
|
||||
// the provided endpoint.
|
||||
func RxICMPv4EchoReply(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) {
|
||||
rxICMPv4Echo(e, src, dst, ttl, header.ICMPv4EchoReply)
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: ICMPv4Echo(src, dst, ttl, header.ICMPv4EchoReply).ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv4ProtocolNumber, newPkt)
|
||||
}
|
||||
|
||||
func rxICMPv6Echo(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8, ty header.ICMPv6Type) {
|
||||
// ICMPv6Echo returns an ICMPv6 echo packet.
|
||||
func ICMPv6Echo(src, dst tcpip.Address, ttl uint8, ty header.ICMPv6Type) buffer.View {
|
||||
totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize))
|
||||
@@ -410,22 +415,25 @@ func rxICMPv6Echo(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8, ty hea
|
||||
SrcAddr: src,
|
||||
DstAddr: dst,
|
||||
})
|
||||
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, newPkt)
|
||||
return hdr.View()
|
||||
}
|
||||
|
||||
// RxICMPv6EchoRequest constructs and injects an ICMPv6 echo request packet on
|
||||
// the provided endpoint.
|
||||
func RxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) {
|
||||
rxICMPv6Echo(e, src, dst, ttl, header.ICMPv6EchoRequest)
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoRequest).ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, newPkt)
|
||||
}
|
||||
|
||||
// RxICMPv6EchoReply constructs and injects an ICMPv6 echo reply packet on
|
||||
// the provided endpoint.
|
||||
func RxICMPv6EchoReply(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) {
|
||||
rxICMPv6Echo(e, src, dst, ttl, header.ICMPv6EchoReply)
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoReply).ToVectorisedView(),
|
||||
})
|
||||
defer newPkt.DecRef()
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, newPkt)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user