mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-12-24 16:57:53 +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:
parent
0715e829c2
commit
eb22ed44ac
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user