headscale/routes.go

106 lines
2.2 KiB
Go
Raw Normal View History

2021-04-28 14:55:29 +00:00
package headscale
import (
2022-05-30 13:31:06 +00:00
"fmt"
2022-09-01 22:06:19 +00:00
"net/netip"
2022-11-23 18:50:30 +00:00
"gorm.io/gorm"
2021-04-28 14:55:29 +00:00
)
2021-11-15 19:18:14 +00:00
const (
2022-07-29 15:35:21 +00:00
ErrRouteIsNotAvailable = Error("route is not available")
2021-11-15 19:18:14 +00:00
)
2022-11-23 18:50:30 +00:00
type Route struct {
gorm.Model
MachineID uint64
Machine Machine
Prefix IPPrefix
Advertised bool
Enabled bool
IsPrimary bool
}
type Routes []Route
2021-04-28 14:55:29 +00:00
func (r *Route) String() string {
return fmt.Sprintf("%s:%s", r.Machine, netip.Prefix(r.Prefix).String())
2021-04-28 14:55:29 +00:00
}
func (rs Routes) toPrefixes() []netip.Prefix {
prefixes := make([]netip.Prefix, len(rs))
for i, r := range rs {
prefixes[i] = netip.Prefix(r.Prefix)
2021-04-28 14:55:29 +00:00
}
return prefixes
}
// getMachinePrimaryRoutes returns the routes that are enabled and marked as primary (for subnet failover)
// Exit nodes are not considered for this, as they are never marked as Primary
func (h *Headscale) getMachinePrimaryRoutes(m *Machine) ([]Route, error) {
var routes []Route
err := h.db.
Preload("Machine").
Where("machine_id = ? AND advertised = ? AND enabled = ? AND is_primary = ?", m.ID, true, true, true).
Find(&routes).Error
if err != nil {
return nil, err
}
2021-11-14 15:46:09 +00:00
return routes, nil
}
func (h *Headscale) processMachineRoutes(machine *Machine) error {
currentRoutes := []Route{}
err := h.db.Where("machine_id = ?", machine.ID).Find(&currentRoutes).Error
if err != nil {
return err
}
2021-04-28 14:55:29 +00:00
advertisedRoutes := map[netip.Prefix]bool{}
for _, prefix := range machine.HostInfo.RoutableIPs {
advertisedRoutes[prefix] = false
}
for _, route := range currentRoutes {
if _, ok := advertisedRoutes[netip.Prefix(route.Prefix)]; ok {
if !route.Advertised {
route.Advertised = true
err := h.db.Save(&route).Error
if err != nil {
return err
}
}
advertisedRoutes[netip.Prefix(route.Prefix)] = true
} else {
if route.Advertised {
route.Advertised = false
route.Enabled = false
err := h.db.Save(&route).Error
if err != nil {
return err
}
2021-04-28 14:55:29 +00:00
}
}
}
for prefix, exists := range advertisedRoutes {
if !exists {
route := Route{
MachineID: machine.ID,
Prefix: IPPrefix(prefix),
Advertised: true,
Enabled: false,
}
err := h.db.Create(&route).Error
if err != nil {
return err
}
}
2022-05-30 13:31:06 +00:00
}
return nil
}