mirror of
https://github.com/juanfont/headscale.git
synced 2024-12-20 23:17:33 +00:00
fix deletion of exit routes without nodes (#2286)
Fixes #2259 Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
76d26a7eec
commit
58d089ce0a
hscontrol
@ -117,13 +117,13 @@ func EnableRoute(tx *gorm.DB, id uint64) (*types.StateUpdate, error) {
|
|||||||
if route.IsExitRoute() {
|
if route.IsExitRoute() {
|
||||||
return enableRoutes(
|
return enableRoutes(
|
||||||
tx,
|
tx,
|
||||||
&route.Node,
|
route.Node,
|
||||||
tsaddr.AllIPv4(),
|
tsaddr.AllIPv4(),
|
||||||
tsaddr.AllIPv6(),
|
tsaddr.AllIPv6(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return enableRoutes(tx, &route.Node, netip.Prefix(route.Prefix))
|
return enableRoutes(tx, route.Node, netip.Prefix(route.Prefix))
|
||||||
}
|
}
|
||||||
|
|
||||||
func DisableRoute(tx *gorm.DB,
|
func DisableRoute(tx *gorm.DB,
|
||||||
@ -154,7 +154,7 @@ func DisableRoute(tx *gorm.DB,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
routes, err = GetNodeRoutes(tx, &node)
|
routes, err = GetNodeRoutes(tx, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -201,24 +201,26 @@ func DeleteRoute(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if route.Node == nil {
|
||||||
|
// If the route is not assigned to a node, just delete it,
|
||||||
|
// there are no updates to be sent as no nodes are
|
||||||
|
// dependent on it
|
||||||
|
if err := tx.Unscoped().Delete(&route).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var routes types.Routes
|
var routes types.Routes
|
||||||
node := route.Node
|
node := route.Node
|
||||||
|
|
||||||
// Tailscale requires both IPv4 and IPv6 exit routes to
|
// Tailscale requires both IPv4 and IPv6 exit routes to
|
||||||
// be enabled at the same time, as per
|
// be enabled at the same time, as per
|
||||||
// https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002
|
// https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002
|
||||||
|
// This means that if we delete a route which is an exit route, delete both.
|
||||||
var update []types.NodeID
|
var update []types.NodeID
|
||||||
if !route.IsExitRoute() {
|
if route.IsExitRoute() {
|
||||||
update, err = failoverRouteTx(tx, isLikelyConnected, route)
|
routes, err = GetNodeRoutes(tx, node)
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Unscoped().Delete(&route).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
routes, err = GetNodeRoutes(tx, &node)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -233,13 +235,22 @@ func DeleteRoute(
|
|||||||
if err := tx.Unscoped().Delete(&routesToDelete).Error; err != nil {
|
if err := tx.Unscoped().Delete(&routesToDelete).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
update, err = failoverRouteTx(tx, isLikelyConnected, route)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Unscoped().Delete(&route).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If update is empty, it means that one was not created
|
// If update is empty, it means that one was not created
|
||||||
// by failover (as a failover was not necessary), create
|
// by failover (as a failover was not necessary), create
|
||||||
// one and return to the caller.
|
// one and return to the caller.
|
||||||
if routes == nil {
|
if routes == nil {
|
||||||
routes, err = GetNodeRoutes(tx, &node)
|
routes, err = GetNodeRoutes(tx, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -290,23 +290,18 @@ func (s *Suite) TestDeleteRoutes(c *check.C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ipp = func(s string) netip.Prefix { return netip.MustParsePrefix(s) }
|
ipp = func(s string) netip.Prefix { return netip.MustParsePrefix(s) }
|
||||||
mkNode = func(nid types.NodeID) types.Node {
|
np = func(nid types.NodeID) *types.Node {
|
||||||
return types.Node{ID: nid}
|
return &types.Node{ID: nid}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var np = func(nid types.NodeID) *types.Node {
|
|
||||||
no := mkNode(nid)
|
|
||||||
return &no
|
|
||||||
}
|
|
||||||
|
|
||||||
var r = func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) types.Route {
|
var r = func(id uint, nid types.NodeID, prefix netip.Prefix, enabled, primary bool) types.Route {
|
||||||
return types.Route{
|
return types.Route{
|
||||||
Model: gorm.Model{
|
Model: gorm.Model{
|
||||||
ID: id,
|
ID: id,
|
||||||
},
|
},
|
||||||
Node: mkNode(nid),
|
Node: np(nid),
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
Enabled: enabled,
|
Enabled: enabled,
|
||||||
IsPrimary: primary,
|
IsPrimary: primary,
|
||||||
@ -693,7 +688,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{},
|
Node: &types.Node{},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
},
|
},
|
||||||
routes: types.Routes{},
|
routes: types.Routes{},
|
||||||
@ -707,7 +702,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("0.0.0.0/0"),
|
Prefix: ipp("0.0.0.0/0"),
|
||||||
Node: types.Node{},
|
Node: &types.Node{},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
},
|
},
|
||||||
routes: types.Routes{},
|
routes: types.Routes{},
|
||||||
@ -721,7 +716,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -732,7 +727,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -748,7 +743,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -760,7 +755,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -771,7 +766,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -795,7 +790,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -807,7 +802,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -818,7 +813,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -835,7 +830,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -847,7 +842,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -858,7 +853,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -869,7 +864,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 3,
|
ID: 3,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 3,
|
ID: 3,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -893,7 +888,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -905,7 +900,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -917,7 +912,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -938,7 +933,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -950,7 +945,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -962,7 +957,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -973,7 +968,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 3,
|
ID: 3,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -998,7 +993,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -1010,7 +1005,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
IsPrimary: true,
|
IsPrimary: true,
|
||||||
@ -1022,7 +1017,7 @@ func TestFailoverRouteTx(t *testing.T) {
|
|||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
Prefix: ipp("10.0.0.0/24"),
|
Prefix: ipp("10.0.0.0/24"),
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
},
|
},
|
||||||
IsPrimary: false,
|
IsPrimary: false,
|
||||||
@ -1075,7 +1070,7 @@ func TestFailoverRoute(t *testing.T) {
|
|||||||
Model: gorm.Model{
|
Model: gorm.Model{
|
||||||
ID: id,
|
ID: id,
|
||||||
},
|
},
|
||||||
Node: types.Node{
|
Node: &types.Node{
|
||||||
ID: nid,
|
ID: nid,
|
||||||
},
|
},
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
|
@ -14,7 +14,7 @@ type Route struct {
|
|||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
||||||
NodeID uint64
|
NodeID uint64
|
||||||
Node Node
|
Node *Node
|
||||||
|
|
||||||
// TODO(kradalby): change this custom type to netip.Prefix
|
// TODO(kradalby): change this custom type to netip.Prefix
|
||||||
Prefix netip.Prefix `gorm:"serializer:text"`
|
Prefix netip.Prefix `gorm:"serializer:text"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user