Compare commits

...

4 commits

4 changed files with 130 additions and 71 deletions

51
main.go
View file

@ -65,13 +65,13 @@ const routingTableTemplate = `
<td>{{$route.LastSeenAgo}}</td> <td>{{$route.LastSeenAgo}}</td>
<td> <td>
{{- with $route.AURPPeer -}} {{- with $route.AURPPeer -}}
{{.RemoteAddr}} [redacted]
{{- end -}} {{- end -}}
{{- with $route.EtherTalkPeer -}} {{- with $route.EtherTalkPeer -}}
{{.Port.Device}} {{.PeerAddr.Network}}.{{.PeerAddr.Node}} {{.Port.Device}} {{.PeerAddr.Network}}.{{.PeerAddr.Node}}
{{- end -}} {{- end -}}
{{- with $route.EtherTalkDirect -}} {{- with $route.EtherTalkDirect -}}
{{.Device}} {{.NetStart}}-{{.NetEnd}} {{.Device}}
{{- end -}} {{- end -}}
</td> </td>
</tr> </tr>
@ -91,8 +91,8 @@ const peerTableTemplate = `
<tbody> <tbody>
{{range $peer := . }} {{range $peer := . }}
<tr> <tr>
<td>{{$peer.ConfiguredAddr}}</td> <td>[redacted]</td>
<td>{{$peer.RemoteAddr}}</td> <td>[redacted]</td>
<td>{{$peer.ReceiverState}}</td> <td>{{$peer.ReceiverState}}</td>
<td>{{$peer.SenderState}}</td> <td>{{$peer.SenderState}}</td>
</tr> </tr>
@ -142,9 +142,9 @@ func main() {
} }
localDI := aurp.IPDomainIdentifier(localIP) localDI := aurp.IPDomainIdentifier(localIP)
log.Printf("Using %v as local domain identifier", localIP) // log.Printf("Using %v as local domain identifier", localIP)
log.Printf("EtherTalk configuration: %+v", cfg.EtherTalk) // log.Printf("EtherTalk configuration: %+v", cfg.EtherTalk)
ln, err := net.ListenUDP("udp4", &net.UDPAddr{Port: int(cfg.ListenPort)}) ln, err := net.ListenUDP("udp4", &net.UDPAddr{Port: int(cfg.ListenPort)})
if err != nil { if err != nil {
@ -246,12 +246,12 @@ func main() {
// ------------------------- Configured peer setup ------------------------ // ------------------------- Configured peer setup ------------------------
if cfg.PeerListURL != "" { if cfg.PeerListURL != "" {
log.Printf("Fetching peer list from %s...", cfg.PeerListURL) log.Print("Fetching peer list...")
existing := len(cfg.Peers) existing := len(cfg.Peers)
func() { func() {
resp, err := http.Get(cfg.PeerListURL) resp, err := http.Get(cfg.PeerListURL)
if err != nil { if err != nil {
log.Fatalf("Couldn't fetch peer list: %v", err) log.Fatalf("Couldn't fetch peer list!")
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -277,28 +277,17 @@ func main() {
raddr, err := net.ResolveUDPAddr("udp4", peerStr) raddr, err := net.ResolveUDPAddr("udp4", peerStr)
if err != nil { if err != nil {
log.Printf("couldn't resolve UDP address, skipping: %v", err) log.Print("couldn't resolve UDP address, skipping peer")
continue continue
} }
log.Printf("resolved %q to %v", peerStr, raddr) //log.Printf("resolved %q to %v", peerStr, raddr)
if raddr.IP.Equal(localIP) { if raddr.IP.Equal(localIP) {
log.Printf("%v == %v == me, skipping", peerStr, raddr) //log.Print("peer == me, skipping")
continue continue
} }
peer := &router.AURPPeer{ peer := router.NewAURPPeer(routes, ln, peerStr, raddr, localDI, nil, nextConnID)
Transport: &aurp.Transport{
LocalDI: localDI,
RemoteDI: aurp.IPDomainIdentifier(raddr.IP),
LocalConnID: nextConnID,
},
UDPConn: ln,
ConfiguredAddr: peerStr,
RemoteAddr: raddr,
ReceiveCh: make(chan aurp.Packet, 1024),
RouteTable: routes,
}
aurp.Inc(&nextConnID) aurp.Inc(&nextConnID)
peersMu.Lock() peersMu.Lock()
peers[udpAddrFromNet(raddr)] = peer peers[udpAddrFromNet(raddr)] = peer
@ -381,7 +370,7 @@ func main() {
return return
} }
log.Printf("AURP: Got %T from %v (%v)", pkt, raddr, dh.SourceDI) // log.Printf("AURP: Got %T from %v (%v)", pkt, raddr, dh.SourceDI)
// Existing peer? // Existing peer?
ra := udpAddrFromNet(raddr) ra := udpAddrFromNet(raddr)
@ -389,22 +378,12 @@ func main() {
pr := peers[ra] pr := peers[ra]
if pr == nil { if pr == nil {
if !cfg.OpenPeering { if !cfg.OpenPeering {
log.Printf("AURP: Got packet from %v but it's not in my config and open peering is disabled; dropping the packet", raddr) log.Print("AURP: Got packet but it's not in my config and open peering is disabled; dropping the packet")
peersMu.Unlock() peersMu.Unlock()
continue continue
} }
// New peer! // New peer!
pr = &router.AURPPeer{ pr = router.NewAURPPeer(routes, ln, "", raddr, localDI, dh.SourceDI, nextConnID)
Transport: &aurp.Transport{
LocalDI: localDI,
RemoteDI: dh.SourceDI, // platinum rule
LocalConnID: nextConnID,
},
UDPConn: ln,
RemoteAddr: raddr,
ReceiveCh: make(chan aurp.Packet, 1024),
RouteTable: routes,
}
aurp.Inc(&nextConnID) aurp.Inc(&nextConnID)
peers[ra] = pr peers[ra] = pr
goPeerHandler(pr) goPeerHandler(pr)

View file

@ -114,11 +114,68 @@ type AURPPeer struct {
// Route table (the peer will add/remove/update routes and zones) // Route table (the peer will add/remove/update routes and zones)
RouteTable *RouteTable RouteTable *RouteTable
// Event tuples yet to be sent to this peer in an RI-Upd.
pendingEvents chan aurp.EventTuple
mu sync.RWMutex mu sync.RWMutex
rstate ReceiverState rstate ReceiverState
sstate SenderState sstate SenderState
} }
func NewAURPPeer(routes *RouteTable, udpConn *net.UDPConn, peerAddr string, raddr *net.UDPAddr, localDI, remoteDI aurp.DomainIdentifier, connID uint16) *AURPPeer {
if remoteDI == nil {
remoteDI = aurp.IPDomainIdentifier(raddr.IP)
}
return &AURPPeer{
Transport: &aurp.Transport{
LocalDI: localDI,
RemoteDI: remoteDI,
LocalConnID: connID,
},
UDPConn: udpConn,
ConfiguredAddr: peerAddr,
RemoteAddr: raddr,
ReceiveCh: make(chan aurp.Packet, 1024),
RouteTable: routes,
pendingEvents: make(chan aurp.EventTuple, 1024),
}
}
func (p *AURPPeer) addPendingEvent(ec aurp.EventCode, route *Route) {
// Don't advertise routes to AURP peers to other AURP peers
if route.AURPPeer != nil {
return
}
et := aurp.EventTuple{
EventCode: ec,
Extended: route.Extended,
RangeStart: route.NetStart,
Distance: route.Distance,
RangeEnd: route.NetEnd,
}
switch ec {
case aurp.EventCodeND, aurp.EventCodeNRC:
et.Distance = 0 // "The distance field does not apply to ND or NRC event tuples and should be set to 0."
}
p.pendingEvents <- et
}
func (p *AURPPeer) RouteAdded(route *Route) {
p.addPendingEvent(aurp.EventCodeNA, route)
}
func (p *AURPPeer) RouteDeleted(route *Route) {
p.addPendingEvent(aurp.EventCodeND, route)
}
func (p *AURPPeer) RouteDistanceChanged(route *Route) {
p.addPendingEvent(aurp.EventCodeNDC, route)
}
func (p *AURPPeer) RouteForwarderChanged(route *Route) {
p.addPendingEvent(aurp.EventCodeNRC, route)
}
func (p *AURPPeer) Forward(ddpkt *ddp.ExtPacket) error { func (p *AURPPeer) Forward(ddpkt *ddp.ExtPacket) error {
outPkt, err := ddp.ExtMarshal(*ddpkt) outPkt, err := ddp.ExtMarshal(*ddpkt)
if err != nil { if err != nil {
@ -165,7 +222,7 @@ func (p *AURPPeer) Send(pkt aurp.Packet) (int, error) {
if _, err := pkt.WriteTo(&b); err != nil { if _, err := pkt.WriteTo(&b); err != nil {
return 0, err return 0, err
} }
log.Printf("AURP Peer: Sending %T (len %d) to %v", pkt, b.Len(), p.RemoteAddr) // log.Printf("AURP Peer: Sending %T (len %d) to %v", pkt, b.Len(), p.RemoteAddr)
return p.UDPConn.WriteToUDP(b.Bytes(), p.RemoteAddr) return p.UDPConn.WriteToUDP(b.Bytes(), p.RemoteAddr)
} }
@ -284,7 +341,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
// send a null RI-Upd to check if the sender is also unconnected // send a null RI-Upd to check if the sender is also unconnected
if p.sstate == SenderConnected && time.Since(lastSend) > sendRetryTimer { if p.sstate == SenderConnected && time.Since(lastSend) > sendRetryTimer {
if sendRetries >= sendRetryLimit { if sendRetries >= sendRetryLimit {
log.Printf("AURP Peer: Send retry limit reached while probing sender connect, closing connection") log.Print("AURP Peer: Send retry limit reached while probing sender connect, closing connection")
} }
sendRetries++ sendRetries++
lastSend = time.Now() lastSend = time.Now()
@ -309,10 +366,10 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
// In case it's a DNS name, re-resolve it before reconnecting // In case it's a DNS name, re-resolve it before reconnecting
raddr, err := net.ResolveUDPAddr("udp4", p.ConfiguredAddr) raddr, err := net.ResolveUDPAddr("udp4", p.ConfiguredAddr)
if err != nil { if err != nil {
log.Printf("couldn't resolve UDP address, skipping: %v", err) log.Print("couldn't resolve UDP address, skipping")
break break
} }
log.Printf("AURP Peer: resolved %q to %v", p.ConfiguredAddr, raddr) // log.Printf("AURP Peer: resolved %q to %v", p.ConfiguredAddr, raddr)
p.RemoteAddr = raddr p.RemoteAddr = raddr
lastReconnect = time.Now() lastReconnect = time.Now()

View file

@ -58,17 +58,40 @@ func (r *Route) Valid() bool {
return len(r.ZoneNames) > 0 && (r.EtherTalkPeer == nil || time.Since(r.LastSeen) <= maxRouteAge) return len(r.ZoneNames) > 0 && (r.EtherTalkPeer == nil || time.Since(r.LastSeen) <= maxRouteAge)
} }
type RouteTableObserver interface {
RouteAdded(*Route)
RouteDeleted(*Route)
RouteDistanceChanged(*Route)
RouteForwarderChanged(*Route)
}
type RouteTable struct { type RouteTable struct {
mu sync.Mutex routesMu sync.RWMutex
routes map[*Route]struct{} routes map[*Route]struct{}
observersMu sync.RWMutex
observers map[RouteTableObserver]struct{}
} }
func NewRouteTable() *RouteTable { func NewRouteTable() *RouteTable {
return &RouteTable{ return &RouteTable{
routes: make(map[*Route]struct{}), routes: make(map[*Route]struct{}),
observers: make(map[RouteTableObserver]struct{}),
} }
} }
func (rt *RouteTable) AddObserver(obs RouteTableObserver) {
rt.observersMu.Lock()
defer rt.observersMu.Unlock()
rt.observers[obs] = struct{}{}
}
func (rt *RouteTable) RemoveObserver(obs RouteTableObserver) {
rt.observersMu.Lock()
defer rt.observersMu.Unlock()
delete(rt.observers, obs)
}
func (rt *RouteTable) InsertEtherTalkDirect(port *EtherTalkPort) { func (rt *RouteTable) InsertEtherTalkDirect(port *EtherTalkPort) {
r := &Route{ r := &Route{
Extended: true, Extended: true,
@ -80,14 +103,14 @@ func (rt *RouteTable) InsertEtherTalkDirect(port *EtherTalkPort) {
EtherTalkDirect: port, EtherTalkDirect: port,
} }
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
rt.routes[r] = struct{}{} rt.routes[r] = struct{}{}
} }
func (rt *RouteTable) Dump() []Route { func (rt *RouteTable) Dump() []Route {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
table := make([]Route, 0, len(rt.routes)) table := make([]Route, 0, len(rt.routes))
for r := range rt.routes { for r := range rt.routes {
@ -97,8 +120,8 @@ func (rt *RouteTable) Dump() []Route {
} }
func (rt *RouteTable) LookupRoute(network ddp.Network) *Route { func (rt *RouteTable) LookupRoute(network ddp.Network) *Route {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
var bestRoute *Route var bestRoute *Route
for r := range rt.routes { for r := range rt.routes {
@ -120,8 +143,8 @@ func (rt *RouteTable) LookupRoute(network ddp.Network) *Route {
} }
func (rt *RouteTable) DeleteAURPPeer(peer *AURPPeer) { func (rt *RouteTable) DeleteAURPPeer(peer *AURPPeer) {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
for route := range rt.routes { for route := range rt.routes {
if route.AURPPeer == peer { if route.AURPPeer == peer {
@ -131,8 +154,8 @@ func (rt *RouteTable) DeleteAURPPeer(peer *AURPPeer) {
} }
func (rt *RouteTable) DeleteAURPPeerNetwork(peer *AURPPeer, network ddp.Network) { func (rt *RouteTable) DeleteAURPPeerNetwork(peer *AURPPeer, network ddp.Network) {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
for route := range rt.routes { for route := range rt.routes {
if route.AURPPeer == peer && route.NetStart == network { if route.AURPPeer == peer && route.NetStart == network {
@ -142,8 +165,8 @@ func (rt *RouteTable) DeleteAURPPeerNetwork(peer *AURPPeer, network ddp.Network)
} }
func (rt *RouteTable) UpdateAURPRouteDistance(peer *AURPPeer, network ddp.Network, distance uint8) { func (rt *RouteTable) UpdateAURPRouteDistance(peer *AURPPeer, network ddp.Network, distance uint8) {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
for route := range rt.routes { for route := range rt.routes {
if route.AURPPeer == peer && route.NetStart == network { if route.AURPPeer == peer && route.NetStart == network {
@ -161,8 +184,8 @@ func (rt *RouteTable) UpsertEtherTalkRoute(peer *EtherTalkPeer, extended bool, n
return nil, fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd) return nil, fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd)
} }
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
// Update? // Update?
for r := range rt.routes { for r := range rt.routes {
@ -213,16 +236,16 @@ func (rt *RouteTable) InsertAURPRoute(peer *AURPPeer, extended bool, netStart, n
AURPPeer: peer, AURPPeer: peer,
} }
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
rt.routes[r] = struct{}{} rt.routes[r] = struct{}{}
return nil return nil
} }
// ValidRoutes returns all valid routes. // ValidRoutes returns all valid routes.
func (rt *RouteTable) ValidRoutes() []*Route { func (rt *RouteTable) ValidRoutes() []*Route {
rt.mu.Lock() rt.routesMu.RLock()
defer rt.mu.Unlock() defer rt.routesMu.RUnlock()
valid := make([]*Route, 0, len(rt.routes)) valid := make([]*Route, 0, len(rt.routes))
for r := range rt.routes { for r := range rt.routes {
if r.Valid() { if r.Valid() {
@ -234,8 +257,8 @@ func (rt *RouteTable) ValidRoutes() []*Route {
// ValidNonAURPRoutes returns all valid routes that were not learned via AURP. // ValidNonAURPRoutes returns all valid routes that were not learned via AURP.
func (rt *RouteTable) ValidNonAURPRoutes() []*Route { func (rt *RouteTable) ValidNonAURPRoutes() []*Route {
rt.mu.Lock() rt.routesMu.RLock()
defer rt.mu.Unlock() defer rt.routesMu.RUnlock()
valid := make([]*Route, 0, len(rt.routes)) valid := make([]*Route, 0, len(rt.routes))
for r := range rt.routes { for r := range rt.routes {
if r.AURPPeer != nil { if r.AURPPeer != nil {

View file

@ -23,8 +23,8 @@ import (
) )
func (rt *RouteTable) AddZonesToNetwork(n ddp.Network, zs ...string) { func (rt *RouteTable) AddZonesToNetwork(n ddp.Network, zs ...string) {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
for r := range rt.routes { for r := range rt.routes {
if n < r.NetStart || n > r.NetEnd { if n < r.NetStart || n > r.NetEnd {
continue continue
@ -39,8 +39,8 @@ func (rt *RouteTable) AddZonesToNetwork(n ddp.Network, zs ...string) {
func (rt *RouteTable) ZonesForNetworks(ns []ddp.Network) map[ddp.Network][]string { func (rt *RouteTable) ZonesForNetworks(ns []ddp.Network) map[ddp.Network][]string {
zs := make(map[ddp.Network][]string) zs := make(map[ddp.Network][]string)
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
for r := range rt.routes { for r := range rt.routes {
if !r.Valid() { if !r.Valid() {
continue continue
@ -55,8 +55,8 @@ func (rt *RouteTable) ZonesForNetworks(ns []ddp.Network) map[ddp.Network][]strin
} }
func (rt *RouteTable) RoutesForZone(zone string) []*Route { func (rt *RouteTable) RoutesForZone(zone string) []*Route {
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
var routes []*Route var routes []*Route
for r := range rt.routes { for r := range rt.routes {
@ -73,8 +73,8 @@ func (rt *RouteTable) RoutesForZone(zone string) []*Route {
func (rt *RouteTable) AllZoneNames() (zones []string) { func (rt *RouteTable) AllZoneNames() (zones []string) {
defer slices.Sort(zones) defer slices.Sort(zones)
rt.mu.Lock() rt.routesMu.Lock()
defer rt.mu.Unlock() defer rt.routesMu.Unlock()
zs := make(StringSet) zs := make(StringSet)
for r := range rt.routes { for r := range rt.routes {