headscale now has a CLI - registration of machines occurs there
This commit is contained in:
parent
ff7db34b5e
commit
b1d06f3ffd
5 changed files with 127 additions and 35 deletions
36
app.go
36
app.go
|
@ -3,6 +3,7 @@ package headscale
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
@ -65,3 +66,38 @@ func (h *Headscale) Serve() error {
|
||||||
err := r.Run(h.cfg.Addr)
|
err := r.Run(h.cfg.Addr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Headscale) RegisterMachine(key string) error {
|
||||||
|
mKey, err := wgcfg.ParseHexKey(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot parse client key: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
db, err := h.db()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot open DB: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
m := Machine{}
|
||||||
|
if db.First(&m, "machine_key = ?", mKey.HexString()).RecordNotFound() {
|
||||||
|
log.Printf("Cannot find machine with machine key: %s", mKey.Base64())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.isAlreadyRegistered() {
|
||||||
|
fmt.Println("This machine already registered")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := h.getAvailableIP()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.IPAddress = ip.String()
|
||||||
|
m.Registered = true
|
||||||
|
db.Save(&m)
|
||||||
|
fmt.Println("Machine registered 🎉")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,72 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/juanfont/headscale"
|
"github.com/juanfont/headscale"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const version = "0.1"
|
||||||
|
|
||||||
|
var versionCmd = &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print the version.",
|
||||||
|
Long: "The version of headscale.",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(version)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var headscaleCmd = &cobra.Command{
|
||||||
|
Use: "headscale",
|
||||||
|
Short: "headscale - a Tailscale control server",
|
||||||
|
Long: fmt.Sprintf(`
|
||||||
|
headscale is an open source implementation of the Tailscale control server
|
||||||
|
|
||||||
|
Juan Font Alonso <juanfontalonso@gmail.com> - 2021
|
||||||
|
https://gitlab.com/juanfont/headscale`),
|
||||||
|
}
|
||||||
|
|
||||||
|
var serveCmd = &cobra.Command{
|
||||||
|
Use: "serve",
|
||||||
|
Short: "Launches the headscale server",
|
||||||
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
h, err := getHeadscaleApp()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error initializing: %s", err)
|
||||||
|
}
|
||||||
|
h.Serve()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerCmd = &cobra.Command{
|
||||||
|
Use: "register machineID",
|
||||||
|
Short: "Registers a machine to your network",
|
||||||
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("Missing parameters")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
h, err := getHeadscaleApp()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error initializing: %s", err)
|
||||||
|
}
|
||||||
|
h.RegisterMachine(args[0])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
viper.SetConfigName("config")
|
viper.SetConfigName("config")
|
||||||
viper.AddConfigPath(".")
|
viper.AddConfigPath(".")
|
||||||
|
@ -20,6 +76,18 @@ func main() {
|
||||||
log.Fatalf("Fatal error config file: %s \n", err)
|
log.Fatalf("Fatal error config file: %s \n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headscaleCmd.AddCommand(versionCmd)
|
||||||
|
headscaleCmd.AddCommand(serveCmd)
|
||||||
|
headscaleCmd.AddCommand(registerCmd)
|
||||||
|
|
||||||
|
if err := headscaleCmd.Execute(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHeadscaleApp() (*headscale.Headscale, error) {
|
||||||
derpMap, err := loadDerpMap(viper.GetString("derp_map_path"))
|
derpMap, err := loadDerpMap(viper.GetString("derp_map_path"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Could not load DERP servers map file: %s", err)
|
log.Printf("Could not load DERP servers map file: %s", err)
|
||||||
|
@ -39,9 +107,9 @@ func main() {
|
||||||
}
|
}
|
||||||
h, err := headscale.NewHeadscale(cfg)
|
h, err := headscale.NewHeadscale(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
h.Serve()
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDerpMap(path string) (*tailcfg.DERPMap, error) {
|
func loadDerpMap(path string) (*tailcfg.DERPMap, error) {
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/gin-gonic/gin v1.6.3
|
github.com/gin-gonic/gin v1.6.3
|
||||||
github.com/jinzhu/gorm v1.9.16
|
github.com/jinzhu/gorm v1.9.16
|
||||||
github.com/klauspost/compress v1.11.7
|
github.com/klauspost/compress v1.11.7
|
||||||
|
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||||
gopkg.in/yaml.v2 v2.2.8
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -232,6 +232,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||||
|
@ -380,6 +381,7 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee h1:GQkkv3XSnxhAMjdq2wLfEnptEVr+2BNvmHizILHn+d4=
|
||||||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
|
49
handlers.go
49
handlers.go
|
@ -262,41 +262,26 @@ func (h *Headscale) RegisterWebAPI(c *gin.Context) {
|
||||||
c.String(http.StatusBadRequest, "Wrong params")
|
c.String(http.StatusBadRequest, "Wrong params")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mKey, err := wgcfg.ParseHexKey(mKeyStr)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Cannot parse client key: %s", err)
|
|
||||||
c.String(http.StatusInternalServerError, "Sad!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
db, err := h.db()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Cannot open DB: %s", err)
|
|
||||||
c.String(http.StatusInternalServerError, ":(")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
m := Machine{}
|
|
||||||
if db.First(&m, "machine_key = ?", mKey.HexString()).RecordNotFound() {
|
|
||||||
log.Printf("Cannot find machine with machine key: %s", mKey.Base64())
|
|
||||||
c.String(http.StatusNotFound, "Sad!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !m.isAlreadyRegistered() {
|
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(`
|
||||||
ip, err := h.getAvailableIP()
|
<html>
|
||||||
if err != nil {
|
<body>
|
||||||
log.Println(err)
|
<h1>headscale</h1>
|
||||||
c.String(http.StatusInternalServerError, "Upsy dupsy")
|
<p>
|
||||||
return
|
Run the command below in the headscale server to add this machine to your network:
|
||||||
}
|
</p>
|
||||||
m.IPAddress = ip.String()
|
|
||||||
m.Registered = true // very naive 😱
|
|
||||||
db.Save(&m)
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"msg": "Ook"})
|
<p>
|
||||||
|
<code>
|
||||||
|
<b>headscale register %s</b>
|
||||||
|
</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
`, mKeyStr)))
|
||||||
return
|
return
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, gin.H{"msg": "Eek"})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) handleNewServer(c *gin.Context, db *gorm.DB, idKey wgcfg.Key, req tailcfg.RegisterRequest) {
|
func (h *Headscale) handleNewServer(c *gin.Context, db *gorm.DB, idKey wgcfg.Key, req tailcfg.RegisterRequest) {
|
||||||
|
|
Loading…
Reference in a new issue