Merge pull request #15 from neilalexander/packettoobig

Implement Path MTU Discovery using session MTU
This commit is contained in:
Arceliar 2018-02-15 12:59:46 -06:00 committed by GitHub
commit 120ce8bd2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 27 deletions

View File

@ -8,6 +8,7 @@ import "net"
import "golang.org/x/net/ipv6" import "golang.org/x/net/ipv6"
import "golang.org/x/net/icmp" import "golang.org/x/net/icmp"
import "encoding/binary" import "encoding/binary"
import "errors"
type macAddress [6]byte type macAddress [6]byte
@ -129,14 +130,12 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
response, err := i.handle_ndp(datain[ipv6.HeaderLen:]) response, err := i.handle_ndp(datain[ipv6.HeaderLen:])
if err == nil { if err == nil {
// Create our ICMPv6 response // Create our ICMPv6 response
responsePacket, err := i.create_icmpv6_tun(ipv6Header.Src, ipv6.ICMPTypeNeighborAdvertisement, 0, response) responsePacket, err := i.create_icmpv6_tun(ipv6Header.Src, ipv6.ICMPTypeNeighborAdvertisement, 0,
&icmp.DefaultMessageBody{Data: response})
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Fix the checksum because I don't even know why, net/icmp is stupid
responsePacket[17] ^= 0x4
// Send it back // Send it back
return responsePacket, nil return responsePacket, nil
} else { } else {
@ -145,10 +144,10 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
} }
} }
return nil, nil return nil, errors.New("ICMPv6 type not matched")
} }
func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICMPType, mcode int, mbody []byte) ([]byte, error) { func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
// Pass through to create_icmpv6_tun // Pass through to create_icmpv6_tun
ipv6packet, err := i.create_icmpv6_tun(dst, mtype, mcode, mbody) ipv6packet, err := i.create_icmpv6_tun(dst, mtype, mcode, mbody)
if err != nil { if err != nil {
@ -156,7 +155,7 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM
} }
// Create the response buffer // Create the response buffer
dataout := make([]byte, ETHER+ipv6.HeaderLen+len(mbody)) dataout := make([]byte, ETHER+len(ipv6packet))
// Populate the response ethernet headers // Populate the response ethernet headers
copy(dataout[:6], dstmac[:6]) copy(dataout[:6], dstmac[:6])
@ -168,36 +167,36 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM
return dataout, nil return dataout, nil
} }
func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, mbody []byte) ([]byte, error) { func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
// Create the ICMPv6 message
icmpMessage := icmp.Message{
Type: mtype,
Code: mcode,
Body: mbody,
}
// Convert the ICMPv6 message into []byte
icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(i.mylladdr, dst))
if err != nil {
return nil, err
}
// Create the IPv6 header // Create the IPv6 header
ipv6Header := ipv6.Header{ ipv6Header := ipv6.Header{
Version: ipv6.Version, Version: ipv6.Version,
NextHeader: 58, NextHeader: 58,
PayloadLen: len(mbody), PayloadLen: len(icmpMessageBuf),
HopLimit: 255, HopLimit: 255,
Src: i.mylladdr, Src: i.mylladdr,
Dst: dst, Dst: dst,
} }
// Create the ICMPv6 message
icmpMessage := icmp.Message{
Type: mtype,
Code: mcode,
Body: &icmp.DefaultMessageBody{Data: mbody},
}
// Convert the IPv6 header into []byte // Convert the IPv6 header into []byte
ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header) ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Convert the ICMPv6 message into []byte
icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(ipv6Header.Dst, ipv6Header.Src))
if err != nil {
return nil, err
}
// Construct the packet // Construct the packet
responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen) responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen)
copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf) copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf)
@ -210,11 +209,11 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, m
func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) { func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) {
// Ignore NDP requests for anything outside of fd00::/8 // Ignore NDP requests for anything outside of fd00::/8
if in[8] != 0xFD { if in[8] != 0xFD {
return nil, nil return nil, errors.New("Not an NDP for fd00::/8")
} }
// Create our NDP message body response // Create our NDP message body response
body := make([]byte, 32) body := make([]byte, 28)
binary.BigEndian.PutUint32(body[:4], uint32(0x20000000)) binary.BigEndian.PutUint32(body[:4], uint32(0x20000000))
copy(body[4:20], in[8:24]) // Target address copy(body[4:20], in[8:24]) // Target address
body[20] = uint8(2) body[20] = uint8(2)

View File

@ -23,6 +23,8 @@ package yggdrasil
// The router then runs some sanity checks before passing it to the tun // The router then runs some sanity checks before passing it to the tun
import "time" import "time"
import "golang.org/x/net/icmp"
import "golang.org/x/net/ipv6"
//import "fmt" //import "fmt"
//import "net" //import "net"
@ -145,9 +147,28 @@ func (r *router) sendPacket(bs []byte) {
fallthrough fallthrough
//default: go func() { sinfo.send<-bs }() //default: go func() { sinfo.send<-bs }()
default: default:
// Generate an ICMPv6 Packet Too Big for packets larger than session MTU
if len(bs) > int(sinfo.getMTU()) { if len(bs) > int(sinfo.getMTU()) {
// TODO: Send ICMPv6 Packet Too Big back to the TUN/TAP adapter // Get the size of the oversized payload, up to a max of 900 bytes
sinfo.core.log.Printf("Packet length %d exceeds session MTU %d", len(bs), sinfo.getMTU()) window := 900
if int(sinfo.getMTU()) < window {
window = int(sinfo.getMTU())
}
// Create the Packet Too Big response
ptb := &icmp.PacketTooBig{
MTU: int(sinfo.getMTU()),
Data: bs[:window],
}
// Create the ICMPv6 response from it
icmpv6Buf, err := r.core.tun.icmpv6.create_icmpv6_tun(bs[8:24], ipv6.ICMPTypePacketTooBig, 0, ptb)
if err == nil {
r.recv <- icmpv6Buf
}
// Don't continue - drop the packet
return
} }
select { select {
case sinfo.send <- bs: case sinfo.send <- bs:

View File

@ -279,7 +279,7 @@ func (ss *sessions) handlePing(ping *sessionPing) {
// send // send
var bs []byte var bs []byte
bs, sinfo.packet = sinfo.packet, nil bs, sinfo.packet = sinfo.packet, nil
go func() { sinfo.send <- bs }() ss.core.router.sendPacket(bs)
} }
} }