2020-06-21 18:32:08 +08:00
|
|
|
package headscale
|
|
|
|
|
|
|
|
import (
|
2021-12-23 10:43:53 +08:00
|
|
|
"bytes"
|
2020-06-21 18:32:08 +08:00
|
|
|
"encoding/json"
|
2021-12-23 10:43:53 +08:00
|
|
|
"html/template"
|
2020-06-21 18:32:08 +08:00
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
2022-06-20 18:30:41 +08:00
|
|
|
"github.com/gorilla/mux"
|
2021-11-13 16:39:04 +08:00
|
|
|
"github.com/rs/zerolog/log"
|
2020-06-21 18:32:08 +08:00
|
|
|
)
|
|
|
|
|
2021-11-18 16:49:55 +08:00
|
|
|
const (
|
2022-08-12 15:36:17 +08:00
|
|
|
// TODO(juan): remove this once https://github.com/juanfont/headscale/issues/727 is fixed.
|
2022-08-12 15:02:58 +08:00
|
|
|
registrationHoldoff = time.Second * 5
|
2021-11-23 03:32:52 +08:00
|
|
|
reservedResponseHeaderSize = 4
|
2022-02-28 01:48:12 +08:00
|
|
|
RegisterMethodAuthKey = "authkey"
|
2021-11-23 03:32:52 +08:00
|
|
|
RegisterMethodOIDC = "oidc"
|
|
|
|
RegisterMethodCLI = "cli"
|
|
|
|
ErrRegisterMethodCLIDoesNotSupportExpire = Error(
|
|
|
|
"machines registered with CLI does not support expire",
|
|
|
|
)
|
2021-11-18 16:49:55 +08:00
|
|
|
)
|
2021-11-15 01:31:51 +08:00
|
|
|
|
2022-07-06 19:39:10 +08:00
|
|
|
func (h *Headscale) HealthHandler(
|
|
|
|
writer http.ResponseWriter,
|
|
|
|
req *http.Request,
|
|
|
|
) {
|
|
|
|
respond := func(err error) {
|
|
|
|
writer.Header().Set("Content-Type", "application/health+json; charset=utf-8")
|
|
|
|
|
|
|
|
res := struct {
|
|
|
|
Status string `json:"status"`
|
|
|
|
}{
|
|
|
|
Status: "pass",
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
|
|
|
log.Error().Caller().Err(err).Msg("health check failed")
|
|
|
|
res.Status = "fail"
|
|
|
|
}
|
|
|
|
|
|
|
|
buf, err := json.Marshal(res)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Caller().Err(err).Msg("marshal failed")
|
|
|
|
}
|
|
|
|
_, err = writer.Write(buf)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Caller().Err(err).Msg("write failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-04 17:43:09 +08:00
|
|
|
if err := h.pingDB(req.Context()); err != nil {
|
2022-07-06 19:39:10 +08:00
|
|
|
respond(err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
respond(nil)
|
|
|
|
}
|
|
|
|
|
2021-12-23 10:43:53 +08:00
|
|
|
type registerWebAPITemplateConfig struct {
|
|
|
|
Key string
|
|
|
|
}
|
2021-02-28 07:58:09 +08:00
|
|
|
|
2021-12-23 10:43:53 +08:00
|
|
|
var registerWebAPITemplate = template.Must(
|
2022-03-08 16:34:46 +08:00
|
|
|
template.New("registerweb").Parse(`
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>Registration - Headscale</title>
|
|
|
|
</head>
|
2021-02-28 07:58:09 +08:00
|
|
|
<body>
|
2022-03-08 16:34:46 +08:00
|
|
|
<h1>headscale</h1>
|
|
|
|
<h2>Machine registration</h2>
|
|
|
|
<p>
|
|
|
|
Run the command below in the headscale server to add this machine to your network:
|
|
|
|
</p>
|
|
|
|
<pre><code>headscale -n NAMESPACE nodes register --key {{.Key}}</code></pre>
|
2021-02-28 07:58:09 +08:00
|
|
|
</body>
|
2022-03-08 16:34:46 +08:00
|
|
|
</html>
|
|
|
|
`))
|
2021-12-23 10:43:53 +08:00
|
|
|
|
|
|
|
// RegisterWebAPI shows a simple message in the browser to point to the CLI
|
2022-08-11 18:11:02 +08:00
|
|
|
// Listens in /register/:nkey.
|
2022-08-11 18:16:50 +08:00
|
|
|
//
|
|
|
|
// This is not part of the Tailscale control API, as we could send whatever URL
|
|
|
|
// in the RegisterResponse.AuthURL field.
|
2022-06-17 22:48:04 +08:00
|
|
|
func (h *Headscale) RegisterWebAPI(
|
2022-06-26 17:55:37 +08:00
|
|
|
writer http.ResponseWriter,
|
|
|
|
req *http.Request,
|
2022-06-17 22:48:04 +08:00
|
|
|
) {
|
2022-08-11 18:11:02 +08:00
|
|
|
vars := mux.Vars(req)
|
|
|
|
nodeKeyStr, ok := vars["nkey"]
|
|
|
|
if !ok || nodeKeyStr == "" {
|
2022-06-26 17:55:37 +08:00
|
|
|
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
|
|
writer.WriteHeader(http.StatusBadRequest)
|
2022-06-26 18:21:35 +08:00
|
|
|
_, err := writer.Write([]byte("Wrong params"))
|
|
|
|
if err != nil {
|
|
|
|
log.Error().
|
|
|
|
Caller().
|
|
|
|
Err(err).
|
|
|
|
Msg("Failed to write response")
|
|
|
|
}
|
2021-12-23 10:43:53 +08:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var content bytes.Buffer
|
|
|
|
if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{
|
2022-08-10 21:35:26 +08:00
|
|
|
Key: nodeKeyStr,
|
2021-12-23 10:43:53 +08:00
|
|
|
}); err != nil {
|
|
|
|
log.Error().
|
|
|
|
Str("func", "RegisterWebAPI").
|
|
|
|
Err(err).
|
|
|
|
Msg("Could not render register web API template")
|
2022-06-26 17:55:37 +08:00
|
|
|
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
2022-06-26 18:21:35 +08:00
|
|
|
_, err = writer.Write([]byte("Could not render register web API template"))
|
|
|
|
if err != nil {
|
|
|
|
log.Error().
|
|
|
|
Caller().
|
|
|
|
Err(err).
|
|
|
|
Msg("Failed to write response")
|
|
|
|
}
|
2022-06-26 17:55:37 +08:00
|
|
|
|
|
|
|
return
|
2021-12-23 10:43:53 +08:00
|
|
|
}
|
2021-05-25 03:59:03 +08:00
|
|
|
|
2022-06-26 17:55:37 +08:00
|
|
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
|
|
writer.WriteHeader(http.StatusOK)
|
2022-06-26 18:21:35 +08:00
|
|
|
_, err := writer.Write(content.Bytes())
|
|
|
|
if err != nil {
|
|
|
|
log.Error().
|
|
|
|
Caller().
|
|
|
|
Err(err).
|
|
|
|
Msg("Failed to write response")
|
|
|
|
}
|
2021-02-28 07:58:09 +08:00
|
|
|
}
|