5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-10 06:20:26 +00:00

Track further neighbor state, don't send more NDPs than needed

This commit is contained in:
Neil Alexander 2018-11-10 17:32:03 +00:00
parent d50e1bc803
commit adc32fe92f
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
2 changed files with 66 additions and 32 deletions

View File

@ -13,6 +13,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"net" "net"
"time"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
@ -26,7 +27,14 @@ type icmpv6 struct {
tun *tunDevice tun *tunDevice
mylladdr net.IP mylladdr net.IP
mymac macAddress mymac macAddress
peermacs map[address]macAddress peermacs map[address]neighbor
}
type neighbor struct {
mac macAddress
learned bool
lastadvertisement time.Time
lastsolicitation time.Time
} }
// Marshal returns the binary encoding of h. // Marshal returns the binary encoding of h.
@ -51,7 +59,7 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
// addresses. // addresses.
func (i *icmpv6) init(t *tunDevice) { func (i *icmpv6) init(t *tunDevice) {
i.tun = t i.tun = t
i.peermacs = make(map[address]macAddress) i.peermacs = make(map[address]neighbor)
// Our MAC address and link-local address // Our MAC address and link-local address
i.mymac = macAddress{ i.mymac = macAddress{
@ -168,7 +176,11 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
var mac macAddress var mac macAddress
copy(addr[:], ipv6Header.Src[:]) copy(addr[:], ipv6Header.Src[:])
copy(mac[:], (*datamac)[:]) copy(mac[:], (*datamac)[:])
i.peermacs[addr] = mac neighbor := i.peermacs[addr]
neighbor.mac = mac
neighbor.learned = true
neighbor.lastadvertisement = time.Now()
i.peermacs[addr] = neighbor
} }
return nil, errors.New("No response needed") return nil, errors.New("No response needed")
} }
@ -242,27 +254,11 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType,
return responsePacket, nil return responsePacket, nil
} }
func (i *icmpv6) create_ndp_tap(in []byte) ([]byte, error) { func (i *icmpv6) create_ndp_tap(dst address) ([]byte, error) {
// Parse the IPv6 packet headers
ipv6Header, err := ipv6.ParseHeader(in[:ipv6.HeaderLen])
if err != nil {
return nil, err
}
// Check if the packet is IPv6
if ipv6Header.Version != ipv6.Version {
return nil, err
}
// Check if the packet is ICMPv6
if ipv6Header.NextHeader != 58 {
return nil, err
}
// Create the ND payload // Create the ND payload
var payload [28]byte var payload [28]byte
copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00}) copy(payload[:4], []byte{0x00, 0x00, 0x00, 0x00})
copy(payload[4:20], ipv6Header.Dst[:]) copy(payload[4:20], dst[:])
copy(payload[20:22], []byte{0x01, 0x01}) copy(payload[20:22], []byte{0x01, 0x01})
copy(payload[22:28], i.mymac[:6]) copy(payload[22:28], i.mymac[:6])
@ -272,7 +268,7 @@ func (i *icmpv6) create_ndp_tap(in []byte) ([]byte, error) {
0xFF, 0x02, 0x00, 0x00, 0xFF, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xFF}) 0x00, 0x00, 0x00, 0x01, 0xFF})
copy(dstaddr[13:], ipv6Header.Dst[13:16]) copy(dstaddr[13:], dst[13:16])
// Create the multicast MAC // Create the multicast MAC
var dstmac macAddress var dstmac macAddress
@ -287,6 +283,9 @@ func (i *icmpv6) create_ndp_tap(in []byte) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
neighbor := i.peermacs[dstaddr]
neighbor.lastsolicitation = time.Now()
i.peermacs[dstaddr] = neighbor
return requestPacket, nil return requestPacket, nil
} }

View File

@ -4,6 +4,7 @@ package yggdrasil
import ( import (
"errors" "errors"
"time"
"yggdrasil/defaults" "yggdrasil/defaults"
"github.com/songgao/packets/ethernet" "github.com/songgao/packets/ethernet"
@ -49,6 +50,21 @@ func (tun *tunDevice) start(ifname string, iftapmode bool, addr string, mtu int)
} }
go func() { panic(tun.read()) }() go func() { panic(tun.read()) }()
go func() { panic(tun.write()) }() go func() { panic(tun.write()) }()
go func() {
for {
if _, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok {
break
}
request, err := tun.icmpv6.create_ndp_tap(tun.core.router.addr)
if err != nil {
panic(err)
}
if _, err := tun.iface.Write(request); err != nil {
panic(err)
}
time.Sleep(time.Second)
}
}()
return nil return nil
} }
@ -76,7 +92,35 @@ func (tun *tunDevice) write() error {
} else { } else {
return errors.New("Invalid address family") return errors.New("Invalid address family")
} }
if peermac, ok := tun.icmpv6.peermacs[destAddr]; ok { sendndp := func(destAddr address) {
neigh, known := tun.icmpv6.peermacs[destAddr]
known = known && (time.Since(neigh.lastsolicitation).Seconds() < 30)
if !known {
request, err := tun.icmpv6.create_ndp_tap(destAddr)
if err != nil {
panic(err)
}
if _, err := tun.iface.Write(request); err != nil {
panic(err)
}
tun.icmpv6.peermacs[destAddr] = neighbor{
lastsolicitation: time.Now(),
}
}
}
var peermac macAddress
var peerknown bool
if neighbor, ok := tun.icmpv6.peermacs[destAddr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
} else if neighbor, ok := tun.icmpv6.peermacs[tun.core.router.addr]; ok && neighbor.learned {
peermac = neighbor.mac
peerknown = true
sendndp(destAddr)
} else {
sendndp(tun.core.router.addr)
}
if peerknown {
var frame ethernet.Frame var frame ethernet.Frame
frame.Prepare( frame.Prepare(
peermac[:6], // Destination MAC address peermac[:6], // Destination MAC address
@ -88,16 +132,7 @@ func (tun *tunDevice) write() error {
if _, err := tun.iface.Write(frame); err != nil { if _, err := tun.iface.Write(frame); err != nil {
panic(err) panic(err)
} }
} else {
request, err := tun.icmpv6.create_ndp_tap(data)
if err != nil {
panic(err)
} }
if _, err := tun.iface.Write(request); err != nil {
panic(err)
}
}
} else { } else {
if _, err := tun.iface.Write(data); err != nil { if _, err := tun.iface.Write(data); err != nil {
panic(err) panic(err)