5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-12-23 16:55:40 +00:00

Add new reject channel to router so we can send back rejected packets to adapter (e.g. for ICMPv6 Packet Too Big), implement ICMPv6 PTB in TUN/TAP instead of router

This commit is contained in:
Neil Alexander 2019-03-28 09:50:13 +00:00
parent 0715e829c2
commit eb22ed44ac
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
3 changed files with 135 additions and 96 deletions

View File

@ -11,6 +11,8 @@ import (
"time" "time"
"github.com/gologme/log" "github.com/gologme/log"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
"github.com/songgao/packets/ethernet" "github.com/songgao/packets/ethernet"
"github.com/yggdrasil-network/water" "github.com/yggdrasil-network/water"
@ -64,10 +66,10 @@ func (tun *TunAdapter) IsTAP() bool {
} }
// Initialises the TUN/TAP adapter. // Initialises the TUN/TAP adapter.
func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) {
tun.config = config tun.config = config
tun.log = log tun.log = log
tun.Adapter.Init(config, log, send, recv) tun.Adapter.Init(config, log, send, recv, reject)
tun.icmpv6.Init(tun) tun.icmpv6.Init(tun)
go func() { go func() {
for { for {
@ -146,81 +148,118 @@ func (tun *TunAdapter) Start(a address.Address, s address.Subnet) error {
// host operating system. // host operating system.
func (tun *TunAdapter) Write() error { func (tun *TunAdapter) Write() error {
for { for {
data := <-tun.Recv select {
if tun.iface == nil { case reject := <-tun.Reject:
continue switch reject.Reason {
} case yggdrasil.PacketTooBig:
if tun.iface.IsTAP() { if mtu, ok := reject.Detail.(int); ok {
var destAddr address.Address // Create the Packet Too Big response
if data[0]&0xf0 == 0x60 { ptb := &icmp.PacketTooBig{
if len(data) < 40 { MTU: int(mtu),
//panic("Tried to send a packet shorter than an IPv6 header...") Data: reject.Packet,
util.PutBytes(data) }
continue
// Create the ICMPv6 response from it
icmpv6Buf, err := CreateICMPv6(
reject.Packet[8:24], reject.Packet[24:40],
ipv6.ICMPTypePacketTooBig, 0, ptb)
// Send the ICMPv6 response back to the TUN/TAP adapter
if err == nil {
tun.iface.Write(icmpv6Buf)
}
} }
copy(destAddr[:16], data[24:]) fallthrough
} else if data[0]&0xf0 == 0x40 { default:
if len(data) < 20 { continue
//panic("Tried to send a packet shorter than an IPv4 header...")
util.PutBytes(data)
continue
}
copy(destAddr[:4], data[16:])
} else {
return errors.New("Invalid address family")
} }
sendndp := func(destAddr address.Address) { case data := <-tun.Recv:
neigh, known := tun.icmpv6.peermacs[destAddr] if tun.iface == nil {
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30) continue
if !known { }
request, err := tun.icmpv6.CreateNDPL2(destAddr) if tun.iface.IsTAP() {
if err != nil { var destAddr address.Address
panic(err) if data[0]&0xf0 == 0x60 {
if len(data) < 40 {
//panic("Tried to send a packet shorter than an IPv6 header...")
util.PutBytes(data)
continue
} }
if _, err := tun.iface.Write(request); err != nil { copy(destAddr[:16], data[24:])
panic(err) } else if data[0]&0xf0 == 0x40 {
if len(data) < 20 {
//panic("Tried to send a packet shorter than an IPv4 header...")
util.PutBytes(data)
continue
} }
tun.icmpv6.peermacs[destAddr] = neighbor{ copy(destAddr[:4], data[16:])
lastsolicitation: time.Now(), } else {
return errors.New("Invalid address family")
}
sendndp := func(destAddr address.Address) {
neigh, known := tun.icmpv6.peermacs[destAddr]
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
if !known {
request, err := tun.icmpv6.CreateNDPL2(destAddr)
if err != nil {
panic(err)
}
if _, err := tun.iface.Write(request); err != nil {
panic(err)
}
tun.icmpv6.peermacs[destAddr] = neighbor{
lastsolicitation: time.Now(),
}
} }
} }
} var peermac macAddress
var peermac macAddress var peerknown bool
var peerknown bool if data[0]&0xf0 == 0x40 {
if data[0]&0xf0 == 0x40 {
destAddr = tun.addr
} else if data[0]&0xf0 == 0x60 {
if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) {
destAddr = tun.addr destAddr = tun.addr
} else if data[0]&0xf0 == 0x60 {
if !bytes.Equal(tun.addr[:16], destAddr[:16]) && !bytes.Equal(tun.subnet[:8], destAddr[:8]) {
destAddr = tun.addr
}
}
if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
} else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
sendndp(destAddr)
} else {
sendndp(tun.addr)
}
if peerknown {
var proto ethernet.Ethertype
switch {
case data[0]&0xf0 == 0x60:
proto = ethernet.IPv6
case data[0]&0xf0 == 0x40:
proto = ethernet.IPv4
}
var frame ethernet.Frame
frame.Prepare(
peermac[:6], // Destination MAC address
tun.icmpv6.mymac[:6], // Source MAC address
ethernet.NotTagged, // VLAN tagging
proto, // Ethertype
len(data)) // Payload length
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
if _, err := tun.iface.Write(frame); err != nil {
tun.mutex.RLock()
open := tun.isOpen
tun.mutex.RUnlock()
if !open {
return nil
} else {
panic(err)
}
}
} }
}
if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
} else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
sendndp(destAddr)
} else { } else {
sendndp(tun.addr) if _, err := tun.iface.Write(data); err != nil {
}
if peerknown {
var proto ethernet.Ethertype
switch {
case data[0]&0xf0 == 0x60:
proto = ethernet.IPv6
case data[0]&0xf0 == 0x40:
proto = ethernet.IPv4
}
var frame ethernet.Frame
frame.Prepare(
peermac[:6], // Destination MAC address
tun.icmpv6.mymac[:6], // Source MAC address
ethernet.NotTagged, // VLAN tagging
proto, // Ethertype
len(data)) // Payload length
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
if _, err := tun.iface.Write(frame); err != nil {
tun.mutex.RLock() tun.mutex.RLock()
open := tun.isOpen open := tun.isOpen
tun.mutex.RUnlock() tun.mutex.RUnlock()
@ -231,19 +270,8 @@ func (tun *TunAdapter) Write() error {
} }
} }
} }
} else { util.PutBytes(data)
if _, err := tun.iface.Write(data); err != nil {
tun.mutex.RLock()
open := tun.isOpen
tun.mutex.RUnlock()
if !open {
return nil
} else {
panic(err)
}
}
} }
util.PutBytes(data)
} }
} }

View File

@ -13,12 +13,13 @@ type Adapter struct {
Core *Core Core *Core
Send chan<- []byte Send chan<- []byte
Recv <-chan []byte Recv <-chan []byte
Reject <-chan RejectedPacket
Reconfigure chan chan error Reconfigure chan chan error
} }
// Defines the minimum required functions for an adapter type // Defines the minimum required functions for an adapter type
type adapterImplementation interface { type adapterImplementation interface {
Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte) Init(*config.NodeState, *log.Logger, chan<- []byte, <-chan []byte, <-chan RejectedPacket)
Name() string Name() string
MTU() int MTU() int
IsTAP() bool IsTAP() bool
@ -29,9 +30,10 @@ type adapterImplementation interface {
} }
// Initialises the adapter. // Initialises the adapter.
func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte) { func (adapter *Adapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan RejectedPacket) {
log.Traceln("Adapter setup - given channels:", send, recv) log.Traceln("Adapter setup - given channels:", send, recv)
adapter.Send = send adapter.Send = send
adapter.Recv = recv adapter.Recv = recv
adapter.Reject = reject
adapter.Reconfigure = make(chan chan error, 1) adapter.Reconfigure = make(chan chan error, 1)
} }

View File

@ -44,6 +44,7 @@ type router struct {
tun adapterImplementation // TUN/TAP adapter tun adapterImplementation // TUN/TAP adapter
recv chan<- []byte // place where the tun pulls received packets from recv chan<- []byte // place where the tun pulls received packets from
send <-chan []byte // place where the tun puts outgoing packets send <-chan []byte // place where the tun puts outgoing packets
reject chan<- RejectedPacket // place where we send error packets back to tun
reset chan struct{} // signal that coords changed (re-init sessions/dht) reset chan struct{} // signal that coords changed (re-init sessions/dht)
admin chan func() // pass a lambda for the admin socket to query stuff admin chan func() // pass a lambda for the admin socket to query stuff
cryptokey cryptokey cryptokey cryptokey
@ -56,6 +57,19 @@ type router_recvPacket struct {
sinfo *sessionInfo sinfo *sessionInfo
} }
type RejectedPacketReason int
const (
// The router rejected the packet because it is too big for the session
PacketTooBig = 1 + iota
)
type RejectedPacket struct {
Reason RejectedPacketReason
Packet []byte
Detail interface{}
}
// Initializes the router struct, which includes setting up channels to/from the tun/tap. // Initializes the router struct, which includes setting up channels to/from the tun/tap.
func (r *router) init(core *Core) { func (r *router) init(core *Core) {
r.core = core r.core = core
@ -103,8 +117,10 @@ func (r *router) init(core *Core) {
r.toRecv = make(chan router_recvPacket, 32) r.toRecv = make(chan router_recvPacket, 32)
recv := make(chan []byte, 32) recv := make(chan []byte, 32)
send := make(chan []byte, 32) send := make(chan []byte, 32)
reject := make(chan RejectedPacket, 32)
r.recv = recv r.recv = recv
r.send = send r.send = send
r.reject = reject
r.reset = make(chan struct{}, 1) r.reset = make(chan struct{}, 1)
r.admin = make(chan func(), 32) r.admin = make(chan func(), 32)
r.nodeinfo.init(r.core) r.nodeinfo.init(r.core)
@ -112,7 +128,7 @@ func (r *router) init(core *Core) {
r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy) r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy)
r.core.config.Mutex.RUnlock() r.core.config.Mutex.RUnlock()
r.cryptokey.init(r.core) r.cryptokey.init(r.core)
r.tun.Init(&r.core.config, r.core.log, send, recv) r.tun.Init(&r.core.config, r.core.log, send, recv, reject)
} }
// Starts the mainLoop goroutine. // Starts the mainLoop goroutine.
@ -303,25 +319,18 @@ func (r *router) sendPacket(bs []byte) {
// Generate an ICMPv6 Packet Too Big for packets larger than session MTU // Generate an ICMPv6 Packet Too Big for packets larger than session MTU
if len(bs) > int(sinfo.getMTU()) { if len(bs) > int(sinfo.getMTU()) {
// Get the size of the oversized payload, up to a max of 900 bytes // Get the size of the oversized payload, up to a max of 900 bytes
/*window := 900 window := 900
if int(sinfo.getMTU()) < window { if int(sinfo.getMTU()) < window {
window = int(sinfo.getMTU()) window = int(sinfo.getMTU())
} }
// Create the Packet Too Big response // Send the error back to the adapter
ptb := &icmp.PacketTooBig{ r.reject <- RejectedPacket{
MTU: int(sinfo.getMTU()), Reason: PacketTooBig,
Data: bs[:window], Packet: bs[:window],
Detail: int(sinfo.getMTU()),
} }
// Create the ICMPv6 response from it
icmpv6Buf, err := CreateICMPv6(
bs[8:24], bs[24:40],
ipv6.ICMPTypePacketTooBig, 0, ptb)
if err == nil {
r.recv <- icmpv6Buf
}*/
// Don't continue - drop the packet // Don't continue - drop the packet
return return
} }