Skip to content

Commit ff4f0b9

Browse files
kevinGCgvisor-bot
authored andcommitted
netstack: properly handle martian ipv4 mapped ipv6 addresses
PiperOrigin-RevId: 527012681
1 parent 20c0790 commit ff4f0b9

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

pkg/tcpip/network/ipv6/ipv6.go

+22
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,10 @@ func (e *endpoint) HandlePacket(pkt stack.PacketBufferPtr) {
10901090
defer hView.Release()
10911091
h := header.IPv6(hView.AsSlice())
10921092

1093+
if !checkV4Mapped(h, stats) {
1094+
return
1095+
}
1096+
10931097
if !e.nic.IsLoopback() {
10941098
if !e.protocol.options.AllowExternalLoopbackTraffic {
10951099
if header.IsV6LoopbackAddress(h.SourceAddress()) {
@@ -1147,6 +1151,10 @@ func (e *endpoint) handleLocalPacket(pkt stack.PacketBufferPtr, canSkipRXChecksu
11471151
defer hView.Release()
11481152
h := header.IPv6(hView.AsSlice())
11491153

1154+
if !checkV4Mapped(h, stats) {
1155+
return
1156+
}
1157+
11501158
e.handleValidatedPacket(h, pkt, e.nic.Name() /* inNICName */)
11511159
}
11521160

@@ -2843,3 +2851,17 @@ func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeaders hea
28432851

28442852
return fragPkt, more
28452853
}
2854+
2855+
func checkV4Mapped(h header.IPv6, stats ip.MultiCounterIPStats) bool {
2856+
// Disallow IPv4-mapped addresses per RFC 6890 section 2.2.3.
2857+
ret := true
2858+
if header.IsV4MappedAddress(h.SourceAddress()) {
2859+
stats.InvalidSourceAddressesReceived.Increment()
2860+
ret = false
2861+
}
2862+
if header.IsV4MappedAddress(h.DestinationAddress()) {
2863+
stats.InvalidDestinationAddressesReceived.Increment()
2864+
ret = false
2865+
}
2866+
return ret
2867+
}

pkg/tcpip/network/ipv6/ipv6_test.go

+107
Original file line numberDiff line numberDiff line change
@@ -3881,3 +3881,110 @@ func TestIcmpRateLimit(t *testing.T) {
38813881
})
38823882
}
38833883
}
3884+
3885+
// TestRejectMartianMappedPackets tests that IPv6 endpoints reject packets
3886+
// containing IPv4-mapped IPv6 addresses.
3887+
func TestRejectMartianMappedPackets(t *testing.T) {
3888+
tcs := []struct {
3889+
name string
3890+
wantSrcReceived uint64
3891+
wantDstReceived uint64
3892+
wantDelivered uint64
3893+
srcAddr tcpip.Address
3894+
dstAddr tcpip.Address
3895+
}{
3896+
{
3897+
name: "bad source",
3898+
wantSrcReceived: 1,
3899+
srcAddr: testutil.MustParse6("::ffff:1.2.3.4"),
3900+
dstAddr: testutil.MustParse6("fe80::2"),
3901+
},
3902+
{
3903+
name: "bad destination",
3904+
wantDstReceived: 1,
3905+
srcAddr: testutil.MustParse6("fe80::2"),
3906+
dstAddr: testutil.MustParse6("::ffff:1.2.3.4"),
3907+
},
3908+
{
3909+
name: "bad source and destination",
3910+
wantSrcReceived: 1,
3911+
wantDstReceived: 1,
3912+
srcAddr: testutil.MustParse6("::ffff:1.2.3.4"),
3913+
dstAddr: testutil.MustParse6("::ffff:5.6.7.8"),
3914+
},
3915+
{
3916+
name: "valid source and destination",
3917+
wantDelivered: 2,
3918+
srcAddr: testutil.MustParse6("fe80::2"),
3919+
dstAddr: header.IPv6AllNodesMulticastAddress,
3920+
},
3921+
}
3922+
3923+
// dst := header.SolicitedNodeAddr(addr2)
3924+
3925+
for _, tc := range tcs {
3926+
t.Run(tc.name, func(t *testing.T) {
3927+
// Initialize the stack and add an address.
3928+
ctx := newTestContext()
3929+
defer ctx.cleanup()
3930+
stk := ctx.s
3931+
3932+
channelEP := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
3933+
defer channelEP.Close()
3934+
if err := stk.CreateNIC(nicID, channelEP); err != nil {
3935+
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
3936+
}
3937+
3938+
stk.SetRouteTable([]tcpip.Route{
3939+
{
3940+
Destination: header.IPv6EmptySubnet,
3941+
NIC: nicID,
3942+
},
3943+
})
3944+
3945+
protocolAddr := tcpip.ProtocolAddress{
3946+
Protocol: ProtocolNumber,
3947+
AddressWithPrefix: addr2.WithPrefix(),
3948+
}
3949+
if err := stk.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
3950+
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
3951+
}
3952+
3953+
// We don't have to setup the UDP header properly, as
3954+
// it should be rejected at the IP layer.
3955+
hdr := prependable.New(header.IPv6MinimumSize + header.UDPMinimumSize)
3956+
_ = header.UDP(hdr.Prepend(header.UDPMinimumSize))
3957+
3958+
payloadLength := hdr.UsedLength()
3959+
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
3960+
ip.Encode(&header.IPv6Fields{
3961+
PayloadLength: uint16(payloadLength),
3962+
TransportProtocol: udp.ProtocolNumber,
3963+
HopLimit: 255,
3964+
SrcAddr: tc.srcAddr,
3965+
DstAddr: tc.dstAddr,
3966+
})
3967+
3968+
// Send the packet out.
3969+
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
3970+
Payload: bufferv2.MakeWithData(hdr.View()),
3971+
})
3972+
channelEP.InjectInbound(ProtocolNumber, pkt)
3973+
pkt.DecRef()
3974+
3975+
// Verify that stat counters are appropriately updated.
3976+
srcStat := stk.Stats().IP.InvalidSourceAddressesReceived
3977+
if got := srcStat.Value(); got != tc.wantSrcReceived {
3978+
t.Errorf("got InvalidSourceAddressesReceived = %d, want = %d", got, tc.wantSrcReceived)
3979+
}
3980+
dstStat := stk.Stats().IP.InvalidDestinationAddressesReceived
3981+
if got := dstStat.Value(); got != tc.wantDstReceived {
3982+
t.Errorf("got InvalidDestinationAddressesReceived = %d, want = %d", got, tc.wantDstReceived)
3983+
}
3984+
deliveredStat := stk.Stats().IP.PacketsDelivered
3985+
if got := deliveredStat.Value(); got != tc.wantDelivered {
3986+
t.Errorf("got PacketsDelivered = %d, want = %d", got, tc.wantDelivered)
3987+
}
3988+
})
3989+
}
3990+
}

0 commit comments

Comments
 (0)