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: Set MTU of session properly
 | 
				
			||||||
// TODO: Reject packets that exceed session MTU with ICMPv6 for PMTU Discovery
 | 
					// 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: 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 (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
					 | 
				
			||||||
	"encoding/hex"
 | 
						"encoding/hex"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
| 
						 | 
					@ -18,14 +17,12 @@ import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gologme/log"
 | 
						"github.com/gologme/log"
 | 
				
			||||||
	"github.com/songgao/packets/ethernet"
 | 
					 | 
				
			||||||
	"github.com/yggdrasil-network/water"
 | 
						"github.com/yggdrasil-network/water"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/config"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/config"
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/util"
 | 
					 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,9 +44,10 @@ type TunAdapter struct {
 | 
				
			||||||
	icmpv6       ICMPv6
 | 
						icmpv6       ICMPv6
 | 
				
			||||||
	mtu          int
 | 
						mtu          int
 | 
				
			||||||
	iface        *water.Interface
 | 
						iface        *water.Interface
 | 
				
			||||||
	mutex        sync.RWMutex                        // Protects the below
 | 
						send         chan []byte
 | 
				
			||||||
	addrToConn   map[address.Address]*yggdrasil.Conn // Managed by connReader
 | 
						mutex        sync.RWMutex // Protects the below
 | 
				
			||||||
	subnetToConn map[address.Subnet]*yggdrasil.Conn  // Managed by connReader
 | 
						addrToConn   map[address.Address]*tunConn
 | 
				
			||||||
 | 
						subnetToConn map[address.Subnet]*tunConn
 | 
				
			||||||
	isOpen       bool
 | 
						isOpen       bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,8 +110,8 @@ func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, listener
 | 
				
			||||||
	tun.log = log
 | 
						tun.log = log
 | 
				
			||||||
	tun.listener = listener
 | 
						tun.listener = listener
 | 
				
			||||||
	tun.dialer = dialer
 | 
						tun.dialer = dialer
 | 
				
			||||||
	tun.addrToConn = make(map[address.Address]*yggdrasil.Conn)
 | 
						tun.addrToConn = make(map[address.Address]*tunConn)
 | 
				
			||||||
	tun.subnetToConn = make(map[address.Subnet]*yggdrasil.Conn)
 | 
						tun.subnetToConn = make(map[address.Subnet]*tunConn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Start the setup process for the TUN/TAP adapter. If successful, starts the
 | 
					// 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.mutex.Lock()
 | 
				
			||||||
	tun.isOpen = true
 | 
						tun.isOpen = true
 | 
				
			||||||
 | 
						tun.send = make(chan []byte, 32) // TODO: is this a sensible value?
 | 
				
			||||||
	tun.mutex.Unlock()
 | 
						tun.mutex.Unlock()
 | 
				
			||||||
	if iftapmode {
 | 
						if iftapmode {
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
| 
						 | 
					@ -159,9 +158,7 @@ func (tun *TunAdapter) Start() error {
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					panic(err)
 | 
										panic(err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if _, err := tun.iface.Write(request); err != nil {
 | 
									tun.send <- request
 | 
				
			||||||
					panic(err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				time.Sleep(time.Second)
 | 
									time.Sleep(time.Second)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
| 
						 | 
					@ -173,7 +170,8 @@ func (tun *TunAdapter) Start() error {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	go tun.handler()
 | 
						go tun.handler()
 | 
				
			||||||
	go tun.ifaceReader()
 | 
						go tun.reader()
 | 
				
			||||||
 | 
						go tun.writer()
 | 
				
			||||||
	tun.icmpv6.Init(tun)
 | 
						tun.icmpv6.Init(tun)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -186,473 +184,47 @@ func (tun *TunAdapter) handler() error {
 | 
				
			||||||
			tun.log.Errorln("TUN/TAP connection accept error:", err)
 | 
								tun.log.Errorln("TUN/TAP connection accept error:", err)
 | 
				
			||||||
			return 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()
 | 
						remoteNodeID := conn.RemoteAddr()
 | 
				
			||||||
	remoteAddr := address.AddrForNodeID(&remoteNodeID)
 | 
						remoteAddr := address.AddrForNodeID(&remoteNodeID)
 | 
				
			||||||
	remoteSubnet := address.SubnetForNodeID(&remoteNodeID)
 | 
						remoteSubnet := address.SubnetForNodeID(&remoteNodeID)
 | 
				
			||||||
	err := func() error {
 | 
						// Work out if this is already a destination we already know about
 | 
				
			||||||
		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
 | 
					 | 
				
			||||||
	tun.mutex.Lock()
 | 
						tun.mutex.Lock()
 | 
				
			||||||
	tun.addrToConn[*remoteAddr] = conn
 | 
						defer tun.mutex.Unlock()
 | 
				
			||||||
	tun.subnetToConn[*remoteSubnet] = conn
 | 
						atc, aok := tun.addrToConn[*remoteAddr]
 | 
				
			||||||
	tun.mutex.Unlock()
 | 
						stc, sok := tun.subnetToConn[*remoteSubnet]
 | 
				
			||||||
	// Make sure to clean those up later when the connection is closed
 | 
						// If we know about a connection for this destination already then assume it
 | 
				
			||||||
	defer func() {
 | 
						// is no longer valid and close it
 | 
				
			||||||
		tun.mutex.Lock()
 | 
						if aok {
 | 
				
			||||||
		delete(tun.addrToConn, *remoteAddr)
 | 
							atc.close()
 | 
				
			||||||
		delete(tun.subnetToConn, *remoteSubnet)
 | 
							err = errors.New("replaced connection for address")
 | 
				
			||||||
		tun.mutex.Unlock()
 | 
						} else if sok {
 | 
				
			||||||
	}()
 | 
							stc.close()
 | 
				
			||||||
	b := make([]byte, 65535)
 | 
							err = errors.New("replaced connection for subnet")
 | 
				
			||||||
	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
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// 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