Skip to content

Commit 5164b27

Browse files
committed
make it harder to insert invalid routes (#2371)
* make it harder to insert invalid routes Signed-off-by: Kristoffer Dalby <[email protected]> * dont panic if node is not available for route Signed-off-by: Kristoffer Dalby <[email protected]> * update changelog Signed-off-by: Kristoffer Dalby <[email protected]> --------- Signed-off-by: Kristoffer Dalby <[email protected]>
1 parent 479f799 commit 5164b27

File tree

4 files changed

+34
-3
lines changed

4 files changed

+34
-3
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Relax username validation to allow emails
88
[#2364](https://github.com/juanfont/headscale/pull/2364)
9+
- Remove invalid routes and add stronger constraints for routes to avoid API panic
10+
[#2371](https://github.com/juanfont/headscale/pull/2371)
911

1012
## 0.24.0 (2025-01-17)
1113

cmd/headscale/cli/routes.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,15 @@ func routesToPtables(routes []*v1.Route) pterm.TableData {
251251
isPrimaryStr = strconv.FormatBool(route.GetIsPrimary())
252252
}
253253

254+
var nodeName string
255+
if route.GetNode() != nil {
256+
nodeName = route.GetNode().GetGivenName()
257+
}
258+
254259
tableData = append(tableData,
255260
[]string{
256261
strconv.FormatUint(route.GetId(), Base10),
257-
route.GetNode().GetGivenName(),
262+
nodeName,
258263
route.GetPrefix(),
259264
strconv.FormatBool(route.GetAdvertised()),
260265
strconv.FormatBool(route.GetEnabled()),

hscontrol/db/db.go

+21
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,27 @@ func NewHeadscaleDatabase(
521521
},
522522
Rollback: func(db *gorm.DB) error { return nil },
523523
},
524+
{
525+
// Add a constraint to routes ensuring they cannot exist without a node.
526+
ID: "202501221827",
527+
Migrate: func(tx *gorm.DB) error {
528+
// Remove any invalid routes associated with a node that does not exist.
529+
if tx.Migrator().HasTable(&types.Route{}) && tx.Migrator().HasTable(&types.Node{}) {
530+
err := tx.Exec("delete from routes where node_id not in (select id from nodes)").Error
531+
if err != nil {
532+
return err
533+
}
534+
}
535+
536+
err := tx.AutoMigrate(&types.Route{})
537+
if err != nil {
538+
return err
539+
}
540+
541+
return nil
542+
},
543+
Rollback: func(db *gorm.DB) error { return nil },
544+
},
524545
},
525546
)
526547

hscontrol/types/routes.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
type Route struct {
1414
gorm.Model
1515

16-
NodeID uint64
16+
NodeID uint64 `gorm:"not null"`
1717
Node *Node
1818

1919
// TODO(kradalby): change this custom type to netip.Prefix
@@ -79,7 +79,6 @@ func (rs Routes) Proto() []*v1.Route {
7979
for _, route := range rs {
8080
protoRoute := v1.Route{
8181
Id: uint64(route.ID),
82-
Node: route.Node.Proto(),
8382
Prefix: route.Prefix.String(),
8483
Advertised: route.Advertised,
8584
Enabled: route.Enabled,
@@ -88,6 +87,10 @@ func (rs Routes) Proto() []*v1.Route {
8887
UpdatedAt: timestamppb.New(route.UpdatedAt),
8988
}
9089

90+
if route.Node != nil {
91+
protoRoute.Node = route.Node.Proto()
92+
}
93+
9194
if route.DeletedAt.Valid {
9295
protoRoute.DeletedAt = timestamppb.New(route.DeletedAt.Time)
9396
}

0 commit comments

Comments
 (0)