From 37e4492b86b9f9f47bf60045145ab1590d021c1c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 14 Feb 2018 22:59:24 +0000 Subject: [PATCH 1/3] Send ICMPv6 response to packets larger than session MTU (WIP: checksum wrong?) --- src/yggdrasil/icmpv6.go | 13 +++++++------ src/yggdrasil/router.go | 26 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index f96a9c9a..85a6bbb7 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -129,7 +129,8 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) { response, err := i.handle_ndp(datain[ipv6.HeaderLen:]) if err == nil { // 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 { return nil, err } @@ -148,7 +149,7 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) { return nil, nil } -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 ipv6packet, err := i.create_icmpv6_tun(dst, mtype, mcode, mbody) if err != nil { @@ -156,7 +157,7 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM } // Create the response buffer - dataout := make([]byte, ETHER+ipv6.HeaderLen+len(mbody)) + dataout := make([]byte, ETHER+ipv6.HeaderLen+mbody.Len(0)) // Populate the response ethernet headers copy(dataout[:6], dstmac[:6]) @@ -168,12 +169,12 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM 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 IPv6 header ipv6Header := ipv6.Header{ Version: ipv6.Version, NextHeader: 58, - PayloadLen: len(mbody), + PayloadLen: mbody.Len(0), HopLimit: 255, Src: i.mylladdr, Dst: dst, @@ -183,7 +184,7 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, m icmpMessage := icmp.Message{ Type: mtype, Code: mcode, - Body: &icmp.DefaultMessageBody{Data: mbody}, + Body: mbody, } // Convert the IPv6 header into []byte diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index e0884ef4..abd51c41 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -23,6 +23,8 @@ package yggdrasil // The router then runs some sanity checks before passing it to the tun import "time" +import "golang.org/x/net/icmp" +import "golang.org/x/net/ipv6" //import "fmt" //import "net" @@ -145,9 +147,31 @@ func (r *router) sendPacket(bs []byte) { fallthrough //default: go func() { sinfo.send<-bs }() default: + // Generate an ICMPv6 Packet Too Big for packets larger than session MTU if len(bs) > int(sinfo.getMTU()) { - // TODO: Send ICMPv6 Packet Too Big back to the TUN/TAP adapter sinfo.core.log.Printf("Packet length %d exceeds session MTU %d", len(bs), sinfo.getMTU()) + + // Get the size of the oversized payload, up to a max of 900 bytes + 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 { + sinfo.core.log.Printf("Sending ICMPv6 Message Too Big") + r.recv <- icmpv6Buf + } + + // Don't continue - drop the packet + return } select { case sinfo.send <- bs: From 1c59338f01c89b9bdd823602f2ee1c861d1579e8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 15 Feb 2018 13:38:54 +0000 Subject: [PATCH 2/3] Fix checksums and packet buffers, sends ICMPv6 Packet Too Big messages successfully now --- src/yggdrasil/icmpv6.go | 42 ++++++++++++++++++++--------------------- src/yggdrasil/router.go | 5 +---- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index 85a6bbb7..da62111a 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -8,6 +8,7 @@ import "net" import "golang.org/x/net/ipv6" import "golang.org/x/net/icmp" import "encoding/binary" +import "errors" type macAddress [6]byte @@ -130,14 +131,11 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) { if err == nil { // Create our ICMPv6 response responsePacket, err := i.create_icmpv6_tun(ipv6Header.Src, ipv6.ICMPTypeNeighborAdvertisement, 0, - &icmp.DefaultMessageBody{ Data: response }) + &icmp.DefaultMessageBody{Data: response}) if err != nil { return nil, err } - // Fix the checksum because I don't even know why, net/icmp is stupid - responsePacket[17] ^= 0x4 - // Send it back return responsePacket, nil } else { @@ -146,7 +144,7 @@ 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 icmp.MessageBody) ([]byte, error) { @@ -157,7 +155,7 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM } // Create the response buffer - dataout := make([]byte, ETHER+ipv6.HeaderLen+mbody.Len(0)) + dataout := make([]byte, ETHER+len(ipv6packet)) // Populate the response ethernet headers copy(dataout[:6], dstmac[:6]) @@ -170,16 +168,6 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, mtype ipv6.ICM } func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { - // Create the IPv6 header - ipv6Header := ipv6.Header{ - Version: ipv6.Version, - NextHeader: 58, - PayloadLen: mbody.Len(0), - HopLimit: 255, - Src: i.mylladdr, - Dst: dst, - } - // Create the ICMPv6 message icmpMessage := icmp.Message{ Type: mtype, @@ -187,14 +175,24 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, mtype ipv6.ICMPType, mcode int, m Body: mbody, } - // Convert the IPv6 header into []byte - ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header) + // Convert the ICMPv6 message into []byte + icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(i.mylladdr, dst)) if err != nil { return nil, err } - // Convert the ICMPv6 message into []byte - icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(ipv6Header.Dst, ipv6Header.Src)) + // Create the IPv6 header + ipv6Header := ipv6.Header{ + Version: ipv6.Version, + NextHeader: 58, + PayloadLen: len(icmpMessageBuf), + HopLimit: 255, + Src: i.mylladdr, + Dst: dst, + } + + // Convert the IPv6 header into []byte + ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header) if err != nil { return nil, err } @@ -211,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) { // Ignore NDP requests for anything outside of fd00::/8 if in[8] != 0xFD { - return nil, nil + return nil, errors.New("Not an NDP for fd00::/8") } // Create our NDP message body response - body := make([]byte, 32) + body := make([]byte, 28) binary.BigEndian.PutUint32(body[:4], uint32(0x20000000)) copy(body[4:20], in[8:24]) // Target address body[20] = uint8(2) diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index abd51c41..8ca5d2b9 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -149,8 +149,6 @@ func (r *router) sendPacket(bs []byte) { default: // Generate an ICMPv6 Packet Too Big for packets larger than session MTU if len(bs) > int(sinfo.getMTU()) { - sinfo.core.log.Printf("Packet length %d exceeds session MTU %d", len(bs), sinfo.getMTU()) - // Get the size of the oversized payload, up to a max of 900 bytes window := 900 if int(sinfo.getMTU()) < window { @@ -159,14 +157,13 @@ func (r *router) sendPacket(bs []byte) { // Create the Packet Too Big response ptb := &icmp.PacketTooBig{ - MTU: int(sinfo.getMTU()), + 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 { - sinfo.core.log.Printf("Sending ICMPv6 Message Too Big") r.recv <- icmpv6Buf } From 366d2af1d39c7121351e7907714ee06c61303e2d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 15 Feb 2018 18:02:08 +0000 Subject: [PATCH 3/3] Fix first queued packet on session pcreation --- src/yggdrasil/session.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 681a1940..47a4e987 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -279,7 +279,7 @@ func (ss *sessions) handlePing(ping *sessionPing) { // send var bs []byte bs, sinfo.packet = sinfo.packet, nil - go func() { sinfo.send <- bs }() + ss.core.router.sendPacket(bs) } }