mirror of
https://github.com/juanfont/headscale.git
synced 2025-12-16 22:22:13 +00:00
Compare commits
3 Commits
v0.27.2-rc
...
doc/0.26.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00a5cce7fd | ||
|
|
4d89030701 | ||
|
|
474ea236d0 |
@@ -1,6 +1,12 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
## Next
|
## 0.26.1 (2025-06-06)
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Ensure nodes are matching both node key and machine key
|
||||||
|
when connecting.
|
||||||
|
[#2642](https://github.com/juanfont/headscale/pull/2642)
|
||||||
|
|
||||||
## 0.26.0 (2025-05-14)
|
## 0.26.0 (2025-05-14)
|
||||||
|
|
||||||
|
|||||||
@@ -112,11 +112,11 @@ docker exec -it headscale \
|
|||||||
|
|
||||||
### Register a machine using a pre authenticated key
|
### Register a machine using a pre authenticated key
|
||||||
|
|
||||||
Generate a key using the command line:
|
Generate a key using the command line for the user with ID 1:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker exec -it headscale \
|
docker exec -it headscale \
|
||||||
headscale preauthkeys create --user myfirstuser --reusable --expiration 24h
|
headscale preauthkeys create --user 1 --reusable --expiration 24h
|
||||||
```
|
```
|
||||||
|
|
||||||
This will return a pre-authenticated key that can be used to connect a node to headscale with the `tailscale up` command:
|
This will return a pre-authenticated key that can be used to connect a node to headscale with the `tailscale up` command:
|
||||||
|
|||||||
@@ -117,14 +117,14 @@ headscale instance. By default, the key is valid for one hour and can only be us
|
|||||||
=== "Native"
|
=== "Native"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
headscale preauthkeys create --user <USER>
|
headscale preauthkeys create --user <USER_ID>
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Container"
|
=== "Container"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker exec -it headscale \
|
docker exec -it headscale \
|
||||||
headscale preauthkeys create --user <USER>
|
headscale preauthkeys create --user <USER_ID>
|
||||||
```
|
```
|
||||||
|
|
||||||
The command returns the preauthkey on success which is used to connect a node to the headscale instance via the
|
The command returns the preauthkey on success which is used to connect a node to the headscale instance via the
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ func (h *Headscale) NoiseUpgradeHandler(
|
|||||||
|
|
||||||
router.HandleFunc("/machine/register", noiseServer.NoiseRegistrationHandler).
|
router.HandleFunc("/machine/register", noiseServer.NoiseRegistrationHandler).
|
||||||
Methods(http.MethodPost)
|
Methods(http.MethodPost)
|
||||||
|
|
||||||
|
// Endpoints outside of the register endpoint must use getAndValidateNode to
|
||||||
|
// get the node to ensure that the MachineKey matches the Node setting up the
|
||||||
|
// connection.
|
||||||
router.HandleFunc("/machine/map", noiseServer.NoisePollNetMapHandler)
|
router.HandleFunc("/machine/map", noiseServer.NoisePollNetMapHandler)
|
||||||
|
|
||||||
noiseServer.httpBaseConfig = &http.Server{
|
noiseServer.httpBaseConfig = &http.Server{
|
||||||
@@ -209,18 +213,14 @@ func (ns *noiseServer) NoisePollNetMapHandler(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ns.nodeKey = mapRequest.NodeKey
|
node, err := ns.getAndValidateNode(mapRequest)
|
||||||
|
|
||||||
node, err := ns.headscale.db.GetNodeByNodeKey(mapRequest.NodeKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
httpError(writer, NewHTTPError(http.StatusNotFound, "node not found", nil))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
httpError(writer, err)
|
httpError(writer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ns.nodeKey = node.NodeKey
|
||||||
|
|
||||||
sess := ns.headscale.newMapSession(req.Context(), mapRequest, writer, node)
|
sess := ns.headscale.newMapSession(req.Context(), mapRequest, writer, node)
|
||||||
sess.tracef("a node sending a MapRequest with Noise protocol")
|
sess.tracef("a node sending a MapRequest with Noise protocol")
|
||||||
if !sess.isStreaming() {
|
if !sess.isStreaming() {
|
||||||
@@ -266,8 +266,8 @@ func (ns *noiseServer) NoiseRegistrationHandler(
|
|||||||
Error: httpErr.Msg,
|
Error: httpErr.Msg,
|
||||||
}
|
}
|
||||||
return ®Req, resp
|
return ®Req, resp
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ®Req, regErr(err)
|
return ®Req, regErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,3 +289,22 @@ func (ns *noiseServer) NoiseRegistrationHandler(
|
|||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.Write(respBody)
|
writer.Write(respBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getAndValidateNode retrieves the node from the database using the NodeKey
|
||||||
|
// and validates that it matches the MachineKey from the Noise session.
|
||||||
|
func (ns *noiseServer) getAndValidateNode(mapRequest tailcfg.MapRequest) (*types.Node, error) {
|
||||||
|
node, err := ns.headscale.db.GetNodeByNodeKey(mapRequest.NodeKey)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, NewHTTPError(http.StatusNotFound, "node not found", nil)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the MachineKey in the Noise session matches the one associated with the NodeKey.
|
||||||
|
if ns.machineKey != node.MachineKey {
|
||||||
|
return nil, NewHTTPError(http.StatusNotFound, "node key in request does not match the one associated with this machine key", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ extra:
|
|||||||
- icon: fontawesome/brands/discord
|
- icon: fontawesome/brands/discord
|
||||||
link: https://discord.gg/c84AZQhmpx
|
link: https://discord.gg/c84AZQhmpx
|
||||||
headscale:
|
headscale:
|
||||||
version: 0.26.0
|
version: 0.26.1
|
||||||
|
|
||||||
# Extensions
|
# Extensions
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
|
|||||||
Reference in New Issue
Block a user