mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Fix TAP mode
This commit is contained in:
		
							parent
							
								
									912c181581
								
							
						
					
					
						commit
						e8272926a4
					
				
					 4 changed files with 88 additions and 53 deletions
				
			
		| 
						 | 
				
			
			@ -48,8 +48,11 @@ func (c *cryptokey) init(tun *TunAdapter) {
 | 
			
		|||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	c.tun.log.Debugln("Configuring CKR...")
 | 
			
		||||
	if err := c.configure(); err != nil {
 | 
			
		||||
		c.tun.log.Errorln("CKR configuration failed:", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		c.tun.log.Debugln("CKR configured")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import (
 | 
			
		|||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/icmp"
 | 
			
		||||
| 
						 | 
				
			
			@ -21,19 +22,18 @@ import (
 | 
			
		|||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type macAddress [6]byte
 | 
			
		||||
 | 
			
		||||
const len_ETHER = 14
 | 
			
		||||
 | 
			
		||||
type ICMPv6 struct {
 | 
			
		||||
	tun      *TunAdapter
 | 
			
		||||
	mylladdr net.IP
 | 
			
		||||
	mymac    macAddress
 | 
			
		||||
	peermacs map[address.Address]neighbor
 | 
			
		||||
	tun           *TunAdapter
 | 
			
		||||
	mylladdr      net.IP
 | 
			
		||||
	mymac         net.HardwareAddr
 | 
			
		||||
	peermacs      map[address.Address]neighbor
 | 
			
		||||
	peermacsmutex sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type neighbor struct {
 | 
			
		||||
	mac               macAddress
 | 
			
		||||
	mac               net.HardwareAddr
 | 
			
		||||
	learned           bool
 | 
			
		||||
	lastadvertisement time.Time
 | 
			
		||||
	lastsolicitation  time.Time
 | 
			
		||||
| 
						 | 
				
			
			@ -61,10 +61,12 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
 | 
			
		|||
// addresses.
 | 
			
		||||
func (i *ICMPv6) Init(t *TunAdapter) {
 | 
			
		||||
	i.tun = t
 | 
			
		||||
	i.peermacsmutex.Lock()
 | 
			
		||||
	i.peermacs = make(map[address.Address]neighbor)
 | 
			
		||||
	i.peermacsmutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Our MAC address and link-local address
 | 
			
		||||
	i.mymac = macAddress{
 | 
			
		||||
	i.mymac = net.HardwareAddr{
 | 
			
		||||
		0x02, 0x00, 0x00, 0x00, 0x00, 0x02}
 | 
			
		||||
	i.mylladdr = net.IP{
 | 
			
		||||
		0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
| 
						 | 
				
			
			@ -181,16 +183,30 @@ func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error)
 | 
			
		|||
		if datamac != nil {
 | 
			
		||||
			var addr address.Address
 | 
			
		||||
			var target address.Address
 | 
			
		||||
			var mac macAddress
 | 
			
		||||
			mac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 | 
			
		||||
			copy(addr[:], ipv6Header.Src[:])
 | 
			
		||||
			copy(target[:], datain[48:64])
 | 
			
		||||
			copy(mac[:], (*datamac)[:])
 | 
			
		||||
			// fmt.Printf("Learning peer MAC %x for %x\n", mac, target)
 | 
			
		||||
			i.peermacsmutex.Lock()
 | 
			
		||||
			neighbor := i.peermacs[target]
 | 
			
		||||
			neighbor.mac = mac
 | 
			
		||||
			neighbor.learned = true
 | 
			
		||||
			neighbor.lastadvertisement = time.Now()
 | 
			
		||||
			i.peermacs[target] = neighbor
 | 
			
		||||
			i.peermacsmutex.Unlock()
 | 
			
		||||
			i.tun.log.Debugln("Learned peer MAC", mac.String(), "for", net.IP(target[:]).String())
 | 
			
		||||
			/*
 | 
			
		||||
				i.tun.log.Debugln("Peer MAC table:")
 | 
			
		||||
				i.peermacsmutex.RLock()
 | 
			
		||||
				for t, n := range i.peermacs {
 | 
			
		||||
					if n.learned {
 | 
			
		||||
						i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "has MAC", n.mac.String())
 | 
			
		||||
					} else {
 | 
			
		||||
						i.tun.log.Debugln("- Target", net.IP(t[:]).String(), "is not learned yet")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				i.peermacsmutex.RUnlock()
 | 
			
		||||
			*/
 | 
			
		||||
		}
 | 
			
		||||
		return nil, errors.New("No response needed")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +217,7 @@ func (i *ICMPv6) UnmarshalPacket(datain []byte, datamac *[]byte) ([]byte, error)
 | 
			
		|||
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
 | 
			
		||||
// parameters, complete with ethernet and IP headers, which can be written
 | 
			
		||||
// directly to a TAP adapter.
 | 
			
		||||
func (i *ICMPv6) CreateICMPv6L2(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
 | 
			
		||||
func (i *ICMPv6) CreateICMPv6L2(dstmac net.HardwareAddr, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
 | 
			
		||||
	// Pass through to CreateICMPv6
 | 
			
		||||
	ipv6packet, err := CreateICMPv6(dst, src, mtype, mcode, mbody)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -264,13 +280,46 @@ func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody
 | 
			
		|||
	return responsePacket, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *ICMPv6) CreateNDPL2(dst address.Address) ([]byte, error) {
 | 
			
		||||
func (i *ICMPv6) Solicit(addr address.Address) {
 | 
			
		||||
	retries := 5
 | 
			
		||||
	for retries > 0 {
 | 
			
		||||
		retries--
 | 
			
		||||
		i.peermacsmutex.RLock()
 | 
			
		||||
		if n, ok := i.peermacs[addr]; ok && n.learned {
 | 
			
		||||
			i.tun.log.Debugln("MAC learned for", net.IP(addr[:]).String())
 | 
			
		||||
			i.peermacsmutex.RUnlock()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		i.peermacsmutex.RUnlock()
 | 
			
		||||
		i.tun.log.Debugln("Sending neighbor solicitation for", net.IP(addr[:]).String())
 | 
			
		||||
		i.peermacsmutex.Lock()
 | 
			
		||||
		if n, ok := i.peermacs[addr]; !ok {
 | 
			
		||||
			i.peermacs[addr] = neighbor{
 | 
			
		||||
				lastsolicitation: time.Now(),
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			n.lastsolicitation = time.Now()
 | 
			
		||||
		}
 | 
			
		||||
		i.peermacsmutex.Unlock()
 | 
			
		||||
		request, err := i.createNDPL2(addr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := i.tun.iface.Write(request); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		i.tun.log.Debugln("Sent neighbor solicitation for", net.IP(addr[:]).String())
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *ICMPv6) createNDPL2(dst address.Address) ([]byte, error) {
 | 
			
		||||
	// Create the ND payload
 | 
			
		||||
	var payload [28]byte
 | 
			
		||||
	copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00})
 | 
			
		||||
	copy(payload[4:20], dst[:])
 | 
			
		||||
	copy(payload[20:22], []byte{0x01, 0x01})
 | 
			
		||||
	copy(payload[22:28], i.mymac[:6])
 | 
			
		||||
	copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) // Flags
 | 
			
		||||
	copy(payload[4:20], dst[:])                       // Destination
 | 
			
		||||
	copy(payload[20:22], []byte{0x01, 0x01})          // Type & length
 | 
			
		||||
	copy(payload[22:28], i.mymac[:6])                 // Link layer address
 | 
			
		||||
 | 
			
		||||
	// Create the ICMPv6 solicited-node address
 | 
			
		||||
	var dstaddr address.Address
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +330,7 @@ func (i *ICMPv6) CreateNDPL2(dst address.Address) ([]byte, error) {
 | 
			
		|||
	copy(dstaddr[13:], dst[13:16])
 | 
			
		||||
 | 
			
		||||
	// Create the multicast MAC
 | 
			
		||||
	var dstmac macAddress
 | 
			
		||||
	dstmac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 | 
			
		||||
	copy(dstmac[:2], []byte{0x33, 0x33})
 | 
			
		||||
	copy(dstmac[2:6], dstaddr[12:16])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -293,9 +342,6 @@ func (i *ICMPv6) CreateNDPL2(dst address.Address) ([]byte, error) {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	neighbor := i.peermacs[dstaddr]
 | 
			
		||||
	neighbor.lastsolicitation = time.Now()
 | 
			
		||||
	i.peermacs[dstaddr] = neighbor
 | 
			
		||||
 | 
			
		||||
	return requestPacket, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -319,10 +365,10 @@ func (i *ICMPv6) HandleNDP(in []byte) ([]byte, error) {
 | 
			
		|||
 | 
			
		||||
	// Create our NDP message body response
 | 
			
		||||
	body := make([]byte, 28)
 | 
			
		||||
	binary.BigEndian.PutUint32(body[:4], uint32(0x20000000))
 | 
			
		||||
	copy(body[4:20], in[8:24]) // Target address
 | 
			
		||||
	body[20] = uint8(2)
 | 
			
		||||
	body[21] = uint8(1)
 | 
			
		||||
	binary.BigEndian.PutUint32(body[:4], uint32(0x40000000)) // Flags
 | 
			
		||||
	copy(body[4:20], in[8:24])                               // Target address
 | 
			
		||||
	body[20] = uint8(2)                                      // Type: Target link-layer address
 | 
			
		||||
	body[21] = uint8(1)                                      // Length: 1x address (8 bytes)
 | 
			
		||||
	copy(body[22:28], i.mymac[:6])
 | 
			
		||||
 | 
			
		||||
	// Send it back
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package tuntap
 | 
			
		|||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/songgao/packets/ethernet"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,19 +44,10 @@ func (tun *TunAdapter) writer() error {
 | 
			
		|||
				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(),
 | 
			
		||||
					}
 | 
			
		||||
					tun.icmpv6.Solicit(dstAddr)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			var peermac macAddress
 | 
			
		||||
			peermac := net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 | 
			
		||||
			var peerknown bool
 | 
			
		||||
			if b[0]&0xf0 == 0x40 {
 | 
			
		||||
				dstAddr = tun.addr
 | 
			
		||||
| 
						 | 
				
			
			@ -65,14 +57,19 @@ func (tun *TunAdapter) writer() error {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if neighbor, ok := tun.icmpv6.peermacs[dstAddr]; ok && neighbor.learned {
 | 
			
		||||
				// If we've learned the MAC of a 300::/7 address, for example, or a CKR
 | 
			
		||||
				// address, use the MAC address of that
 | 
			
		||||
				peermac = neighbor.mac
 | 
			
		||||
				peerknown = true
 | 
			
		||||
			} else if neighbor, ok := tun.icmpv6.peermacs[tun.addr]; ok && neighbor.learned {
 | 
			
		||||
				// Otherwise send directly to the MAC address of the host if that's
 | 
			
		||||
				// known instead
 | 
			
		||||
				peermac = neighbor.mac
 | 
			
		||||
				peerknown = true
 | 
			
		||||
				sendndp(dstAddr)
 | 
			
		||||
			} else {
 | 
			
		||||
				// Nothing has been discovered, try to discover the destination
 | 
			
		||||
				sendndp(tun.addr)
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			if peerknown {
 | 
			
		||||
				var proto ethernet.Ethertype
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +89,8 @@ func (tun *TunAdapter) writer() error {
 | 
			
		|||
				copy(frame[tun_ETHER_HEADER_LENGTH:], b[:n])
 | 
			
		||||
				n += tun_ETHER_HEADER_LENGTH
 | 
			
		||||
				w, err = tun.iface.Write(frame[:n])
 | 
			
		||||
			} else {
 | 
			
		||||
				tun.log.Errorln("TUN/TAP iface write error: no peer MAC known for", net.IP(dstAddr[:]).String(), "- dropping packet")
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			w, err = tun.iface.Write(b[:n])
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +183,7 @@ func (tun *TunAdapter) reader() error {
 | 
			
		|||
			// Unknown address length or protocol, so drop the packet and ignore it
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !tun.ckr.isValidSource(srcAddr, addrlen) {
 | 
			
		||||
		if tun.ckr.isEnabled() && !tun.ckr.isValidSource(srcAddr, addrlen) {
 | 
			
		||||
			// The packet had a source address that doesn't belong to us or our
 | 
			
		||||
			// configured crypto-key routing source subnets
 | 
			
		||||
			continue
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gologme/log"
 | 
			
		||||
	"github.com/yggdrasil-network/water"
 | 
			
		||||
| 
						 | 
				
			
			@ -152,21 +151,6 @@ func (tun *TunAdapter) Start() error {
 | 
			
		|||
	tun.send = make(chan []byte, 32) // TODO: is this a sensible value?
 | 
			
		||||
	tun.reconfigure = make(chan chan error)
 | 
			
		||||
	tun.mutex.Unlock()
 | 
			
		||||
	if iftapmode {
 | 
			
		||||
		go func() {
 | 
			
		||||
			for {
 | 
			
		||||
				if _, ok := tun.icmpv6.peermacs[tun.addr]; ok {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				request, err := tun.icmpv6.CreateNDPL2(tun.addr)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					panic(err)
 | 
			
		||||
				}
 | 
			
		||||
				tun.send <- request
 | 
			
		||||
				time.Sleep(time.Second)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			e := <-tun.reconfigure
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +161,9 @@ func (tun *TunAdapter) Start() error {
 | 
			
		|||
	go tun.reader()
 | 
			
		||||
	go tun.writer()
 | 
			
		||||
	tun.icmpv6.Init(tun)
 | 
			
		||||
	if iftapmode {
 | 
			
		||||
		go tun.icmpv6.Solicit(tun.addr)
 | 
			
		||||
	}
 | 
			
		||||
	tun.ckr.init(tun)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue