Skip to content

Commit

Permalink
Hacks for ipv6
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumerose committed Sep 30, 2021
1 parent 2199d4c commit eb2c1a9
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
13 changes: 13 additions & 0 deletions pkg/tap/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
)

type LinkEndpoint struct {
Expand Down Expand Up @@ -111,6 +113,17 @@ func (e *LinkEndpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProt
}
}

if pkt.NetworkProtocolNumber == ipv6.ProtocolNumber && pkt.TransportProtocolNumber == icmp.ProtocolNumber6 {
transportLayer := header.ICMPv6(pkt.TransportHeader().View())
if transportLayer.Type() == header.ICMPv6NeighborAdvert {
ip := header.NDPNeighborAdvert(transportLayer.MessageBody()).TargetAddress().String()
if ip != "fe80::1" {
log.Debugf("dropping spoofing packets from the gateway about IP %s", ip)
return nil
}
}
}

if e.debug {
vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
packet := gopacket.NewPacket(vv.ToView(), layers.LayerTypeEthernet, gopacket.Default)
Expand Down
83 changes: 83 additions & 0 deletions pkg/tap/router_advertisement.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package tap

import (
"encoding/binary"

"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
)

// raBuf returns a valid NDP Router Advertisement with options, router
// preference and DHCPv6 configurations specified.
func raBuf(src, dst tcpip.LinkAddress, ip tcpip.Address, rl uint16, managedAddress, otherConfigurations bool, prf header.NDPRoutePreference, optSer header.NDPOptionsSerializer) *stack.PacketBuffer {
const flagsByte = 1
const routerLifetimeOffset = 2

icmpSize := header.ICMPv6HeaderSize + header.NDPRAMinimumSize + optSer.Length()
hdr := buffer.NewPrependable(header.EthernetMinimumSize + header.IPv6MinimumSize + icmpSize)
pkt := header.ICMPv6(hdr.Prepend(icmpSize))
pkt.SetType(header.ICMPv6RouterAdvert)
pkt.SetCode(0)
raPayload := pkt.MessageBody()
ra := header.NDPRouterAdvert(raPayload)
// Populate the Router Lifetime.
binary.BigEndian.PutUint16(raPayload[routerLifetimeOffset:], rl)
// Populate the Managed Address flag field.
if managedAddress {
// The Managed Addresses flag field is the 7th bit of the flags byte.
raPayload[flagsByte] |= 1 << 7
}
// Populate the Other Configurations flag field.
if otherConfigurations {
// The Other Configurations flag field is the 6th bit of the flags byte.
raPayload[flagsByte] |= 1 << 6
}
// The Prf field is held in the flags byte.
raPayload[flagsByte] |= byte(prf) << 3
opts := ra.Options()
opts.Serialize(optSer)
pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
Header: pkt,
Src: ip,
Dst: header.IPv6AllNodesMulticastAddress,
}))
payloadLength := hdr.UsedLength()
iph := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
iph.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: header.NDPHopLimit,
SrcAddr: ip,
DstAddr: header.IPv6AllNodesMulticastAddress,
})

eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize))
eth.Encode(&header.EthernetFields{
Type: ipv6.ProtocolNumber,
SrcAddr: src,
DstAddr: dst,
})
return stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
})
}

// raBufWithOpts returns a valid NDP Router Advertisement with options.
//
// Note, raBufWithOpts does not populate any of the RA fields other than the
// Router Lifetime.
func raBufWithOpts(src, dst tcpip.LinkAddress, ip tcpip.Address, rl uint16, optSer header.NDPOptionsSerializer) *stack.PacketBuffer {
return raBuf(src, dst, ip, rl, false /* managedAddress */, false /* otherConfigurations */, 0 /* prf */, optSer)
}

// raBuf returns a valid NDP Router Advertisement.
//
// Note, raBuf does not populate any of the RA fields other than the
// Router Lifetime.
func raBufSimple(src, dst tcpip.LinkAddress, ip tcpip.Address, rl uint16) *stack.PacketBuffer {
return raBufWithOpts(src, dst, ip, rl, header.NDPOptionsSerializer{})
}
14 changes: 14 additions & 0 deletions pkg/tap/switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)

Expand Down Expand Up @@ -217,6 +218,19 @@ loop:
e.cam[eth.SourceAddress()] = id
e.camLock.Unlock()

if eth.Type() == ipv6.ProtocolNumber {
networkLayer := header.IPv6(buf[header.EthernetMinimumSize:])
if networkLayer.TransportProtocol() == header.ICMPv6ProtocolNumber {
transportLayer := header.ICMPv6(networkLayer.Payload())
if transportLayer.Type() == header.ICMPv6RouterSolicit {
routerAdvertisement := raBufSimple(e.gateway.LinkAddress(), eth.SourceAddress(), tcpip.Address(net.ParseIP("fe80::1")), 1000)
if err := e.tx(e.gateway.LinkAddress(), eth.SourceAddress(), routerAdvertisement); err != nil {
log.Error(err)
}
}
}
}

if eth.DestinationAddress() != e.gateway.LinkAddress() {
if err := e.tx(eth.SourceAddress(), eth.DestinationAddress(), stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: vv,
Expand Down

0 comments on commit eb2c1a9

Please sign in to comment.