Make STUN server configurable

This commit is contained in:
Juan Font Alonso 2022-03-06 17:00:56 +01:00
parent dc909ba6d7
commit eb500155e8
4 changed files with 33 additions and 5 deletions

6
app.go
View file

@ -121,6 +121,8 @@ type OIDCConfig struct {
type DERPConfig struct { type DERPConfig struct {
ServerEnabled bool ServerEnabled bool
STUNEnabled bool
STUNAddr string
URLs []url.URL URLs []url.URL
Paths []string Paths []string
AutoUpdate bool AutoUpdate bool
@ -497,8 +499,10 @@ func (h *Headscale) Serve() error {
h.DERPMap = GetDERPMap(h.cfg.DERP) h.DERPMap = GetDERPMap(h.cfg.DERP)
if h.cfg.DERP.ServerEnabled { if h.cfg.DERP.ServerEnabled {
go h.ServeSTUN()
h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
if h.cfg.DERP.STUNEnabled {
go h.ServeSTUN()
}
} }
if h.cfg.DERP.AutoUpdate { if h.cfg.DERP.AutoUpdate {

View file

@ -118,6 +118,8 @@ func LoadConfig(path string) error {
func GetDERPConfig() headscale.DERPConfig { func GetDERPConfig() headscale.DERPConfig {
enabled := viper.GetBool("derp.server.enabled") enabled := viper.GetBool("derp.server.enabled")
stunEnabled := viper.GetBool("derp.server.stun.enabled")
stunAddr := viper.GetString("derp.server.stun.listen_addr")
urlStrs := viper.GetStringSlice("derp.urls") urlStrs := viper.GetStringSlice("derp.urls")
@ -141,6 +143,8 @@ func GetDERPConfig() headscale.DERPConfig {
return headscale.DERPConfig{ return headscale.DERPConfig{
ServerEnabled: enabled, ServerEnabled: enabled,
STUNEnabled: stunEnabled,
STUNAddr: stunAddr,
URLs: urls, URLs: urls,
Paths: paths, Paths: paths,
AutoUpdate: autoUpdate, AutoUpdate: autoUpdate,

View file

@ -60,6 +60,12 @@ derp:
# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
enabled: false enabled: false
# If enabled, also listens in the configured address for STUN connections to help on NAT traversal
# For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
stun:
enabled: false
listen_addr: "0.0.0.0:3478"
# List of externally available DERP maps encoded in JSON # List of externally available DERP maps encoded in JSON
urls: urls:
- https://controlplane.tailscale.com/derpmap/default - https://controlplane.tailscale.com/derpmap/default

View file

@ -75,6 +75,19 @@ func (h *Headscale) generateRegionLocalDERP() (tailcfg.DERPRegion, error) {
}, },
}, },
} }
if h.cfg.DERP.STUNEnabled {
_, portStr, err := net.SplitHostPort(h.cfg.DERP.STUNAddr)
if err != nil {
return tailcfg.DERPRegion{}, err
}
port, err := strconv.Atoi(portStr)
if err != nil {
return tailcfg.DERPRegion{}, err
}
localDERPregion.Nodes[0].STUNPort = port
}
return localDERPregion, nil return localDERPregion, nil
} }
@ -136,6 +149,7 @@ func (h *Headscale) DERPProbeHandler(ctx *gin.Context) {
// because its DNS are broken. // because its DNS are broken.
// The initial implementation is here https://github.com/tailscale/tailscale/pull/1406 // 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. // 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(ctx *gin.Context) { func (h *Headscale) DERPBootstrapDNSHandler(ctx *gin.Context) {
dnsEntries := make(map[string][]net.IP) dnsEntries := make(map[string][]net.IP)
@ -155,14 +169,14 @@ func (h *Headscale) DERPBootstrapDNSHandler(ctx *gin.Context) {
ctx.JSON(http.StatusOK, dnsEntries) ctx.JSON(http.StatusOK, dnsEntries)
} }
// ServeSTUN starts a STUN server on udp/3478 // ServeSTUN starts a STUN server on the configured addr
func (h *Headscale) ServeSTUN() { func (h *Headscale) ServeSTUN() {
pc, err := net.ListenPacket("udp", "0.0.0.0:3478") packetConn, err := net.ListenPacket("udp", h.cfg.DERP.STUNAddr)
if err != nil { if err != nil {
log.Fatal().Msgf("failed to open STUN listener: %v", err) log.Fatal().Msgf("failed to open STUN listener: %v", err)
} }
log.Trace().Msgf("STUN server started at %s", pc.LocalAddr()) log.Info().Msgf("STUN server started at %s", packetConn.LocalAddr())
serverSTUNListener(context.Background(), pc.(*net.UDPConn)) serverSTUNListener(context.Background(), packetConn.(*net.UDPConn))
} }
func serverSTUNListener(ctx context.Context, pc *net.UDPConn) { func serverSTUNListener(ctx context.Context, pc *net.UDPConn) {