diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 99cc36fa..37a8cb80 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -7,5 +7,5 @@ contact_links:
url: "https://github.com/juanfont/headscale/blob/main/docs"
about: "Find documentation about how to configure and run headscale."
- name: "headscale Discord community"
- url: "https://discord.com/invite/XcQxk2VHjx"
+ url: "https://discord.gg/xGj2TuqyxY"
about: "Please ask and answer questions about usage of headscale here."
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8999f7bf..140ea0b0 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,7 +18,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
- go-version: 1.17.7
+ go-version: 1.18.0
- name: Install dependencies
run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ce0c35b..359ace64 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,14 @@
# CHANGELOG
-## 0.15.0 (2022-xx-xx)
+## 0.16.0 (2022-xx-xx)
+
+### Changes
+
+- Headscale fails to serve if the ACL policy file cannot be parsed [#537](https://github.com/juanfont/headscale/pull/537)
+- Fix labels cardinality error when registering unknown pre-auth key [#519](https://github.com/juanfont/headscale/pull/519)
+- Fix send on closed channel crash in polling [#542](https://github.com/juanfont/headscale/pull/542)
+
+## 0.15.0 (2022-03-20)
**Note:** Take a backup of your database before upgrading.
@@ -19,7 +27,7 @@
- Users can now use emails in ACL's groups [#372](https://github.com/juanfont/headscale/issues/372)
- Add shorthand aliases for commands and subcommands [#376](https://github.com/juanfont/headscale/pull/376)
- Add `/windows` endpoint for Windows configuration instructions + registry file download [#392](https://github.com/juanfont/headscale/pull/392)
-- Added embedded DERP server into Headscale [#388](https://github.com/juanfont/headscale/pull/388)
+- Added embedded DERP (and STUN) server into Headscale [#388](https://github.com/juanfont/headscale/pull/388)
### Changes
@@ -29,6 +37,8 @@
- Fix a limitation in the ACLs that prevented users to write rules with `*` as source [#374](https://github.com/juanfont/headscale/issues/374)
- Reduce the overhead of marshal/unmarshal for Hostinfo, routes and endpoints by using specific types in Machine [#371](https://github.com/juanfont/headscale/pull/371)
- Apply normalization function to FQDN on hostnames when hosts registers and retrieve informations [#363](https://github.com/juanfont/headscale/issues/363)
+- Fix a bug that prevented the use of `tailscale logout` with OIDC [#508](https://github.com/juanfont/headscale/issues/508)
+- Added Tailscale repo HEAD and unstable releases channel to the integration tests targets [#513](https://github.com/juanfont/headscale/pull/513)
## 0.14.0 (2022-02-24)
diff --git a/Dockerfile b/Dockerfile
index 3ab9c1d1..8d53f6d9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Builder image
-FROM docker.io/golang:1.17.8-bullseye AS build
+FROM docker.io/golang:1.18.0-bullseye AS build
ENV GOPATH /go
WORKDIR /go/src/headscale
diff --git a/Dockerfile.alpine b/Dockerfile.alpine
index 1f0d6353..45fa171d 100644
--- a/Dockerfile.alpine
+++ b/Dockerfile.alpine
@@ -1,5 +1,5 @@
# Builder image
-FROM docker.io/golang:1.17.8-alpine AS build
+FROM docker.io/golang:1.18.0-alpine AS build
ENV GOPATH /go
WORKDIR /go/src/headscale
diff --git a/Dockerfile.debug b/Dockerfile.debug
index e73c0647..91fe2893 100644
--- a/Dockerfile.debug
+++ b/Dockerfile.debug
@@ -1,5 +1,5 @@
# Builder image
-FROM docker.io/golang:1.17.8-bullseye AS build
+FROM docker.io/golang:1.18.0-bullseye AS build
ENV GOPATH /go
WORKDIR /go/src/headscale
diff --git a/Dockerfile.tailscale b/Dockerfile.tailscale
index 32a8ce7b..145ab6f7 100644
--- a/Dockerfile.tailscale
+++ b/Dockerfile.tailscale
@@ -1,11 +1,12 @@
FROM ubuntu:latest
-ARG TAILSCALE_VERSION
+ARG TAILSCALE_VERSION=*
+ARG TAILSCALE_CHANNEL=stable
RUN apt-get update \
&& apt-get install -y gnupg curl \
- && curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/focal.gpg | apt-key add - \
- && curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/focal.list | tee /etc/apt/sources.list.d/tailscale.list \
+ && curl -fsSL https://pkgs.tailscale.com/${TAILSCALE_CHANNEL}/ubuntu/focal.gpg | apt-key add - \
+ && curl -fsSL https://pkgs.tailscale.com/${TAILSCALE_CHANNEL}/ubuntu/focal.list | tee /etc/apt/sources.list.d/tailscale.list \
&& apt-get update \
&& apt-get install -y ca-certificates tailscale=${TAILSCALE_VERSION} dnsutils \
&& rm -rf /var/lib/apt/lists/*
diff --git a/Dockerfile.tailscale-HEAD b/Dockerfile.tailscale-HEAD
new file mode 100644
index 00000000..b62f7e2b
--- /dev/null
+++ b/Dockerfile.tailscale-HEAD
@@ -0,0 +1,21 @@
+FROM golang:latest
+
+RUN apt-get update \
+ && apt-get install -y ca-certificates dnsutils git iptables \
+ && rm -rf /var/lib/apt/lists/*
+
+
+RUN git clone https://github.com/tailscale/tailscale.git
+
+WORKDIR tailscale
+
+RUN sh build_dist.sh tailscale.com/cmd/tailscale
+RUN sh build_dist.sh tailscale.com/cmd/tailscaled
+
+RUN cp tailscale /usr/local/bin/
+RUN cp tailscaled /usr/local/bin/
+
+ADD integration_test/etc_embedded_derp/tls/server.crt /usr/local/share/ca-certificates/
+RUN chmod 644 /usr/local/share/ca-certificates/server.crt
+
+RUN update-ca-certificates
diff --git a/Makefile b/Makefile
index 73630d3f..74ecd89e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
# Calculate version
-version = $(shell ./scripts/version-at-commit.sh)
+version = $(git describe --always --tags --dirty)
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
@@ -10,7 +10,7 @@ PROTO_SOURCES = $(call rwildcard,,*.proto)
build:
- GGO_ENABLED=0 go build -ldflags "-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$(version)" cmd/headscale/headscale.go
+ CGO_ENABLED=0 go build -trimpath -buildmode=pie -mod=readonly -ldflags "-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$(version)" cmd/headscale/headscale.go
dev: lint test build
diff --git a/README.md b/README.md
index 1901ce63..e05f8b7d 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
An open source, self-hosted implementation of the Tailscale control server.
-Join our [Discord](https://discord.gg/XcQxk2VHjx) server for a chat.
+Join our [Discord](https://discord.gg/c84AZQhmpx) server for a chat.
**Note:** Always select the same GitHub tag as the released version you use
to ensure you have the correct example configuration and documentation.
@@ -232,6 +232,13 @@ make build
Nico
+
+
+
+
+ Niek van der Maas
+
+ |
@@ -239,6 +246,8 @@ make build
Eugen Biegler
|
+
+
@@ -246,8 +255,6 @@ make build
Aaron Bieber
|
-
-
@@ -283,6 +290,15 @@ make build
Paul Tötterman
|
+
+
+
+
+
+
+ Artem Klevtsov
+
+ |
@@ -290,8 +306,6 @@ make build
Casey Marshall
|
-
-
@@ -320,6 +334,8 @@ make build
thomas
|
+
+
@@ -328,14 +344,12 @@ make build
|
-
-
+
+
- Artem Klevtsov
+ Aofei Sheng
|
-
-
@@ -350,6 +364,13 @@ make build
Bryan Stenson
|
+
+
+
+
+ Carson Yang
+
+ |
@@ -357,6 +378,8 @@ make build
Felix Kronlage-Dammers
|
+
+
@@ -378,8 +401,6 @@ make build
Jamie Greeff
|
-
-
@@ -401,6 +422,8 @@ make build
rcursaru
|
+
+
@@ -422,8 +445,6 @@ make build
Shaanan Cohney
|
-
-
@@ -445,6 +466,8 @@ make build
The Gitter Badger
|
+
+
@@ -466,8 +489,6 @@ make build
Yang Bin
|
-
-
@@ -489,6 +510,8 @@ make build
bravechamp
|
+
+
@@ -496,6 +519,13 @@ make build
derelm
|
+
+
+
+
+ henning mueller
+
+ |
@@ -510,8 +540,6 @@ make build
lion24
|
-
-
@@ -526,6 +554,8 @@ make build
Wakeful-Cloud
|
+
+
diff --git a/api.go b/api.go
index eab8076e..61ec1b5f 100644
--- a/api.go
+++ b/api.go
@@ -573,7 +573,7 @@ func (h *Headscale) handleAuthKey(
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
Inc()
} else {
- machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error").Inc()
+ machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", "unknown").Inc()
}
return
diff --git a/app.go b/app.go
index 1809f95c..b87fb33c 100644
--- a/app.go
+++ b/app.go
@@ -47,6 +47,14 @@ import (
"tailscale.com/types/key"
)
+const (
+ errSTUNAddressNotSet = Error("STUN address not set")
+ errUnsupportedDatabase = Error("unsupported DB")
+ errUnsupportedLetsEncryptChallengeType = Error(
+ "unknown value for Lets Encrypt challenge type",
+ )
+)
+
const (
AuthPrefix = "Bearer "
Postgres = "postgres"
@@ -58,11 +66,6 @@ const (
registerCacheExpiration = time.Minute * 15
registerCacheCleanup = time.Minute * 20
- errUnsupportedDatabase = Error("unsupported DB")
- errUnsupportedLetsEncryptChallengeType = Error(
- "unknown value for Lets Encrypt challenge type",
- )
-
DisabledClientAuth = "disabled"
RelaxedClientAuth = "relaxed"
EnforcedClientAuth = "enforced"
@@ -124,7 +127,6 @@ type DERPConfig struct {
ServerRegionID int
ServerRegionCode string
ServerRegionName string
- STUNEnabled bool
STUNAddr string
URLs []url.URL
Paths []string
@@ -500,10 +502,13 @@ func (h *Headscale) Serve() error {
h.DERPMap = GetDERPMap(h.cfg.DERP)
if h.cfg.DERP.ServerEnabled {
- h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
- if h.cfg.DERP.STUNEnabled {
- go h.ServeSTUN()
+ // When embedded DERP is enabled we always need a STUN server
+ if h.cfg.DERP.STUNAddr == "" {
+ return errSTUNAddressNotSet
}
+
+ h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
+ go h.ServeSTUN()
}
if h.cfg.DERP.AutoUpdate {
diff --git a/cmd/headscale/cli/api_key.go b/cmd/headscale/cli/api_key.go
index 06099aa1..aa056c54 100644
--- a/cmd/headscale/cli/api_key.go
+++ b/cmd/headscale/cli/api_key.go
@@ -23,7 +23,7 @@ func init() {
apiKeysCmd.AddCommand(listAPIKeys)
createAPIKeyCmd.Flags().
- DurationP("expiration", "e", DefaultAPIKeyExpiry, "Human-readable expiration of the key (30m, 24h, 365d...)")
+ DurationP("expiration", "e", DefaultAPIKeyExpiry, "Human-readable expiration of the key (e.g. 30m, 24h)")
apiKeysCmd.AddCommand(createAPIKeyCmd)
diff --git a/cmd/headscale/cli/preauthkeys.go b/cmd/headscale/cli/preauthkeys.go
index 950cbcc5..7efb72fb 100644
--- a/cmd/headscale/cli/preauthkeys.go
+++ b/cmd/headscale/cli/preauthkeys.go
@@ -31,7 +31,7 @@ func init() {
createPreAuthKeyCmd.PersistentFlags().
Bool("ephemeral", false, "Preauthkey for ephemeral nodes")
createPreAuthKeyCmd.Flags().
- DurationP("expiration", "e", DefaultPreAuthKeyExpiry, "Human-readable expiration of the key (30m, 24h, 365d...)")
+ DurationP("expiration", "e", DefaultPreAuthKeyExpiry, "Human-readable expiration of the key (e.g. 30m, 24h)")
}
var preauthkeysCmd = &cobra.Command{
diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go
index dc7a4e9f..992d1254 100644
--- a/cmd/headscale/cli/utils.go
+++ b/cmd/headscale/cli/utils.go
@@ -55,6 +55,9 @@ func LoadConfig(path string) error {
viper.SetDefault("dns_config", nil)
+ viper.SetDefault("derp.server.enabled", false)
+ viper.SetDefault("derp.server.stun.enabled", true)
+
viper.SetDefault("unix_socket", "/var/run/headscale.sock")
viper.SetDefault("unix_socket_permission", "0o770")
@@ -121,8 +124,11 @@ func GetDERPConfig() headscale.DERPConfig {
serverRegionID := viper.GetInt("derp.server.region_id")
serverRegionCode := viper.GetString("derp.server.region_code")
serverRegionName := viper.GetString("derp.server.region_name")
- stunEnabled := viper.GetBool("derp.server.stun.enabled")
- stunAddr := viper.GetString("derp.server.stun.listen_addr")
+ stunAddr := viper.GetString("derp.server.stun_listen_addr")
+
+ if serverEnabled && stunAddr == "" {
+ log.Fatal().Msg("derp.server.stun_listen_addr must be set if derp.server.enabled is true")
+ }
urlStrs := viper.GetStringSlice("derp.urls")
@@ -149,7 +155,6 @@ func GetDERPConfig() headscale.DERPConfig {
ServerRegionID: serverRegionID,
ServerRegionCode: serverRegionCode,
ServerRegionName: serverRegionName,
- STUNEnabled: stunEnabled,
STUNAddr: stunAddr,
URLs: urls,
Paths: paths,
@@ -403,7 +408,7 @@ func getHeadscaleApp() (*headscale.Headscale, error) {
aclPath := absPath(viper.GetString("acl_policy_path"))
err = app.LoadACLPolicy(aclPath)
if err != nil {
- log.Error().
+ log.Fatal().
Str("path", aclPath).
Err(err).
Msg("Could not load the ACL policy")
diff --git a/config-example.yaml b/config-example.yaml
index 2075e69a..dee25cb3 100644
--- a/config-example.yaml
+++ b/config-example.yaml
@@ -69,11 +69,11 @@ derp:
region_code: "headscale"
region_name: "Headscale Embedded DERP"
- # If enabled, also listens in UDP at the configured address for STUN connections to help on NAT traversal
+ # Listens in UDP at the configured address for STUN connections to help on NAT traversal.
+ # When the embedded DERP server is enabled stun_listen_addr MUST be defined.
+ #
# 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"
+ stun_listen_addr: "0.0.0.0:3478"
# List of externally available DERP maps encoded in JSON
urls:
diff --git a/derp-example.yaml b/derp-example.yaml
index 0ebe32ed..732c4ba0 100644
--- a/derp-example.yaml
+++ b/derp-example.yaml
@@ -12,4 +12,4 @@ regions:
ipv6: "2604:a880:400:d1::828:b001"
stunport: 0
stunonly: false
- derptestport: 0
+ derpport: 0
diff --git a/derp.go b/derp.go
index 7a9b2367..7abce683 100644
--- a/derp.go
+++ b/derp.go
@@ -148,7 +148,9 @@ func (h *Headscale) scheduledDERPMapUpdateWorker(cancelChan <-chan struct{}) {
case <-ticker.C:
log.Info().Msg("Fetching DERPMap updates")
h.DERPMap = GetDERPMap(h.cfg.DERP)
- h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
+ if h.cfg.DERP.ServerEnabled {
+ h.DERPMap.Regions[h.DERPServer.region.RegionID] = &h.DERPServer.region
+ }
namespaces, err := h.ListNamespaces()
if err != nil {
diff --git a/derp_server.go b/derp_server.go
index 11e3eb14..6580419e 100644
--- a/derp_server.go
+++ b/derp_server.go
@@ -77,17 +77,15 @@ 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
+ _, portSTUNStr, err := net.SplitHostPort(h.cfg.DERP.STUNAddr)
+ if err != nil {
+ return tailcfg.DERPRegion{}, err
}
+ portSTUN, err := strconv.Atoi(portSTUNStr)
+ if err != nil {
+ return tailcfg.DERPRegion{}, err
+ }
+ localDERPregion.Nodes[0].STUNPort = portSTUN
return localDERPregion, nil
}
diff --git a/docs/README.md b/docs/README.md
index 7a3080e3..459a6c21 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -3,7 +3,7 @@
This page contains the official and community contributed documentation for `headscale`.
If you are having trouble with following the documentation or get unexpected results,
-please ask on [Discord](https://discord.gg/XcQxk2VHjx) instead of opening an Issue.
+please ask on [Discord](https://discord.gg/c84AZQhmpx) instead of opening an Issue.
## Official documentation
diff --git a/docs/running-headscale-container.md b/docs/running-headscale-container.md
index 36e63de9..b36f3bbf 100644
--- a/docs/running-headscale-container.md
+++ b/docs/running-headscale-container.md
@@ -14,8 +14,8 @@ not work with alternatives like [Podman](https://podman.io). The Docker image ca
1. Prepare a directory on the host Docker node in your directory of choice, used to hold `headscale` configuration and the [SQLite](https://www.sqlite.org/) database:
```shell
-mkdir ./headscale && cd ./headscale
-mkdir ./config
+mkdir -p ./headscale/config
+cd ./headscale
```
2. Create an empty SQlite datebase in the headscale directory:
@@ -45,6 +45,17 @@ touch ./config/config.yaml
```
Modify the config file to your preferences before launching Docker container.
+Here are some settings that you likely want:
+
+```yaml
+server_url: http://your-host-name:8080 # Change to your hostname or host IP
+# Listen to 0.0.0.0 so it's accessible outside the container
+metrics_listen_addr: 0.0.0.0:9090
+# The default /var/lib/headscale path is not writable in the container
+private_key_path: /etc/headscale/private.key
+# The default /var/lib/headscale path is not writable in the container
+db_path: /etc/headscale/db.sqlite
+```
4. Start the headscale server while working in the host headscale directory:
@@ -61,6 +72,8 @@ docker run \
```
+Note: use `0.0.0.0:8080:8080` instead of `127.0.0.1:8080:8080` if you want to expose the container externally.
+
This command will mount `config/` under `/etc/headscale`, forward port 8080 out of the container so the
`headscale` instance becomes available and then detach so headscale runs in the background.
@@ -87,7 +100,8 @@ curl http://127.0.0.1:9090/metrics
6. Create a namespace ([tailnet](https://tailscale.com/kb/1136/tailnet/)):
```shell
-docker exec headscale -- headscale namespaces create myfirstnamespace
+docker exec headscale \
+ headscale namespaces create myfirstnamespace
```
### Register a machine (normal login)
@@ -101,7 +115,7 @@ tailscale up --login-server YOUR_HEADSCALE_URL
To register a machine when running `headscale` in a container, take the headscale command and pass it to the container:
```shell
-docker exec headscale -- \
+docker exec headscale \
headscale --namespace myfirstnamespace nodes register --key
```
@@ -110,7 +124,7 @@ docker exec headscale -- \
Generate a key using the command line:
```shell
-docker exec headscale -- \
+docker exec headscale \
headscale --namespace myfirstnamespace preauthkeys create --reusable --expiration 24h
```
diff --git a/docs/running-headscale-linux.md b/docs/running-headscale-linux.md
index 1e9d11c4..98a67f1d 100644
--- a/docs/running-headscale-linux.md
+++ b/docs/running-headscale-linux.md
@@ -178,7 +178,7 @@ systemctl status headscale
Verify `headscale` is available:
```shell
-curl http://127.0.0.1:8080/metrics
+curl http://127.0.0.1:9090/metrics
```
`headscale` will now run in the background and start at boot.
diff --git a/go.mod b/go.mod
index 454ffd19..654d631d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/juanfont/headscale
-go 1.17
+go 1.18
require (
github.com/AlecAivazis/survey/v2 v2.3.2
diff --git a/integration_cli_test.go b/integration_cli_test.go
index 7ce0758f..9644037d 100644
--- a/integration_cli_test.go
+++ b/integration_cli_test.go
@@ -72,7 +72,7 @@ func (s *IntegrationCLITestSuite) SetupTest() {
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale
} else {
- log.Fatalf("Could not start resource: %s", err)
+ log.Fatalf("Could not start headscale container: %s", err)
}
fmt.Println("Created headscale container")
diff --git a/integration_common_test.go b/integration_common_test.go
index 70285fc4..f7afb807 100644
--- a/integration_common_test.go
+++ b/integration_common_test.go
@@ -20,7 +20,7 @@ var (
IpPrefix4 = netaddr.MustParseIPPrefix("100.64.0.0/10")
IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48")
- tailscaleVersions = []string{"1.22.0", "1.20.4", "1.18.2", "1.16.2", "1.14.3", "1.12.3"}
+ tailscaleVersions = []string{"head", "unstable", "1.22.2", "1.20.4", "1.18.2", "1.16.2", "1.14.3", "1.12.3"}
)
type TestNamespace struct {
@@ -128,6 +128,49 @@ func DockerAllowNetworkAdministration(config *docker.HostConfig) {
})
}
+func getDockerBuildOptions(version string) *dockertest.BuildOptions {
+ var tailscaleBuildOptions *dockertest.BuildOptions
+ switch version {
+ case "head":
+ tailscaleBuildOptions = &dockertest.BuildOptions{
+ Dockerfile: "Dockerfile.tailscale-HEAD",
+ ContextDir: ".",
+ BuildArgs: []docker.BuildArg{},
+ }
+ case "unstable":
+ tailscaleBuildOptions = &dockertest.BuildOptions{
+ Dockerfile: "Dockerfile.tailscale",
+ ContextDir: ".",
+ BuildArgs: []docker.BuildArg{
+ {
+ Name: "TAILSCALE_VERSION",
+ Value: "*", // Installs the latest version https://askubuntu.com/a/824926
+ },
+ {
+ Name: "TAILSCALE_CHANNEL",
+ Value: "unstable",
+ },
+ },
+ }
+ default:
+ tailscaleBuildOptions = &dockertest.BuildOptions{
+ Dockerfile: "Dockerfile.tailscale",
+ ContextDir: ".",
+ BuildArgs: []docker.BuildArg{
+ {
+ Name: "TAILSCALE_VERSION",
+ Value: version,
+ },
+ {
+ Name: "TAILSCALE_CHANNEL",
+ Value: "stable",
+ },
+ },
+ }
+ }
+ return tailscaleBuildOptions
+}
+
func getIPs(
tailscales map[string]dockertest.Resource,
) (map[string][]netaddr.IP, error) {
diff --git a/integration_embedded_derp_test.go b/integration_embedded_derp_test.go
index a1737173..54eec804 100644
--- a/integration_embedded_derp_test.go
+++ b/integration_embedded_derp_test.go
@@ -121,7 +121,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale
} else {
- log.Fatalf("Could not start resource: %s", err)
+ log.Fatalf("Could not start headscale container: %s", err)
}
log.Println("Created headscale container to test DERP")
@@ -245,16 +245,8 @@ func (s *IntegrationDERPTestSuite) Join(
func (s *IntegrationDERPTestSuite) tailscaleContainer(identifier, version string, network dockertest.Network,
) (string, *dockertest.Resource) {
- tailscaleBuildOptions := &dockertest.BuildOptions{
- Dockerfile: "Dockerfile.tailscale",
- ContextDir: ".",
- BuildArgs: []docker.BuildArg{
- {
- Name: "TAILSCALE_VERSION",
- Value: version,
- },
- },
- }
+ tailscaleBuildOptions := getDockerBuildOptions(version)
+
hostname := fmt.Sprintf(
"tailscale-%s-%s",
strings.Replace(version, ".", "-", -1),
@@ -279,7 +271,7 @@ func (s *IntegrationDERPTestSuite) tailscaleContainer(identifier, version string
DockerAllowNetworkAdministration,
)
if err != nil {
- log.Fatalf("Could not start resource: %s", err)
+ log.Fatalf("Could not start tailscale container version %s: %s", version, err)
}
log.Printf("Created %s container\n", hostname)
diff --git a/integration_test.go b/integration_test.go
index 1649f322..52f1765b 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -168,16 +168,8 @@ func (s *IntegrationTestSuite) Join(
func (s *IntegrationTestSuite) tailscaleContainer(
namespace, identifier, version string,
) (string, *dockertest.Resource) {
- tailscaleBuildOptions := &dockertest.BuildOptions{
- Dockerfile: "Dockerfile.tailscale",
- ContextDir: ".",
- BuildArgs: []docker.BuildArg{
- {
- Name: "TAILSCALE_VERSION",
- Value: version,
- },
- },
- }
+ tailscaleBuildOptions := getDockerBuildOptions(version)
+
hostname := fmt.Sprintf(
"%s-tailscale-%s-%s",
namespace,
@@ -200,7 +192,7 @@ func (s *IntegrationTestSuite) tailscaleContainer(
DockerAllowNetworkAdministration,
)
if err != nil {
- log.Fatalf("Could not start resource: %s", err)
+ log.Fatalf("Could not start tailscale container version %s: %s", version, err)
}
log.Printf("Created %s container\n", hostname)
@@ -249,7 +241,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale
} else {
- log.Fatalf("Could not start resource: %s", err)
+ log.Fatalf("Could not start headscale container: %s", err)
}
log.Println("Created headscale container")
diff --git a/integration_test/etc_embedded_derp/config.yaml b/integration_test/etc_embedded_derp/config.yaml
index 1531d347..a8b57af5 100644
--- a/integration_test/etc_embedded_derp/config.yaml
+++ b/integration_test/etc_embedded_derp/config.yaml
@@ -24,6 +24,5 @@ derp:
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
- stun:
- enabled: true
- listen_addr: "0.0.0.0:3478"
+
+ stun_listen_addr: "0.0.0.0:3478"
diff --git a/oidc.go b/oidc.go
index 29ce351f..598a208d 100644
--- a/oidc.go
+++ b/oidc.go
@@ -10,6 +10,7 @@ import (
"html/template"
"net/http"
"strings"
+ "time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-gonic/gin"
@@ -129,6 +130,10 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) {
oauth2Token, err := h.oauth2Config.Exchange(context.Background(), code)
if err != nil {
+ log.Error().
+ Err(err).
+ Caller().
+ Msg("Could not exchange code for token")
ctx.String(http.StatusBadRequest, "Could not exchange code for token")
return
@@ -229,7 +234,7 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) {
Str("machine", machine.Name).
Msg("machine already registered, reauthenticating")
- h.RefreshMachine(machine, *machine.Expiry)
+ h.RefreshMachine(machine, time.Time{})
var content bytes.Buffer
if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{
diff --git a/poll.go b/poll.go
index 15945a9b..3bad0b89 100644
--- a/poll.go
+++ b/poll.go
@@ -175,32 +175,13 @@ func (h *Headscale) PollNetMapHandler(ctx *gin.Context) {
Str("machine", machine.Name).
Msg("Loading or creating update channel")
- // TODO: could probably remove all that duplication once generics land.
- closeChanWithLog := func(channel interface{}, name string) {
- log.Trace().
- Str("handler", "PollNetMap").
- Str("machine", machine.Name).
- Str("channel", "Done").
- Msg(fmt.Sprintf("Closing %s channel", name))
-
- switch c := channel.(type) {
- case (chan struct{}):
- close(c)
-
- case (chan []byte):
- close(c)
- }
- }
-
const chanSize = 8
updateChan := make(chan struct{}, chanSize)
- defer closeChanWithLog(updateChan, "updateChan")
pollDataChan := make(chan []byte, chanSize)
- defer closeChanWithLog(pollDataChan, "pollDataChan")
+ defer closeChanWithLog(pollDataChan, machine.Name, "pollDataChan")
keepAliveChan := make(chan []byte)
- defer closeChanWithLog(keepAliveChan, "keepAliveChan")
if req.OmitPeers && !req.Stream {
log.Info().
@@ -273,7 +254,27 @@ func (h *Headscale) PollNetMapStream(
updateChan chan struct{},
) {
{
- ctx, cancel := context.WithCancel(ctx.Request.Context())
+ machine, err := h.GetMachineByMachineKey(machineKey)
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ log.Warn().
+ Str("handler", "PollNetMap").
+ Msgf("Ignoring request, cannot find machine with key %s", machineKey.String())
+ ctx.String(http.StatusUnauthorized, "")
+
+ return
+ }
+ log.Error().
+ Str("handler", "PollNetMap").
+ Msgf("Failed to fetch machine from the database with Machine key: %s", machineKey.String())
+ ctx.String(http.StatusInternalServerError, "")
+
+ return
+ }
+
+ ctx := context.WithValue(ctx.Request.Context(), "machineName", machine.Name)
+
+ ctx, cancel := context.WithCancel(ctx)
defer cancel()
go h.scheduledPollWorker(
@@ -564,8 +565,8 @@ func (h *Headscale) PollNetMapStream(
func (h *Headscale) scheduledPollWorker(
ctx context.Context,
- updateChan chan<- struct{},
- keepAliveChan chan<- []byte,
+ updateChan chan struct{},
+ keepAliveChan chan []byte,
machineKey key.MachinePublic,
mapRequest tailcfg.MapRequest,
machine *Machine,
@@ -573,6 +574,17 @@ func (h *Headscale) scheduledPollWorker(
keepAliveTicker := time.NewTicker(keepAliveInterval)
updateCheckerTicker := time.NewTicker(updateCheckInterval)
+ defer closeChanWithLog(
+ updateChan,
+ fmt.Sprint(ctx.Value("machineName")),
+ "updateChan",
+ )
+ defer closeChanWithLog(
+ keepAliveChan,
+ fmt.Sprint(ctx.Value("machineName")),
+ "updateChan",
+ )
+
for {
select {
case <-ctx.Done():
@@ -606,3 +618,13 @@ func (h *Headscale) scheduledPollWorker(
}
}
}
+
+func closeChanWithLog[C chan []byte | chan struct{}](channel C, machine, name string) {
+ log.Trace().
+ Str("handler", "PollNetMap").
+ Str("machine", machine).
+ Str("channel", "Done").
+ Msg(fmt.Sprintf("Closing %s channel", name))
+
+ close(channel)
+}
diff --git a/scripts/version-at-commit.sh b/scripts/version-at-commit.sh
deleted file mode 100755
index 2f7fab84..00000000
--- a/scripts/version-at-commit.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -o pipefail
-commit="$1"
-versionglob="v[0-9].[0-9]*.[0-9]*"
-devsuffix=".dev"
-if [ -z "$commit" ]; then
- commit=`git log -n1 --first-parent "--format=format:%h"`
-fi
-
-# automatically assign version
-#
-# handles the following cases:
-#
-# 0. no tags on the repository. Print "dev".
-#
-# 1. no local modifications and commit is directly tagged. Print tag.
-#
-# 2. no local modifications and commit is not tagged. Take greatest version tag in repo X.Y.Z and assign X.Y.(Z+1). Print that + $devsuffix + $timestamp.
-#
-# 3. local modifications. Print "dev".
-
-tags=$(git tag)
-if [[ -z "$tags" ]]; then
- echo "dev"
-elif `git diff --quiet 2>/dev/null`; then
- tagged=$(git tag --points-at "$commit")
- if [[ -n "$tagged" ]] ; then
- echo $tagged
- else
- nearest_tag=$(git describe --tags --abbrev=0 --match "$versionglob" "$commit")
- v=$(echo $nearest_tag | perl -pe 's/(\d+)$/$1+1/e')
- isodate=$(TZ=UTC git log -n1 --format=%cd --date=iso "$commit")
- ts=$(TZ=UTC date --date="$isodate" "+%Y%m%d%H%M%S")
- echo "${v}${devsuffix}${ts}"
- fi
-else
- echo "dev"
-fi
|