Skip to content

Commit

Permalink
move derp_server to derp server module
Browse files Browse the repository at this point in the history
Signed-off-by: Kristoffer Dalby <[email protected]>
  • Loading branch information
kradalby committed Jun 8, 2023
1 parent 8c4c4c8 commit 80ea87c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 62 deletions.
27 changes: 18 additions & 9 deletions hscontrol/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol/db"
"github.com/juanfont/headscale/hscontrol/derp"
derpServer "github.com/juanfont/headscale/hscontrol/derp/server"
"github.com/juanfont/headscale/hscontrol/policy"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/util"
Expand Down Expand Up @@ -79,7 +80,7 @@ type Headscale struct {
noisePrivateKey *key.MachinePrivate

DERPMap *tailcfg.DERPMap
DERPServer *DERPServer
DERPServer *derpServer.DERPServer

ACLPolicy *policy.ACLPolicy

Expand Down Expand Up @@ -202,7 +203,8 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
}

if cfg.DERP.ServerEnabled {
embeddedDERPServer, err := app.NewDERPServer()
// TODO(kradalby): replace this key with a dedicated DERP key.
embeddedDERPServer, err := derpServer.NewDERPServer(cfg.ServerURL, key.NodePrivate(*privateKey), &cfg.DERP)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -237,7 +239,7 @@ func (h *Headscale) expireExpiredMachines(milliSeconds int64) {
}

// scheduledDERPMapUpdateWorker refreshes the DERPMap stored on the global object
// at a set interval
// at a set interval.
func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) {
log.Info().
Dur("frequency", h.cfg.DERP.UpdateFrequency).
Expand All @@ -253,7 +255,8 @@ func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) {
log.Info().Msg("Fetching DERPMap updates")
h.DERPMap = derp.GetDERPMap(h.cfg.DERP)
if h.cfg.DERP.ServerEnabled {
h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
region, _ := h.DERPServer.GenerateRegion()
h.DERPMap.Regions[region.RegionID] = &region
}

h.setLastStateChangeToNow()
Expand Down Expand Up @@ -456,9 +459,9 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router {
Methods(http.MethodGet)

if h.cfg.DERP.ServerEnabled {
router.HandleFunc("/derp", h.DERPHandler)
router.HandleFunc("/derp/probe", h.DERPProbeHandler)
router.HandleFunc("/bootstrap-dns", h.DERPBootstrapDNSHandler)
router.HandleFunc("/derp", h.DERPServer.DERPHandler)
router.HandleFunc("/derp/probe", derpServer.DERPProbeHandler)
router.HandleFunc("/bootstrap-dns", derpServer.DERPBootstrapDNSHandler(h.DERPMap))
}

apiRouter := router.PathPrefix("/api").Subrouter()
Expand All @@ -483,8 +486,14 @@ func (h *Headscale) Serve() error {
return errSTUNAddressNotSet
}

h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
go h.ServeSTUN()
region, err := h.DERPServer.GenerateRegion()
if err != nil {
return err
}

h.DERPMap.Regions[region.RegionID] = &region

go h.DERPServer.ServeSTUN()
}

if h.cfg.DERP.AutoUpdate {
Expand Down
118 changes: 65 additions & 53 deletions hscontrol/derp_server.go → hscontrol/derp/server/derp_server.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package hscontrol
package server

import (
"context"
Expand All @@ -12,6 +12,7 @@ import (
"strings"
"time"

"github.com/juanfont/headscale/hscontrol/types"
"github.com/rs/zerolog/log"
"tailscale.com/derp"
"tailscale.com/net/stun"
Expand All @@ -26,23 +27,30 @@ import (
const fastStartHeader = "Derp-Fast-Start"

type DERPServer struct {
serverURL string
key key.NodePrivate
cfg *types.DERPConfig
tailscaleDERP *derp.Server
region tailcfg.DERPRegion
}

func (h *Headscale) NewDERPServer() (*DERPServer, error) {
func NewDERPServer(
serverURL string,
derpKey key.NodePrivate,
cfg *types.DERPConfig,
) (*DERPServer, error) {
log.Trace().Caller().Msg("Creating new embedded DERP server")
server := derp.NewServer(key.NodePrivate(*h.privateKey2019), log.Info().Msgf)
region, err := h.generateRegionLocalDERP()
if err != nil {
return nil, err
}

return &DERPServer{server, region}, nil
server := derp.NewServer(derpKey, log.Debug().Msgf)

return &DERPServer{
serverURL: serverURL,
key: derpKey,
cfg: cfg,
tailscaleDERP: server,
}, nil
}

func (h *Headscale) generateRegionLocalDERP() (tailcfg.DERPRegion, error) {
serverURL, err := url.Parse(h.cfg.ServerURL)
func (d *DERPServer) GenerateRegion() (tailcfg.DERPRegion, error) {
serverURL, err := url.Parse(d.serverURL)
if err != nil {
return tailcfg.DERPRegion{}, err
}
Expand All @@ -65,21 +73,21 @@ func (h *Headscale) generateRegionLocalDERP() (tailcfg.DERPRegion, error) {
}

localDERPregion := tailcfg.DERPRegion{
RegionID: h.cfg.DERP.ServerRegionID,
RegionCode: h.cfg.DERP.ServerRegionCode,
RegionName: h.cfg.DERP.ServerRegionName,
RegionID: d.cfg.ServerRegionID,
RegionCode: d.cfg.ServerRegionCode,
RegionName: d.cfg.ServerRegionName,
Avoid: false,
Nodes: []*tailcfg.DERPNode{
{
Name: fmt.Sprintf("%d", h.cfg.DERP.ServerRegionID),
RegionID: h.cfg.DERP.ServerRegionID,
Name: fmt.Sprintf("%d", d.cfg.ServerRegionID),
RegionID: d.cfg.ServerRegionID,
HostName: host,
DERPPort: port,
},
},
}

_, portSTUNStr, err := net.SplitHostPort(h.cfg.DERP.STUNAddr)
_, portSTUNStr, err := net.SplitHostPort(d.cfg.STUNAddr)
if err != nil {
return tailcfg.DERPRegion{}, err
}
Expand All @@ -94,7 +102,7 @@ func (h *Headscale) generateRegionLocalDERP() (tailcfg.DERPRegion, error) {
return localDERPregion, nil
}

func (h *Headscale) DERPHandler(
func (d *DERPServer) DERPHandler(
writer http.ResponseWriter,
req *http.Request,
) {
Expand Down Expand Up @@ -156,7 +164,7 @@ func (h *Headscale) DERPHandler(
log.Trace().Caller().Msgf("Hijacked connection from %v", req.RemoteAddr)

if !fastStart {
pubKey := h.privateKey2019.Public()
pubKey := d.key.Public()
pubKeyStr, _ := pubKey.MarshalText() //nolint
fmt.Fprintf(conn, "HTTP/1.1 101 Switching Protocols\r\n"+
"Upgrade: DERP\r\n"+
Expand All @@ -167,12 +175,12 @@ func (h *Headscale) DERPHandler(
string(pubKeyStr))
}

h.DERPServer.tailscaleDERP.Accept(req.Context(), netConn, conn, netConn.RemoteAddr().String())
d.tailscaleDERP.Accept(req.Context(), netConn, conn, netConn.RemoteAddr().String())
}

// DERPProbeHandler is the endpoint that js/wasm clients hit to measure
// DERP latency, since they can't do UDP STUN queries.
func (h *Headscale) DERPProbeHandler(
func DERPProbeHandler(
writer http.ResponseWriter,
req *http.Request,
) {
Expand All @@ -199,43 +207,47 @@ func (h *Headscale) DERPProbeHandler(
// The initial implementation is here https://github.com/tailscale/tailscale/pull/1406
// They have a cache, but not clear if that is really necessary at Headscale, uh, scale.
// An example implementation is found here https://derp.tailscale.com/bootstrap-dns
func (h *Headscale) DERPBootstrapDNSHandler(
writer http.ResponseWriter,
req *http.Request,
) {
dnsEntries := make(map[string][]net.IP)

resolvCtx, cancel := context.WithTimeout(req.Context(), time.Minute)
defer cancel()
var resolver net.Resolver
for _, region := range h.DERPMap.Regions {
for _, node := range region.Nodes { // we don't care if we override some nodes
addrs, err := resolver.LookupIP(resolvCtx, "ip", node.HostName)
if err != nil {
log.Trace().
Caller().
Err(err).
Msgf("bootstrap DNS lookup failed %q", node.HostName)

continue
func DERPBootstrapDNSHandler(
derpMap *tailcfg.DERPMap,
) func(http.ResponseWriter, *http.Request) {
return func(
writer http.ResponseWriter,
req *http.Request,
) {
dnsEntries := make(map[string][]net.IP)

resolvCtx, cancel := context.WithTimeout(req.Context(), time.Minute)
defer cancel()
var resolver net.Resolver
for _, region := range derpMap.Regions {
for _, node := range region.Nodes { // we don't care if we override some nodes
addrs, err := resolver.LookupIP(resolvCtx, "ip", node.HostName)
if err != nil {
log.Trace().
Caller().
Err(err).
Msgf("bootstrap DNS lookup failed %q", node.HostName)

continue
}
dnsEntries[node.HostName] = addrs
}
dnsEntries[node.HostName] = addrs
}
}
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(http.StatusOK)
err := json.NewEncoder(writer).Encode(dnsEntries)
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(http.StatusOK)
err := json.NewEncoder(writer).Encode(dnsEntries)
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}
}
}

// ServeSTUN starts a STUN server on the configured addr.
func (h *Headscale) ServeSTUN() {
packetConn, err := net.ListenPacket("udp", h.cfg.DERP.STUNAddr)
func (d *DERPServer) ServeSTUN() {
packetConn, err := net.ListenPacket("udp", d.cfg.STUNAddr)
if err != nil {
log.Fatal().Msgf("failed to open STUN listener: %v", err)
}
Expand Down

0 comments on commit 80ea87c

Please sign in to comment.