mirror of
https://github.com/juanfont/headscale.git
synced 2025-08-20 08:47:27 +00:00
Compare commits
20 Commits
remove-fun
...
v0.17.0-al
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cdc8bab7d9 | ||
![]() |
397754753f | ||
![]() |
42ef71bff9 | ||
![]() |
f2da1a1665 | ||
![]() |
356b76fc56 | ||
![]() |
33ae56acfa | ||
![]() |
9923adcb8b | ||
![]() |
874d6aaf6b | ||
![]() |
ae4f2cc4b5 | ||
![]() |
dd155dca97 | ||
![]() |
a0a463494b | ||
![]() |
07dca79b20 | ||
![]() |
7247302f45 | ||
![]() |
1a5a5b12b7 | ||
![]() |
0099dd1724 | ||
![]() |
1f131c6729 | ||
![]() |
302a88bfdb | ||
![]() |
a9ede6a2bc | ||
![]() |
bb6b07dedc | ||
![]() |
2403c0e198 |
@@ -2,11 +2,19 @@
|
|||||||
|
|
||||||
## 0.17.0 (2022-XX-XX)
|
## 0.17.0 (2022-XX-XX)
|
||||||
|
|
||||||
|
### BREAKING
|
||||||
|
|
||||||
|
- Log level option `log_level` was moved to a distinct `log` config section and renamed to `level` [#768](https://github.com/juanfont/headscale/pull/768)
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
- Added support for Tailscale TS2021 protocol [#738](https://github.com/juanfont/headscale/pull/738)
|
- Added support for Tailscale TS2021 protocol [#738](https://github.com/juanfont/headscale/pull/738)
|
||||||
- Add ability to specify config location via env var `HEADSCALE_CONFIG` [#674](https://github.com/juanfont/headscale/issues/674)
|
- Add ability to specify config location via env var `HEADSCALE_CONFIG` [#674](https://github.com/juanfont/headscale/issues/674)
|
||||||
- Target Go 1.19 for Headscale [#778](https://github.com/juanfont/headscale/pull/778)
|
- Target Go 1.19 for Headscale [#778](https://github.com/juanfont/headscale/pull/778)
|
||||||
- Target Tailscale v1.30.0 to build Headscale [#780](https://github.com/juanfont/headscale/pull/780)
|
- Target Tailscale v1.30.0 to build Headscale [#780](https://github.com/juanfont/headscale/pull/780)
|
||||||
- Give a warning when running Headscale with reverse proxy improperly configured for WebSockets [#788](https://github.com/juanfont/headscale/pull/788)
|
- Give a warning when running Headscale with reverse proxy improperly configured for WebSockets [#788](https://github.com/juanfont/headscale/pull/788)
|
||||||
|
- Fix subnet routers with Primary Routes [#811](https://github.com/juanfont/headscale/pull/811)
|
||||||
|
- Added support for JSON logs [#653](https://github.com/juanfont/headscale/issues/653)
|
||||||
|
|
||||||
## 0.16.4 (2022-08-21)
|
## 0.16.4 (2022-08-21)
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ func initConfig() {
|
|||||||
|
|
||||||
machineOutput := HasMachineOutputFlag()
|
machineOutput := HasMachineOutputFlag()
|
||||||
|
|
||||||
zerolog.SetGlobalLevel(cfg.LogLevel)
|
zerolog.SetGlobalLevel(cfg.Log.Level)
|
||||||
|
|
||||||
// If the user has requested a "machine" readable format,
|
// If the user has requested a "machine" readable format,
|
||||||
// then disable login so the output remains valid.
|
// then disable login so the output remains valid.
|
||||||
@@ -55,6 +55,10 @@ func initConfig() {
|
|||||||
zerolog.SetGlobalLevel(zerolog.Disabled)
|
zerolog.SetGlobalLevel(zerolog.Disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Log.Format == headscale.JSONLogFormat {
|
||||||
|
log.Logger = log.Output(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
if !cfg.DisableUpdateCheck && !machineOutput {
|
if !cfg.DisableUpdateCheck && !machineOutput {
|
||||||
if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
|
if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
|
||||||
Version != "dev" {
|
Version != "dev" {
|
||||||
|
@@ -172,7 +172,10 @@ tls_letsencrypt_listen: ":http"
|
|||||||
tls_cert_path: ""
|
tls_cert_path: ""
|
||||||
tls_key_path: ""
|
tls_key_path: ""
|
||||||
|
|
||||||
log_level: info
|
log:
|
||||||
|
# Output formatting for logs: text or json
|
||||||
|
format: text
|
||||||
|
level: info
|
||||||
|
|
||||||
# Path to a file containg ACL policies.
|
# Path to a file containg ACL policies.
|
||||||
# ACLs can be defined as YAML or HUJSON.
|
# ACLs can be defined as YAML or HUJSON.
|
||||||
|
50
config.go
50
config.go
@@ -22,6 +22,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
tlsALPN01ChallengeType = "TLS-ALPN-01"
|
tlsALPN01ChallengeType = "TLS-ALPN-01"
|
||||||
http01ChallengeType = "HTTP-01"
|
http01ChallengeType = "HTTP-01"
|
||||||
|
|
||||||
|
JSONLogFormat = "json"
|
||||||
|
TextLogFormat = "text"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the initial Headscale configuration.
|
// Config contains the initial Headscale configuration.
|
||||||
@@ -37,7 +40,7 @@ type Config struct {
|
|||||||
PrivateKeyPath string
|
PrivateKeyPath string
|
||||||
NoisePrivateKeyPath string
|
NoisePrivateKeyPath string
|
||||||
BaseDomain string
|
BaseDomain string
|
||||||
LogLevel zerolog.Level
|
Log LogConfig
|
||||||
DisableUpdateCheck bool
|
DisableUpdateCheck bool
|
||||||
|
|
||||||
DERP DERPConfig
|
DERP DERPConfig
|
||||||
@@ -124,6 +127,11 @@ type ACLConfig struct {
|
|||||||
PolicyPath string
|
PolicyPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogConfig struct {
|
||||||
|
Format string
|
||||||
|
Level zerolog.Level
|
||||||
|
}
|
||||||
|
|
||||||
func LoadConfig(path string, isFile bool) error {
|
func LoadConfig(path string, isFile bool) error {
|
||||||
if isFile {
|
if isFile {
|
||||||
viper.SetConfigFile(path)
|
viper.SetConfigFile(path)
|
||||||
@@ -147,7 +155,8 @@ func LoadConfig(path string, isFile bool) error {
|
|||||||
viper.SetDefault("tls_letsencrypt_challenge_type", http01ChallengeType)
|
viper.SetDefault("tls_letsencrypt_challenge_type", http01ChallengeType)
|
||||||
viper.SetDefault("tls_client_auth_mode", "relaxed")
|
viper.SetDefault("tls_client_auth_mode", "relaxed")
|
||||||
|
|
||||||
viper.SetDefault("log_level", "info")
|
viper.SetDefault("log.level", "info")
|
||||||
|
viper.SetDefault("log.format", TextLogFormat)
|
||||||
|
|
||||||
viper.SetDefault("dns_config", nil)
|
viper.SetDefault("dns_config", nil)
|
||||||
|
|
||||||
@@ -334,6 +343,34 @@ func GetACLConfig() ACLConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLogConfig() LogConfig {
|
||||||
|
logLevelStr := viper.GetString("log.level")
|
||||||
|
logLevel, err := zerolog.ParseLevel(logLevelStr)
|
||||||
|
if err != nil {
|
||||||
|
logLevel = zerolog.DebugLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
logFormatOpt := viper.GetString("log.format")
|
||||||
|
var logFormat string
|
||||||
|
switch logFormatOpt {
|
||||||
|
case "json":
|
||||||
|
logFormat = JSONLogFormat
|
||||||
|
case "text":
|
||||||
|
logFormat = TextLogFormat
|
||||||
|
case "":
|
||||||
|
logFormat = TextLogFormat
|
||||||
|
default:
|
||||||
|
log.Error().
|
||||||
|
Str("func", "GetLogConfig").
|
||||||
|
Msgf("Could not parse log format: %s. Valid choices are 'json' or 'text'", logFormatOpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LogConfig{
|
||||||
|
Format: logFormat,
|
||||||
|
Level: logLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetDNSConfig() (*tailcfg.DNSConfig, string) {
|
func GetDNSConfig() (*tailcfg.DNSConfig, string) {
|
||||||
if viper.IsSet("dns_config") {
|
if viper.IsSet("dns_config") {
|
||||||
dnsConfig := &tailcfg.DNSConfig{}
|
dnsConfig := &tailcfg.DNSConfig{}
|
||||||
@@ -430,12 +467,6 @@ func GetHeadscaleConfig() (*Config, error) {
|
|||||||
configuredPrefixes := viper.GetStringSlice("ip_prefixes")
|
configuredPrefixes := viper.GetStringSlice("ip_prefixes")
|
||||||
parsedPrefixes := make([]netip.Prefix, 0, len(configuredPrefixes)+1)
|
parsedPrefixes := make([]netip.Prefix, 0, len(configuredPrefixes)+1)
|
||||||
|
|
||||||
logLevelStr := viper.GetString("log_level")
|
|
||||||
logLevel, err := zerolog.ParseLevel(logLevelStr)
|
|
||||||
if err != nil {
|
|
||||||
logLevel = zerolog.DebugLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
legacyPrefixField := viper.GetString("ip_prefix")
|
legacyPrefixField := viper.GetString("ip_prefix")
|
||||||
if len(legacyPrefixField) > 0 {
|
if len(legacyPrefixField) > 0 {
|
||||||
log.
|
log.
|
||||||
@@ -488,7 +519,6 @@ func GetHeadscaleConfig() (*Config, error) {
|
|||||||
GRPCAddr: viper.GetString("grpc_listen_addr"),
|
GRPCAddr: viper.GetString("grpc_listen_addr"),
|
||||||
GRPCAllowInsecure: viper.GetBool("grpc_allow_insecure"),
|
GRPCAllowInsecure: viper.GetBool("grpc_allow_insecure"),
|
||||||
DisableUpdateCheck: viper.GetBool("disable_check_updates"),
|
DisableUpdateCheck: viper.GetBool("disable_check_updates"),
|
||||||
LogLevel: logLevel,
|
|
||||||
|
|
||||||
IPPrefixes: prefixes,
|
IPPrefixes: prefixes,
|
||||||
PrivateKeyPath: AbsolutePathFromConfigPath(
|
PrivateKeyPath: AbsolutePathFromConfigPath(
|
||||||
@@ -550,5 +580,7 @@ func GetHeadscaleConfig() (*Config, error) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ACL: GetACLConfig(),
|
ACL: GetACLConfig(),
|
||||||
|
|
||||||
|
Log: GetLogConfig(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@@ -66,7 +66,6 @@ db_path: /etc/headscale/db.sqlite
|
|||||||
docker run \
|
docker run \
|
||||||
--name headscale \
|
--name headscale \
|
||||||
--detach \
|
--detach \
|
||||||
--rm \
|
|
||||||
--volume $(pwd)/config:/etc/headscale/ \
|
--volume $(pwd)/config:/etc/headscale/ \
|
||||||
--publish 127.0.0.1:8080:8080 \
|
--publish 127.0.0.1:8080:8080 \
|
||||||
--publish 127.0.0.1:9090:9090 \
|
--publish 127.0.0.1:9090:9090 \
|
||||||
|
@@ -28,7 +28,9 @@ ip_prefixes:
|
|||||||
- fd7a:115c:a1e0::/48
|
- fd7a:115c:a1e0::/48
|
||||||
- 100.64.0.0/10
|
- 100.64.0.0/10
|
||||||
listen_addr: 0.0.0.0:18080
|
listen_addr: 0.0.0.0:18080
|
||||||
log_level: disabled
|
log:
|
||||||
|
level: disabled
|
||||||
|
format: text
|
||||||
logtail:
|
logtail:
|
||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:19090
|
metrics_listen_addr: 127.0.0.1:19090
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
log_level: trace
|
log:
|
||||||
|
level: trace
|
||||||
acl_policy_path: ""
|
acl_policy_path: ""
|
||||||
db_type: sqlite3
|
db_type: sqlite3
|
||||||
ephemeral_node_inactivity_timeout: 30m
|
ephemeral_node_inactivity_timeout: 30m
|
||||||
|
@@ -27,7 +27,9 @@ ip_prefixes:
|
|||||||
- fd7a:115c:a1e0::/48
|
- fd7a:115c:a1e0::/48
|
||||||
- 100.64.0.0/10
|
- 100.64.0.0/10
|
||||||
listen_addr: 0.0.0.0:18080
|
listen_addr: 0.0.0.0:18080
|
||||||
log_level: disabled
|
log:
|
||||||
|
level: disabled
|
||||||
|
format: text
|
||||||
logtail:
|
logtail:
|
||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:19090
|
metrics_listen_addr: 127.0.0.1:19090
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
log_level: trace
|
log:
|
||||||
|
level: trace
|
||||||
acl_policy_path: ""
|
acl_policy_path: ""
|
||||||
db_type: sqlite3
|
db_type: sqlite3
|
||||||
ephemeral_node_inactivity_timeout: 30m
|
ephemeral_node_inactivity_timeout: 30m
|
||||||
|
@@ -28,7 +28,9 @@ ip_prefixes:
|
|||||||
- fd7a:115c:a1e0::/48
|
- fd7a:115c:a1e0::/48
|
||||||
- 100.64.0.0/10
|
- 100.64.0.0/10
|
||||||
listen_addr: 0.0.0.0:8080
|
listen_addr: 0.0.0.0:8080
|
||||||
log_level: disabled
|
log:
|
||||||
|
format: text
|
||||||
|
level: disabled
|
||||||
logtail:
|
logtail:
|
||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:9090
|
metrics_listen_addr: 127.0.0.1:9090
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
log_level: trace
|
log:
|
||||||
|
level: trace
|
||||||
acl_policy_path: ""
|
acl_policy_path: ""
|
||||||
db_type: sqlite3
|
db_type: sqlite3
|
||||||
ephemeral_node_inactivity_timeout: 30m
|
ephemeral_node_inactivity_timeout: 30m
|
||||||
|
57
machine.go
57
machine.go
@@ -26,15 +26,22 @@ const (
|
|||||||
)
|
)
|
||||||
ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface")
|
ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface")
|
||||||
ErrHostnameTooLong = Error("Hostname too long")
|
ErrHostnameTooLong = Error("Hostname too long")
|
||||||
ErrDifferentRegisteredNamespace = Error("machine was previously registered with a different namespace")
|
ErrDifferentRegisteredNamespace = Error(
|
||||||
MachineGivenNameHashLength = 8
|
"machine was previously registered with a different namespace",
|
||||||
MachineGivenNameTrimSize = 2
|
)
|
||||||
|
MachineGivenNameHashLength = 8
|
||||||
|
MachineGivenNameTrimSize = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxHostnameLength = 255
|
maxHostnameLength = 255
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ExitRouteV4 = netip.MustParsePrefix("0.0.0.0/0")
|
||||||
|
ExitRouteV6 = netip.MustParsePrefix("::/0")
|
||||||
|
)
|
||||||
|
|
||||||
// Machine is a Headscale client.
|
// Machine is a Headscale client.
|
||||||
type Machine struct {
|
type Machine struct {
|
||||||
ID uint64 `gorm:"primary_key"`
|
ID uint64 `gorm:"primary_key"`
|
||||||
@@ -633,10 +640,22 @@ func (machine Machine) toNode(
|
|||||||
[]netip.Prefix{},
|
[]netip.Prefix{},
|
||||||
addrs...) // we append the node own IP, as it is required by the clients
|
addrs...) // we append the node own IP, as it is required by the clients
|
||||||
|
|
||||||
// TODO(kradalby): Needs investigation, We probably dont need this condition
|
allowedIPs = append(allowedIPs, machine.EnabledRoutes...)
|
||||||
// now that we dont have shared nodes
|
|
||||||
if includeRoutes {
|
// TODO(kradalby): This is kind of a hack where we say that
|
||||||
allowedIPs = append(allowedIPs, machine.EnabledRoutes...)
|
// all the announced routes (except exit), is presented as primary
|
||||||
|
// routes. This might be problematic if two nodes expose the same route.
|
||||||
|
// This was added to address an issue where subnet routers stopped working
|
||||||
|
// when we only populated AllowedIPs.
|
||||||
|
primaryRoutes := []netip.Prefix{}
|
||||||
|
if len(machine.EnabledRoutes) > 0 {
|
||||||
|
for _, route := range machine.EnabledRoutes {
|
||||||
|
if route == ExitRouteV4 || route == ExitRouteV6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
primaryRoutes = append(primaryRoutes, route)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var derp string
|
var derp string
|
||||||
@@ -683,16 +702,17 @@ func (machine Machine) toNode(
|
|||||||
StableID: tailcfg.StableNodeID(
|
StableID: tailcfg.StableNodeID(
|
||||||
strconv.FormatUint(machine.ID, Base10),
|
strconv.FormatUint(machine.ID, Base10),
|
||||||
), // in headscale, unlike tailcontrol server, IDs are permanent
|
), // in headscale, unlike tailcontrol server, IDs are permanent
|
||||||
Name: hostname,
|
Name: hostname,
|
||||||
User: tailcfg.UserID(machine.NamespaceID),
|
User: tailcfg.UserID(machine.NamespaceID),
|
||||||
Key: nodeKey,
|
Key: nodeKey,
|
||||||
KeyExpiry: keyExpiry,
|
KeyExpiry: keyExpiry,
|
||||||
Machine: machineKey,
|
Machine: machineKey,
|
||||||
DiscoKey: discoKey,
|
DiscoKey: discoKey,
|
||||||
Addresses: addrs,
|
Addresses: addrs,
|
||||||
AllowedIPs: allowedIPs,
|
AllowedIPs: allowedIPs,
|
||||||
Endpoints: machine.Endpoints,
|
PrimaryRoutes: primaryRoutes,
|
||||||
DERP: derp,
|
Endpoints: machine.Endpoints,
|
||||||
|
DERP: derp,
|
||||||
|
|
||||||
Online: &online,
|
Online: &online,
|
||||||
Hostinfo: hostInfo.View(),
|
Hostinfo: hostInfo.View(),
|
||||||
@@ -807,7 +827,8 @@ func (h *Headscale) RegisterMachineFromAuthCallback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Registration of expired machine with different namespace
|
// Registration of expired machine with different namespace
|
||||||
if registrationMachine.ID != 0 && registrationMachine.NamespaceID != namespace.ID {
|
if registrationMachine.ID != 0 &&
|
||||||
|
registrationMachine.NamespaceID != namespace.ID {
|
||||||
return nil, ErrDifferentRegisteredNamespace
|
return nil, ErrDifferentRegisteredNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,21 +4,12 @@ deps:
|
|||||||
- remote: buf.build
|
- remote: buf.build
|
||||||
owner: googleapis
|
owner: googleapis
|
||||||
repository: googleapis
|
repository: googleapis
|
||||||
branch: main
|
commit: 62f35d8aed1149c291d606d958a7ce32
|
||||||
commit: cd101b0abb7b4404a0b1ecc1afd4ce10
|
|
||||||
digest: b1-H4GHwHVHcJBbVPg-Cdmnx812reFCDQws_QoQ0W2hYQA=
|
|
||||||
create_time: 2021-10-23T15:04:06.087748Z
|
|
||||||
- remote: buf.build
|
- remote: buf.build
|
||||||
owner: grpc-ecosystem
|
owner: grpc-ecosystem
|
||||||
repository: grpc-gateway
|
repository: grpc-gateway
|
||||||
branch: main
|
commit: bc28b723cd774c32b6fbc77621518765
|
||||||
commit: ff83506eb9cc4cf8972f49ce87e6ed3e
|
|
||||||
digest: b1-iLPHgLaoeWWinMiXXqPnxqE4BThtY3eSbswVGh9GOGI=
|
|
||||||
create_time: 2021-10-23T16:26:52.283938Z
|
|
||||||
- remote: buf.build
|
- remote: buf.build
|
||||||
owner: ufoundit-dev
|
owner: ufoundit-dev
|
||||||
repository: protoc-gen-gorm
|
repository: protoc-gen-gorm
|
||||||
branch: main
|
|
||||||
commit: e2ecbaa0d37843298104bd29fd866df8
|
commit: e2ecbaa0d37843298104bd29fd866df8
|
||||||
digest: b1-SV9yKH_8P-IKTOlHZxP-bb0ALANYeEqH_mtPA0EWfLc=
|
|
||||||
create_time: 2021-10-08T06:03:05.64876Z
|
|
||||||
|
Reference in New Issue
Block a user