mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Try using separate workers for each TUN/TAP connection (sometimes produces duplicate packets when communicating with both the node address and a subnet address, sometimes also can't Ctrl-C to quit)
This commit is contained in:
		
							parent
							
								
									6469e39ff1
								
							
						
					
					
						commit
						5f66c4c95c
					
				
					 3 changed files with 376 additions and 474 deletions
				
			
		
							
								
								
									
										75
									
								
								src/tuntap/conn.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/tuntap/conn.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
package tuntap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tunConn struct {
 | 
			
		||||
	tun  *TunAdapter
 | 
			
		||||
	conn *yggdrasil.Conn
 | 
			
		||||
	send chan []byte
 | 
			
		||||
	stop chan interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tunConn) close() {
 | 
			
		||||
	close(s.stop)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tunConn) reader() error {
 | 
			
		||||
	select {
 | 
			
		||||
	case _, ok := <-s.stop:
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return errors.New("session was already closed")
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
	var n int
 | 
			
		||||
	var err error
 | 
			
		||||
	read := make(chan bool)
 | 
			
		||||
	b := make([]byte, 65535)
 | 
			
		||||
	for {
 | 
			
		||||
		go func() {
 | 
			
		||||
			if n, err = s.conn.Read(b); err != nil {
 | 
			
		||||
				s.tun.log.Errorln(s.conn.String(), "TUN/TAP conn read error:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			read <- true
 | 
			
		||||
		}()
 | 
			
		||||
		select {
 | 
			
		||||
		case <-read:
 | 
			
		||||
			if n > 0 {
 | 
			
		||||
				s.tun.send <- b[:n]
 | 
			
		||||
			}
 | 
			
		||||
		case <-s.stop:
 | 
			
		||||
			s.tun.log.Debugln("Stopping conn reader for", s)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tunConn) writer() error {
 | 
			
		||||
	select {
 | 
			
		||||
	case _, ok := <-s.stop:
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return errors.New("session was already closed")
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-s.stop:
 | 
			
		||||
			s.tun.log.Debugln("Stopping conn writer for", s)
 | 
			
		||||
			return nil
 | 
			
		||||
		case b, ok := <-s.send:
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return errors.New("send closed")
 | 
			
		||||
			}
 | 
			
		||||
			if _, err := s.conn.Write(b); err != nil {
 | 
			
		||||
				s.tun.log.Errorln(s.conn.String(), "TUN/TAP conn write error:", err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										255
									
								
								src/tuntap/iface.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								src/tuntap/iface.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,255 @@
 | 
			
		|||
package tuntap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/songgao/packets/ethernet"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (tun *TunAdapter) writer() error {
 | 
			
		||||
	var w int
 | 
			
		||||
	var err error
 | 
			
		||||
	for {
 | 
			
		||||
		b := <-tun.send
 | 
			
		||||
		n := len(b)
 | 
			
		||||
		if n == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			var dstAddr address.Address
 | 
			
		||||
			if b[0]&0xf0 == 0x60 {
 | 
			
		||||
				if len(b) < 40 {
 | 
			
		||||
					//panic("Tried to send a packet shorter than an IPv6 header...")
 | 
			
		||||
					util.PutBytes(b)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				copy(dstAddr[:16], b[24:])
 | 
			
		||||
			} else if b[0]&0xf0 == 0x40 {
 | 
			
		||||
				if len(b) < 20 {
 | 
			
		||||
					//panic("Tried to send a packet shorter than an IPv4 header...")
 | 
			
		||||
					util.PutBytes(b)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				copy(dstAddr[:4], b[16:])
 | 
			
		||||
			} else {
 | 
			
		||||
				return errors.New("Invalid address family")
 | 
			
		||||
			}
 | 
			
		||||
			sendndp := func(dstAddr address.Address) {
 | 
			
		||||
				neigh, known := tun.icmpv6.peermacs[dstAddr]
 | 
			
		||||
				known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
 | 
			
		||||
				if !known {
 | 
			
		||||
					request, err := tun.icmpv6.CreateNDPL2(dstAddr)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						panic(err)
 | 
			
		||||
					}
 | 
			
		||||
					if _, err := tun.iface.Write(request); err != nil {
 | 
			
		||||
						panic(err)
 | 
			
		||||
					}
 | 
			
		||||
					tun.icmpv6.peermacs[dstAddr] = neighbor{
 | 
			
		||||
						lastsolicitation: time.Now(),
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var peermac macAddress
 | 
			
		||||
			var peerknown bool
 | 
			
		||||
			if b[0]&0xf0 == 0x40 {
 | 
			
		||||
				dstAddr = tun.addr
 | 
			
		||||
			} else if b[0]&0xf0 == 0x60 {
 | 
			
		||||
				if !bytes.Equal(tun.addr[:16], dstAddr[:16]) && !bytes.Equal(tun.subnet[:8], dstAddr[:8]) {
 | 
			
		||||
					dstAddr = tun.addr
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if neighbor, ok := tun.icmpv6.peermacs[dstAddr]; 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(dstAddr)
 | 
			
		||||
			} else {
 | 
			
		||||
				sendndp(tun.addr)
 | 
			
		||||
			}
 | 
			
		||||
			if peerknown {
 | 
			
		||||
				var proto ethernet.Ethertype
 | 
			
		||||
				switch {
 | 
			
		||||
				case b[0]&0xf0 == 0x60:
 | 
			
		||||
					proto = ethernet.IPv6
 | 
			
		||||
				case b[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(b))               // Payload length
 | 
			
		||||
				copy(frame[tun_ETHER_HEADER_LENGTH:], b[:n])
 | 
			
		||||
				n += tun_ETHER_HEADER_LENGTH
 | 
			
		||||
				w, err = tun.iface.Write(frame[:n])
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			w, err = tun.iface.Write(b[:n])
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			tun.log.Errorln("TUN/TAP iface write error:", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if w != n {
 | 
			
		||||
			tun.log.Errorln("TUN/TAP iface write mismatch:", w, "bytes written vs", n, "bytes given")
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *TunAdapter) reader() error {
 | 
			
		||||
	bs := make([]byte, 65535)
 | 
			
		||||
	for {
 | 
			
		||||
		// Wait for a packet to be delivered to us through the TUN/TAP adapter
 | 
			
		||||
		n, err := tun.iface.Read(bs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		if n == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// If it's a TAP adapter, update the buffer slice so that we no longer
 | 
			
		||||
		// include the ethernet headers
 | 
			
		||||
		offset := 0
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			// Set our offset to beyond the ethernet headers
 | 
			
		||||
			offset = tun_ETHER_HEADER_LENGTH
 | 
			
		||||
			// If we detect an ICMP packet then hand it to the ICMPv6 module
 | 
			
		||||
			if bs[offset+6] == 58 {
 | 
			
		||||
				// Found an ICMPv6 packet
 | 
			
		||||
				b := make([]byte, n)
 | 
			
		||||
				copy(b, bs)
 | 
			
		||||
				go tun.icmpv6.ParsePacket(b)
 | 
			
		||||
			}
 | 
			
		||||
			// Then offset the buffer so that we can now just treat it as an IP
 | 
			
		||||
			// packet from now on
 | 
			
		||||
			bs = bs[offset:]
 | 
			
		||||
		}
 | 
			
		||||
		// From the IP header, work out what our source and destination addresses
 | 
			
		||||
		// and node IDs are. We will need these in order to work out where to send
 | 
			
		||||
		// the packet
 | 
			
		||||
		var srcAddr address.Address
 | 
			
		||||
		var dstAddr address.Address
 | 
			
		||||
		var dstNodeID *crypto.NodeID
 | 
			
		||||
		var dstNodeIDMask *crypto.NodeID
 | 
			
		||||
		var dstSnet address.Subnet
 | 
			
		||||
		var addrlen int
 | 
			
		||||
		// Check the IP protocol - if it doesn't match then we drop the packet and
 | 
			
		||||
		// do nothing with it
 | 
			
		||||
		if bs[0]&0xf0 == 0x60 {
 | 
			
		||||
			// Check if we have a fully-sized IPv6 header
 | 
			
		||||
			if len(bs) < 40 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// Check the packet size
 | 
			
		||||
			if n != 256*int(bs[4])+int(bs[5])+offset+tun_IPv6_HEADER_LENGTH {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// IPv6 address
 | 
			
		||||
			addrlen = 16
 | 
			
		||||
			copy(srcAddr[:addrlen], bs[8:])
 | 
			
		||||
			copy(dstAddr[:addrlen], bs[24:])
 | 
			
		||||
			copy(dstSnet[:addrlen/2], bs[24:])
 | 
			
		||||
		} else if bs[0]&0xf0 == 0x40 {
 | 
			
		||||
			// Check if we have a fully-sized IPv4 header
 | 
			
		||||
			if len(bs) < 20 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// Check the packet size
 | 
			
		||||
			if n != 256*int(bs[2])+int(bs[3])+offset {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// IPv4 address
 | 
			
		||||
			addrlen = 4
 | 
			
		||||
			copy(srcAddr[:addrlen], bs[12:])
 | 
			
		||||
			copy(dstAddr[:addrlen], bs[16:])
 | 
			
		||||
		} else {
 | 
			
		||||
			// Unknown address length or protocol, so drop the packet and ignore it
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
			// For now don't deal with any non-Yggdrasil ranges
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// Do we have an active connection for this node address?
 | 
			
		||||
		tun.mutex.RLock()
 | 
			
		||||
		session, isIn := tun.addrToConn[dstAddr]
 | 
			
		||||
		if !isIn || session == nil {
 | 
			
		||||
			session, isIn = tun.subnetToConn[dstSnet]
 | 
			
		||||
			if !isIn || session == nil {
 | 
			
		||||
				// Neither an address nor a subnet mapping matched, therefore populate
 | 
			
		||||
				// the node ID and mask to commence a search
 | 
			
		||||
				dstNodeID, dstNodeIDMask = dstAddr.GetNodeIDandMask()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		tun.mutex.RUnlock()
 | 
			
		||||
		// If we don't have a connection then we should open one
 | 
			
		||||
		if !isIn || session == nil {
 | 
			
		||||
			// Check we haven't been given empty node ID, really this shouldn't ever
 | 
			
		||||
			// happen but just to be sure...
 | 
			
		||||
			if dstNodeID == nil || dstNodeIDMask == nil {
 | 
			
		||||
				panic("Given empty dstNodeID and dstNodeIDMask - this shouldn't happen")
 | 
			
		||||
			}
 | 
			
		||||
			// Dial to the remote node
 | 
			
		||||
			if conn, err := tun.dialer.DialByNodeIDandMask(dstNodeID, dstNodeIDMask); err == nil {
 | 
			
		||||
				// We've been given a connection so prepare the session wrapper
 | 
			
		||||
				if s, err := tun.wrap(conn); err != nil {
 | 
			
		||||
					// Something went wrong when storing the connection, typically that
 | 
			
		||||
					// something already exists for this address or subnet
 | 
			
		||||
					tun.log.Debugln("TUN/TAP iface wrap:", err)
 | 
			
		||||
				} else {
 | 
			
		||||
					// Update our reference to the connection
 | 
			
		||||
					session, isIn = s, true
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// We weren't able to dial for some reason so there's no point in
 | 
			
		||||
				// continuing this iteration - skip to the next one
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// If we have a connection now, try writing to it
 | 
			
		||||
		if isIn && session != nil {
 | 
			
		||||
			select {
 | 
			
		||||
			case session.send <- bs[:n]:
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*if !r.cryptokey.isValidSource(srcAddr, addrlen) {
 | 
			
		||||
			// The packet had a src address that doesn't belong to us or our
 | 
			
		||||
			// configured crypto-key routing src subnets
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
			// The addresses didn't match valid Yggdrasil node addresses so let's see
 | 
			
		||||
			// whether it matches a crypto-key routing range instead
 | 
			
		||||
			if key, err := r.cryptokey.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
 | 
			
		||||
				// A public key was found, get the node ID for the search
 | 
			
		||||
				dstPubKey = &key
 | 
			
		||||
				dstNodeID = crypto.GetNodeID(dstPubKey)
 | 
			
		||||
				// Do a quick check to ensure that the node ID refers to a vaild Yggdrasil
 | 
			
		||||
				// address or subnet - this might be superfluous
 | 
			
		||||
				addr := *address.AddrForNodeID(dstNodeID)
 | 
			
		||||
				copy(dstAddr[:], addr[:])
 | 
			
		||||
				copy(dstSnet[:], addr[:])
 | 
			
		||||
				if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// No public key was found in the CKR table so we've exhausted our options
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}*/
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -6,10 +6,9 @@ package tuntap
 | 
			
		|||
// TODO: Set MTU of session properly
 | 
			
		||||
// TODO: Reject packets that exceed session MTU with ICMPv6 for PMTU Discovery
 | 
			
		||||
// TODO: Connection timeouts (call Conn.Close() when we want to time out)
 | 
			
		||||
// TODO: Don't block in ifaceReader on writes that are pending searches
 | 
			
		||||
// TODO: Don't block in reader on writes that are pending searches
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
| 
						 | 
				
			
			@ -18,14 +17,12 @@ import (
 | 
			
		|||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gologme/log"
 | 
			
		||||
	"github.com/songgao/packets/ethernet"
 | 
			
		||||
	"github.com/yggdrasil-network/water"
 | 
			
		||||
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/config"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/util"
 | 
			
		||||
	"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +44,10 @@ type TunAdapter struct {
 | 
			
		|||
	icmpv6       ICMPv6
 | 
			
		||||
	mtu          int
 | 
			
		||||
	iface        *water.Interface
 | 
			
		||||
	mutex        sync.RWMutex                        // Protects the below
 | 
			
		||||
	addrToConn   map[address.Address]*yggdrasil.Conn // Managed by connReader
 | 
			
		||||
	subnetToConn map[address.Subnet]*yggdrasil.Conn  // Managed by connReader
 | 
			
		||||
	send         chan []byte
 | 
			
		||||
	mutex        sync.RWMutex // Protects the below
 | 
			
		||||
	addrToConn   map[address.Address]*tunConn
 | 
			
		||||
	subnetToConn map[address.Subnet]*tunConn
 | 
			
		||||
	isOpen       bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -112,8 +110,8 @@ func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, listener
 | 
			
		|||
	tun.log = log
 | 
			
		||||
	tun.listener = listener
 | 
			
		||||
	tun.dialer = dialer
 | 
			
		||||
	tun.addrToConn = make(map[address.Address]*yggdrasil.Conn)
 | 
			
		||||
	tun.subnetToConn = make(map[address.Subnet]*yggdrasil.Conn)
 | 
			
		||||
	tun.addrToConn = make(map[address.Address]*tunConn)
 | 
			
		||||
	tun.subnetToConn = make(map[address.Subnet]*tunConn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start the setup process for the TUN/TAP adapter. If successful, starts the
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +146,7 @@ func (tun *TunAdapter) Start() error {
 | 
			
		|||
	}
 | 
			
		||||
	tun.mutex.Lock()
 | 
			
		||||
	tun.isOpen = true
 | 
			
		||||
	tun.send = make(chan []byte, 32) // TODO: is this a sensible value?
 | 
			
		||||
	tun.mutex.Unlock()
 | 
			
		||||
	if iftapmode {
 | 
			
		||||
		go func() {
 | 
			
		||||
| 
						 | 
				
			
			@ -159,9 +158,7 @@ func (tun *TunAdapter) Start() error {
 | 
			
		|||
				if err != nil {
 | 
			
		||||
					panic(err)
 | 
			
		||||
				}
 | 
			
		||||
				if _, err := tun.iface.Write(request); err != nil {
 | 
			
		||||
					panic(err)
 | 
			
		||||
				}
 | 
			
		||||
				tun.send <- request
 | 
			
		||||
				time.Sleep(time.Second)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +170,8 @@ func (tun *TunAdapter) Start() error {
 | 
			
		|||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	go tun.handler()
 | 
			
		||||
	go tun.ifaceReader()
 | 
			
		||||
	go tun.reader()
 | 
			
		||||
	go tun.writer()
 | 
			
		||||
	tun.icmpv6.Init(tun)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -186,473 +184,47 @@ func (tun *TunAdapter) handler() error {
 | 
			
		|||
			tun.log.Errorln("TUN/TAP connection accept error:", err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		go tun.connReader(conn)
 | 
			
		||||
		if _, err := tun.wrap(conn); err != nil {
 | 
			
		||||
			// Something went wrong when storing the connection, typically that
 | 
			
		||||
			// something already exists for this address or subnet
 | 
			
		||||
			tun.log.Debugln("TUN/TAP handler wrap:", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *TunAdapter) connReader(conn *yggdrasil.Conn) error {
 | 
			
		||||
func (tun *TunAdapter) wrap(conn *yggdrasil.Conn) (c *tunConn, err error) {
 | 
			
		||||
	// Prepare a session wrapper for the given connection
 | 
			
		||||
	s := tunConn{
 | 
			
		||||
		tun:  tun,
 | 
			
		||||
		conn: conn,
 | 
			
		||||
		send: make(chan []byte, 32), // TODO: is this a sensible value?
 | 
			
		||||
		stop: make(chan interface{}),
 | 
			
		||||
	}
 | 
			
		||||
	// Get the remote address and subnet of the other side
 | 
			
		||||
	remoteNodeID := conn.RemoteAddr()
 | 
			
		||||
	remoteAddr := address.AddrForNodeID(&remoteNodeID)
 | 
			
		||||
	remoteSubnet := address.SubnetForNodeID(&remoteNodeID)
 | 
			
		||||
	err := func() error {
 | 
			
		||||
		tun.mutex.RLock()
 | 
			
		||||
		defer tun.mutex.RUnlock()
 | 
			
		||||
		if _, isIn := tun.addrToConn[*remoteAddr]; isIn {
 | 
			
		||||
			return errors.New("duplicate connection for address " + net.IP(remoteAddr[:]).String())
 | 
			
		||||
		}
 | 
			
		||||
		if _, isIn := tun.subnetToConn[*remoteSubnet]; isIn {
 | 
			
		||||
			return errors.New("duplicate connection for subnet " + net.IP(remoteSubnet[:]).String())
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		//return err
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	// Store the connection mapped to address and subnet
 | 
			
		||||
	// Work out if this is already a destination we already know about
 | 
			
		||||
	tun.mutex.Lock()
 | 
			
		||||
	tun.addrToConn[*remoteAddr] = conn
 | 
			
		||||
	tun.subnetToConn[*remoteSubnet] = conn
 | 
			
		||||
	tun.mutex.Unlock()
 | 
			
		||||
	// Make sure to clean those up later when the connection is closed
 | 
			
		||||
	defer func() {
 | 
			
		||||
		tun.mutex.Lock()
 | 
			
		||||
		delete(tun.addrToConn, *remoteAddr)
 | 
			
		||||
		delete(tun.subnetToConn, *remoteSubnet)
 | 
			
		||||
		tun.mutex.Unlock()
 | 
			
		||||
	}()
 | 
			
		||||
	b := make([]byte, 65535)
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := conn.Read(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			tun.log.Errorln(conn.String(), "TUN/TAP conn read error:", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if n == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		var w int
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			var dstAddr address.Address
 | 
			
		||||
			if b[0]&0xf0 == 0x60 {
 | 
			
		||||
				if len(b) < 40 {
 | 
			
		||||
					//panic("Tried to send a packet shorter than an IPv6 header...")
 | 
			
		||||
					util.PutBytes(b)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				copy(dstAddr[:16], b[24:])
 | 
			
		||||
			} else if b[0]&0xf0 == 0x40 {
 | 
			
		||||
				if len(b) < 20 {
 | 
			
		||||
					//panic("Tried to send a packet shorter than an IPv4 header...")
 | 
			
		||||
					util.PutBytes(b)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				copy(dstAddr[:4], b[16:])
 | 
			
		||||
			} else {
 | 
			
		||||
				return errors.New("Invalid address family")
 | 
			
		||||
			}
 | 
			
		||||
			sendndp := func(dstAddr address.Address) {
 | 
			
		||||
				neigh, known := tun.icmpv6.peermacs[dstAddr]
 | 
			
		||||
				known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
 | 
			
		||||
				if !known {
 | 
			
		||||
					request, err := tun.icmpv6.CreateNDPL2(dstAddr)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						panic(err)
 | 
			
		||||
					}
 | 
			
		||||
					if _, err := tun.iface.Write(request); err != nil {
 | 
			
		||||
						panic(err)
 | 
			
		||||
					}
 | 
			
		||||
					tun.icmpv6.peermacs[dstAddr] = neighbor{
 | 
			
		||||
						lastsolicitation: time.Now(),
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var peermac macAddress
 | 
			
		||||
			var peerknown bool
 | 
			
		||||
			if b[0]&0xf0 == 0x40 {
 | 
			
		||||
				dstAddr = tun.addr
 | 
			
		||||
			} else if b[0]&0xf0 == 0x60 {
 | 
			
		||||
				if !bytes.Equal(tun.addr[:16], dstAddr[:16]) && !bytes.Equal(tun.subnet[:8], dstAddr[:8]) {
 | 
			
		||||
					dstAddr = tun.addr
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if neighbor, ok := tun.icmpv6.peermacs[dstAddr]; 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(dstAddr)
 | 
			
		||||
			} else {
 | 
			
		||||
				sendndp(tun.addr)
 | 
			
		||||
			}
 | 
			
		||||
			if peerknown {
 | 
			
		||||
				var proto ethernet.Ethertype
 | 
			
		||||
				switch {
 | 
			
		||||
				case b[0]&0xf0 == 0x60:
 | 
			
		||||
					proto = ethernet.IPv6
 | 
			
		||||
				case b[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(b))               // Payload length
 | 
			
		||||
				copy(frame[tun_ETHER_HEADER_LENGTH:], b[:n])
 | 
			
		||||
				n += tun_ETHER_HEADER_LENGTH
 | 
			
		||||
				w, err = tun.iface.Write(frame[:n])
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			w, err = tun.iface.Write(b[:n])
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			tun.log.Errorln(conn.String(), "TUN/TAP iface write error:", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if w != n {
 | 
			
		||||
			tun.log.Errorln(conn.String(), "TUN/TAP iface write mismatch:", w, "bytes written vs", n, "bytes given")
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	defer tun.mutex.Unlock()
 | 
			
		||||
	atc, aok := tun.addrToConn[*remoteAddr]
 | 
			
		||||
	stc, sok := tun.subnetToConn[*remoteSubnet]
 | 
			
		||||
	// If we know about a connection for this destination already then assume it
 | 
			
		||||
	// is no longer valid and close it
 | 
			
		||||
	if aok {
 | 
			
		||||
		atc.close()
 | 
			
		||||
		err = errors.New("replaced connection for address")
 | 
			
		||||
	} else if sok {
 | 
			
		||||
		stc.close()
 | 
			
		||||
		err = errors.New("replaced connection for subnet")
 | 
			
		||||
	}
 | 
			
		||||
	// Save the session wrapper so that we can look it up quickly next time
 | 
			
		||||
	// we receive a packet through the interface for this address
 | 
			
		||||
	tun.addrToConn[*remoteAddr] = &s
 | 
			
		||||
	tun.subnetToConn[*remoteSubnet] = &s
 | 
			
		||||
	// Start the connection goroutines
 | 
			
		||||
	go s.reader()
 | 
			
		||||
	go s.writer()
 | 
			
		||||
	// Return
 | 
			
		||||
	return c, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *TunAdapter) ifaceReader() error {
 | 
			
		||||
	bs := make([]byte, 65535)
 | 
			
		||||
	for {
 | 
			
		||||
		// Wait for a packet to be delivered to us through the TUN/TAP adapter
 | 
			
		||||
		n, err := tun.iface.Read(bs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// If it's a TAP adapter, update the buffer slice so that we no longer
 | 
			
		||||
		// include the ethernet headers
 | 
			
		||||
		offset := 0
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			// Set our offset to beyond the ethernet headers
 | 
			
		||||
			offset = tun_ETHER_HEADER_LENGTH
 | 
			
		||||
			// If we detect an ICMP packet then hand it to the ICMPv6 module
 | 
			
		||||
			if bs[offset+6] == 58 {
 | 
			
		||||
				// Found an ICMPv6 packet
 | 
			
		||||
				b := make([]byte, n)
 | 
			
		||||
				copy(b, bs)
 | 
			
		||||
				go tun.icmpv6.ParsePacket(b)
 | 
			
		||||
			}
 | 
			
		||||
			// Then offset the buffer so that we can now just treat it as an IP
 | 
			
		||||
			// packet from now on
 | 
			
		||||
			bs = bs[offset:]
 | 
			
		||||
		}
 | 
			
		||||
		// From the IP header, work out what our source and destination addresses
 | 
			
		||||
		// and node IDs are. We will need these in order to work out where to send
 | 
			
		||||
		// the packet
 | 
			
		||||
		var srcAddr address.Address
 | 
			
		||||
		var dstAddr address.Address
 | 
			
		||||
		var dstNodeID *crypto.NodeID
 | 
			
		||||
		var dstNodeIDMask *crypto.NodeID
 | 
			
		||||
		var dstSnet address.Subnet
 | 
			
		||||
		var addrlen int
 | 
			
		||||
		// Check the IP protocol - if it doesn't match then we drop the packet and
 | 
			
		||||
		// do nothing with it
 | 
			
		||||
		if bs[0]&0xf0 == 0x60 {
 | 
			
		||||
			// Check if we have a fully-sized IPv6 header
 | 
			
		||||
			if len(bs) < 40 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// Check the packet size
 | 
			
		||||
			if n != 256*int(bs[4])+int(bs[5])+offset+tun_IPv6_HEADER_LENGTH {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// IPv6 address
 | 
			
		||||
			addrlen = 16
 | 
			
		||||
			copy(srcAddr[:addrlen], bs[8:])
 | 
			
		||||
			copy(dstAddr[:addrlen], bs[24:])
 | 
			
		||||
			copy(dstSnet[:addrlen/2], bs[24:])
 | 
			
		||||
		} else if bs[0]&0xf0 == 0x40 {
 | 
			
		||||
			// Check if we have a fully-sized IPv4 header
 | 
			
		||||
			if len(bs) < 20 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// Check the packet size
 | 
			
		||||
			if n != 256*int(bs[2])+int(bs[3])+offset {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// IPv4 address
 | 
			
		||||
			addrlen = 4
 | 
			
		||||
			copy(srcAddr[:addrlen], bs[12:])
 | 
			
		||||
			copy(dstAddr[:addrlen], bs[16:])
 | 
			
		||||
		} else {
 | 
			
		||||
			// Unknown address length or protocol, so drop the packet and ignore it
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
			// For now don't deal with any non-Yggdrasil ranges
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// Do we have an active connection for this node address?
 | 
			
		||||
		tun.mutex.RLock()
 | 
			
		||||
		conn, isIn := tun.addrToConn[dstAddr]
 | 
			
		||||
		if !isIn || conn == nil {
 | 
			
		||||
			conn, isIn = tun.subnetToConn[dstSnet]
 | 
			
		||||
			if !isIn || conn == nil {
 | 
			
		||||
				// Neither an address nor a subnet mapping matched, therefore populate
 | 
			
		||||
				// the node ID and mask to commence a search
 | 
			
		||||
				dstNodeID, dstNodeIDMask = dstAddr.GetNodeIDandMask()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		tun.mutex.RUnlock()
 | 
			
		||||
		// If we don't have a connection then we should open one
 | 
			
		||||
		if !isIn || conn == nil {
 | 
			
		||||
			// Check we haven't been given empty node ID, really this shouldn't ever
 | 
			
		||||
			// happen but just to be sure...
 | 
			
		||||
			if dstNodeID == nil || dstNodeIDMask == nil {
 | 
			
		||||
				panic("Given empty dstNodeID and dstNodeIDMask - this shouldn't happen")
 | 
			
		||||
			}
 | 
			
		||||
			// Dial to the remote node
 | 
			
		||||
			if c, err := tun.dialer.DialByNodeIDandMask(dstNodeID, dstNodeIDMask); err == nil {
 | 
			
		||||
				// We've been given a connection so start the connection reader goroutine
 | 
			
		||||
				go tun.connReader(c)
 | 
			
		||||
				// Then update our reference to the connection
 | 
			
		||||
				conn, isIn = c, true
 | 
			
		||||
			} else {
 | 
			
		||||
				// We weren't able to dial for some reason so there's no point in
 | 
			
		||||
				// continuing this iteration - skip to the next one
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// If we have a connection now, try writing to it
 | 
			
		||||
		if isIn && conn != nil {
 | 
			
		||||
			// If we have an open connection, either because we already had one or
 | 
			
		||||
			// because we opened one above, try writing the packet to it
 | 
			
		||||
			w, err := conn.Write(bs[:n])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				tun.log.Errorln(conn.String(), "TUN/TAP conn write error:", err)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if w != n {
 | 
			
		||||
				tun.log.Errorln(conn.String(), "TUN/TAP conn write mismatch:", w, "bytes written vs", n, "bytes given")
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*if !r.cryptokey.isValidSource(srcAddr, addrlen) {
 | 
			
		||||
			// The packet had a src address that doesn't belong to us or our
 | 
			
		||||
			// configured crypto-key routing src subnets
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
			// The addresses didn't match valid Yggdrasil node addresses so let's see
 | 
			
		||||
			// whether it matches a crypto-key routing range instead
 | 
			
		||||
			if key, err := r.cryptokey.getPublicKeyForAddress(dstAddr, addrlen); err == nil {
 | 
			
		||||
				// A public key was found, get the node ID for the search
 | 
			
		||||
				dstPubKey = &key
 | 
			
		||||
				dstNodeID = crypto.GetNodeID(dstPubKey)
 | 
			
		||||
				// Do a quick check to ensure that the node ID refers to a vaild Yggdrasil
 | 
			
		||||
				// address or subnet - this might be superfluous
 | 
			
		||||
				addr := *address.AddrForNodeID(dstNodeID)
 | 
			
		||||
				copy(dstAddr[:], addr[:])
 | 
			
		||||
				copy(dstSnet[:], addr[:])
 | 
			
		||||
				if !dstAddr.IsValid() && !dstSnet.IsValid() {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// No public key was found in the CKR table so we've exhausted our options
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}*/
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP
 | 
			
		||||
// mode then additional ethernet encapsulation is added for the benefit of the
 | 
			
		||||
// host operating system.
 | 
			
		||||
/*
 | 
			
		||||
func (tun *TunAdapter) write() error {
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case reject := <-tun.Reject:
 | 
			
		||||
		switch reject.Reason {
 | 
			
		||||
		case yggdrasil.PacketTooBig:
 | 
			
		||||
			if mtu, ok := reject.Detail.(int); ok {
 | 
			
		||||
				// Create the Packet Too Big response
 | 
			
		||||
				ptb := &icmp.PacketTooBig{
 | 
			
		||||
					MTU:  int(mtu),
 | 
			
		||||
					Data: reject.Packet,
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// 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)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			fallthrough
 | 
			
		||||
		default:
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		case data := <-tun.Recv:
 | 
			
		||||
			if tun.iface == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if tun.iface.IsTAP() {
 | 
			
		||||
				var dstAddr address.Address
 | 
			
		||||
				if data[0]&0xf0 == 0x60 {
 | 
			
		||||
					if len(data) < 40 {
 | 
			
		||||
						//panic("Tried to send a packet shorter than an IPv6 header...")
 | 
			
		||||
						util.PutBytes(data)
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					copy(dstAddr[:16], data[24:])
 | 
			
		||||
				} 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
 | 
			
		||||
					}
 | 
			
		||||
					copy(dstAddr[:4], data[16:])
 | 
			
		||||
				} else {
 | 
			
		||||
					return errors.New("Invalid address family")
 | 
			
		||||
				}
 | 
			
		||||
				sendndp := func(dstAddr address.Address) {
 | 
			
		||||
					neigh, known := tun.icmpv6.peermacs[dstAddr]
 | 
			
		||||
					known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
 | 
			
		||||
					if !known {
 | 
			
		||||
						request, err := tun.icmpv6.CreateNDPL2(dstAddr)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							panic(err)
 | 
			
		||||
						}
 | 
			
		||||
						if _, err := tun.iface.Write(request); err != nil {
 | 
			
		||||
							panic(err)
 | 
			
		||||
						}
 | 
			
		||||
						tun.icmpv6.peermacs[dstAddr] = neighbor{
 | 
			
		||||
							lastsolicitation: time.Now(),
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				var peermac macAddress
 | 
			
		||||
				var peerknown bool
 | 
			
		||||
				if data[0]&0xf0 == 0x40 {
 | 
			
		||||
					dstAddr = tun.addr
 | 
			
		||||
				} else if data[0]&0xf0 == 0x60 {
 | 
			
		||||
					if !bytes.Equal(tun.addr[:16], dstAddr[:16]) && !bytes.Equal(tun.subnet[:8], dstAddr[:8]) {
 | 
			
		||||
						dstAddr = tun.addr
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if neighbor, ok := tun.icmpv6.peermacs[dstAddr]; 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(dstAddr)
 | 
			
		||||
				} 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)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reads any packets that are waiting on the TUN/TAP adapter. If the adapter
 | 
			
		||||
// is running in TAP mode then the ethernet headers will automatically be
 | 
			
		||||
// processed and stripped if necessary. If an ICMPv6 packet is found, then
 | 
			
		||||
// the relevant helper functions in icmpv6.go are called.
 | 
			
		||||
func (tun *TunAdapter) read() error {
 | 
			
		||||
	mtu := tun.mtu
 | 
			
		||||
	if tun.iface.IsTAP() {
 | 
			
		||||
		mtu += tun_ETHER_HEADER_LENGTH
 | 
			
		||||
	}
 | 
			
		||||
	buf := make([]byte, mtu)
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := tun.iface.Read(buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			tun.mutex.RLock()
 | 
			
		||||
			open := tun.isOpen
 | 
			
		||||
			tun.mutex.RUnlock()
 | 
			
		||||
			if !open {
 | 
			
		||||
				return nil
 | 
			
		||||
			} else {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		o := 0
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			o = tun_ETHER_HEADER_LENGTH
 | 
			
		||||
		}
 | 
			
		||||
		switch {
 | 
			
		||||
		case buf[o]&0xf0 == 0x60 && n == 256*int(buf[o+4])+int(buf[o+5])+tun_IPv6_HEADER_LENGTH+o:
 | 
			
		||||
		case buf[o]&0xf0 == 0x40 && n == 256*int(buf[o+2])+int(buf[o+3])+o:
 | 
			
		||||
		default:
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if buf[o+6] == 58 {
 | 
			
		||||
			if tun.iface.IsTAP() {
 | 
			
		||||
				// Found an ICMPv6 packet
 | 
			
		||||
				b := make([]byte, n)
 | 
			
		||||
				copy(b, buf)
 | 
			
		||||
				go tun.icmpv6.ParsePacket(b)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		packet := append(util.GetBytes(), buf[o:n]...)
 | 
			
		||||
		tun.Send <- packet
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Closes the TUN/TAP adapter. This is only usually called when the Yggdrasil
 | 
			
		||||
// process stops. Typically this operation will happen quickly, but on macOS
 | 
			
		||||
// it can block until a read operation is completed.
 | 
			
		||||
func (tun *TunAdapter) Close() error {
 | 
			
		||||
	tun.mutex.Lock()
 | 
			
		||||
	tun.isOpen = false
 | 
			
		||||
	tun.mutex.Unlock()
 | 
			
		||||
	if tun.iface == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return tun.iface.Close()
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue