mirror of
https://github.com/juanfont/headscale.git
synced 2024-12-26 22:25:52 -05:00
c883e79884
This commit rewrites the `routes list` command to use ptables to present a slightly nicer list, including a new field if the route is enabled or not (which is quite useful). In addition, it reworks the enable command to support enabling multiple routes (not only one route as per removed TODO). This allows users to actually take advantage of exit-nodes and subnet relays.
142 lines
3.2 KiB
Go
142 lines
3.2 KiB
Go
package headscale
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/pterm/pterm"
|
|
"gorm.io/datatypes"
|
|
"inet.af/netaddr"
|
|
)
|
|
|
|
// GetAdvertisedNodeRoutes returns the subnet routes advertised by a node (identified by
|
|
// namespace and node name)
|
|
func (h *Headscale) GetAdvertisedNodeRoutes(namespace string, nodeName string) (*[]netaddr.IPPrefix, error) {
|
|
m, err := h.GetMachine(namespace, nodeName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hostInfo, err := m.GetHostInfo()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &hostInfo.RoutableIPs, nil
|
|
}
|
|
|
|
// GetEnabledNodeRoutes returns the subnet routes enabled by a node (identified by
|
|
// namespace and node name)
|
|
func (h *Headscale) GetEnabledNodeRoutes(namespace string, nodeName string) ([]netaddr.IPPrefix, error) {
|
|
m, err := h.GetMachine(namespace, nodeName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data, err := m.EnabledRoutes.MarshalJSON()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
routesStr := []string{}
|
|
err = json.Unmarshal(data, &routesStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
routes := make([]netaddr.IPPrefix, len(routesStr))
|
|
for index, routeStr := range routesStr {
|
|
route, err := netaddr.ParseIPPrefix(routeStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
routes[index] = route
|
|
}
|
|
|
|
return routes, nil
|
|
}
|
|
|
|
func (h *Headscale) IsNodeRouteEnabled(namespace string, nodeName string, routeStr string) bool {
|
|
route, err := netaddr.ParseIPPrefix(routeStr)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
enabledRoutes, err := h.GetEnabledNodeRoutes(namespace, nodeName)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
for _, enabledRoute := range enabledRoutes {
|
|
if route == enabledRoute {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// EnableNodeRoute enables a subnet route advertised by a node (identified by
|
|
// namespace and node name)
|
|
func (h *Headscale) EnableNodeRoute(namespace string, nodeName string, routeStr string) error {
|
|
m, err := h.GetMachine(namespace, nodeName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
route, err := netaddr.ParseIPPrefix(routeStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
availableRoutes, err := h.GetAdvertisedNodeRoutes(namespace, nodeName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
enabledRoutes, err := h.GetEnabledNodeRoutes(namespace, nodeName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
available := false
|
|
for _, availableRoute := range *availableRoutes {
|
|
// If the route is available, and not yet enabled, add it to the new routing table
|
|
if route == availableRoute {
|
|
available = true
|
|
if !h.IsNodeRouteEnabled(namespace, nodeName, routeStr) {
|
|
enabledRoutes = append(enabledRoutes, route)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !available {
|
|
return fmt.Errorf("route (%s) is not available on node %s", nodeName, routeStr)
|
|
}
|
|
|
|
routes, err := json.Marshal(enabledRoutes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m.EnabledRoutes = datatypes.JSON(routes)
|
|
h.db.Save(&m)
|
|
|
|
err = h.RequestMapUpdates(m.NamespaceID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *Headscale) RoutesToPtables(namespace string, nodeName string, availableRoutes []netaddr.IPPrefix) pterm.TableData {
|
|
d := pterm.TableData{{"Route", "Enabled"}}
|
|
|
|
for _, route := range availableRoutes {
|
|
enabled := h.IsNodeRouteEnabled(namespace, nodeName, route.String())
|
|
|
|
d = append(d, []string{route.String(), strconv.FormatBool(enabled)})
|
|
}
|
|
return d
|
|
}
|