Remove all instances of undefined numbers (gonmd)

This commit is contained in:
Kristoffer Dalby 2021-11-14 18:31:51 +01:00
parent 796072a5a4
commit 85f28a3f4a
No known key found for this signature in database
GPG key ID: 09F62DC067465735
14 changed files with 78 additions and 42 deletions

View file

@ -29,7 +29,6 @@ linters:
- testpackage - testpackage
- stylecheck - stylecheck
- wrapcheck - wrapcheck
- gomnd
- goerr113 - goerr113
- errorlint - errorlint
- forcetypeassert - forcetypeassert

24
acls.go
View file

@ -24,6 +24,14 @@ const (
errorInvalidPortFormat = Error("invalid port format") errorInvalidPortFormat = Error("invalid port format")
) )
const (
PORT_RANGE_BEGIN = 0
PORT_RANGE_END = 65535
BASE_10 = 10
BIT_SIZE_16 = 16
EXPECTED_TOKEN_ITEMS = 2
)
// LoadACLPolicy loads the ACL policy from the specify path, and generates the ACL rules. // LoadACLPolicy loads the ACL policy from the specify path, and generates the ACL rules.
func (h *Headscale) LoadACLPolicy(path string) error { func (h *Headscale) LoadACLPolicy(path string) error {
policyFile, err := os.Open(path) policyFile, err := os.Open(path)
@ -114,7 +122,7 @@ func (h *Headscale) generateACLPolicyDestPorts(
d string, d string,
) ([]tailcfg.NetPortRange, error) { ) ([]tailcfg.NetPortRange, error) {
tokens := strings.Split(d, ":") tokens := strings.Split(d, ":")
if len(tokens) < 2 || len(tokens) > 3 { if len(tokens) < EXPECTED_TOKEN_ITEMS || len(tokens) > 3 {
return nil, errorInvalidPortFormat return nil, errorInvalidPortFormat
} }
@ -125,7 +133,7 @@ func (h *Headscale) generateACLPolicyDestPorts(
// tag:montreal-webserver:80,443 // tag:montreal-webserver:80,443
// tag:api-server:443 // tag:api-server:443
// example-host-1:* // example-host-1:*
if len(tokens) == 2 { if len(tokens) == EXPECTED_TOKEN_ITEMS {
alias = tokens[0] alias = tokens[0]
} else { } else {
alias = fmt.Sprintf("%s:%s", tokens[0], tokens[1]) alias = fmt.Sprintf("%s:%s", tokens[0], tokens[1])
@ -248,14 +256,16 @@ func (h *Headscale) expandAlias(s string) ([]string, error) {
func (h *Headscale) expandPorts(s string) (*[]tailcfg.PortRange, error) { func (h *Headscale) expandPorts(s string) (*[]tailcfg.PortRange, error) {
if s == "*" { if s == "*" {
return &[]tailcfg.PortRange{{First: 0, Last: 65535}}, nil return &[]tailcfg.PortRange{
{First: PORT_RANGE_BEGIN, Last: PORT_RANGE_END},
}, nil
} }
ports := []tailcfg.PortRange{} ports := []tailcfg.PortRange{}
for _, p := range strings.Split(s, ",") { for _, p := range strings.Split(s, ",") {
rang := strings.Split(p, "-") rang := strings.Split(p, "-")
if len(rang) == 1 { if len(rang) == 1 {
pi, err := strconv.ParseUint(rang[0], 10, 16) pi, err := strconv.ParseUint(rang[0], BASE_10, BIT_SIZE_16)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -263,12 +273,12 @@ func (h *Headscale) expandPorts(s string) (*[]tailcfg.PortRange, error) {
First: uint16(pi), First: uint16(pi),
Last: uint16(pi), Last: uint16(pi),
}) })
} else if len(rang) == 2 { } else if len(rang) == EXPECTED_TOKEN_ITEMS {
start, err := strconv.ParseUint(rang[0], 10, 16) start, err := strconv.ParseUint(rang[0], BASE_10, BIT_SIZE_16)
if err != nil { if err != nil {
return nil, err return nil, err
} }
last, err := strconv.ParseUint(rang[1], 10, 16) last, err := strconv.ParseUint(rang[1], BASE_10, BIT_SIZE_16)
if err != nil { if err != nil {
return nil, err return nil, err
} }

22
api.go
View file

@ -18,10 +18,12 @@ import (
"tailscale.com/types/wgkey" "tailscale.com/types/wgkey"
) )
const RESERVED_RESPONSE_HEADER_SIZE = 4
// KeyHandler provides the Headscale pub key // KeyHandler provides the Headscale pub key
// Listens in /key. // Listens in /key.
func (h *Headscale) KeyHandler(c *gin.Context) { func (h *Headscale) KeyHandler(c *gin.Context) {
c.Data(200, "text/plain; charset=utf-8", []byte(h.publicKey.HexString())) c.Data(http.StatusOK, "text/plain; charset=utf-8", []byte(h.publicKey.HexString()))
} }
// RegisterWebAPI shows a simple message in the browser to point to the CLI // RegisterWebAPI shows a simple message in the browser to point to the CLI
@ -139,7 +141,7 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
return return
} }
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
return return
} }
@ -170,7 +172,7 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
} }
machineRegistrations.WithLabelValues("update", "web", "success", m.Namespace.Name). machineRegistrations.WithLabelValues("update", "web", "success", m.Namespace.Name).
Inc() Inc()
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
return return
} }
@ -213,7 +215,7 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
} }
machineRegistrations.WithLabelValues("new", "web", "success", m.Namespace.Name). machineRegistrations.WithLabelValues("new", "web", "success", m.Namespace.Name).
Inc() Inc()
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
return return
} }
@ -239,7 +241,7 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
return return
} }
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
return return
} }
@ -275,7 +277,7 @@ func (h *Headscale) RegistrationHandler(c *gin.Context) {
return return
} }
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
} }
func (h *Headscale) getMapResponse( func (h *Headscale) getMapResponse(
@ -360,7 +362,7 @@ func (h *Headscale) getMapResponse(
} }
} }
// declare the incoming size on the first 4 bytes // declare the incoming size on the first 4 bytes
data := make([]byte, 4) data := make([]byte, RESERVED_RESPONSE_HEADER_SIZE)
binary.LittleEndian.PutUint32(data, uint32(len(respBody))) binary.LittleEndian.PutUint32(data, uint32(len(respBody)))
data = append(data, respBody...) data = append(data, respBody...)
@ -390,7 +392,7 @@ func (h *Headscale) getMapKeepAliveResponse(
return nil, err return nil, err
} }
} }
data := make([]byte, 4) data := make([]byte, RESERVED_RESPONSE_HEADER_SIZE)
binary.LittleEndian.PutUint32(data, uint32(len(respBody))) binary.LittleEndian.PutUint32(data, uint32(len(respBody)))
data = append(data, respBody...) data = append(data, respBody...)
@ -430,7 +432,7 @@ func (h *Headscale) handleAuthKey(
return return
} }
c.Data(401, "application/json; charset=utf-8", respBody) c.Data(http.StatusUnauthorized, "application/json; charset=utf-8", respBody)
log.Error(). log.Error().
Str("func", "handleAuthKey"). Str("func", "handleAuthKey").
Str("machine", m.Name). Str("machine", m.Name).
@ -490,7 +492,7 @@ func (h *Headscale) handleAuthKey(
} }
machineRegistrations.WithLabelValues("new", "authkey", "success", m.Namespace.Name). machineRegistrations.WithLabelValues("new", "authkey", "success", m.Namespace.Name).
Inc() Inc()
c.Data(200, "application/json; charset=utf-8", respBody) c.Data(http.StatusOK, "application/json; charset=utf-8", respBody)
log.Info(). log.Info().
Str("func", "handleAuthKey"). Str("func", "handleAuthKey").
Str("machine", m.Name). Str("machine", m.Name).

9
app.go
View file

@ -50,6 +50,8 @@ const (
AUTH_PREFIX = "Bearer " AUTH_PREFIX = "Bearer "
POSTGRESQL = "postgresql" POSTGRESQL = "postgresql"
SQLITE = "sqlite3" SQLITE = "sqlite3"
UPDATE_RATE_MILLISECONDS = 5000
HTTP_READ_TIMEOUT = 30 * time.Second
) )
// Config contains the initial Headscale configuration. // Config contains the initial Headscale configuration.
@ -507,14 +509,13 @@ func (h *Headscale) Serve() error {
} }
// I HATE THIS // I HATE THIS
updateMillisecondsWait := int64(5000) go h.watchForKVUpdates(UPDATE_RATE_MILLISECONDS)
go h.watchForKVUpdates(updateMillisecondsWait) go h.expireEphemeralNodes(UPDATE_RATE_MILLISECONDS)
go h.expireEphemeralNodes(updateMillisecondsWait)
httpServer := &http.Server{ httpServer := &http.Server{
Addr: h.cfg.Addr, Addr: h.cfg.Addr,
Handler: r, Handler: r,
ReadTimeout: 30 * time.Second, ReadTimeout: HTTP_READ_TIMEOUT,
// Go does not handle timeouts in HTTP very well, and there is // Go does not handle timeouts in HTTP very well, and there is
// no good way to handle streaming timeouts, therefore we need to // no good way to handle streaming timeouts, therefore we need to
// keep this at unlimited and be careful to clean up connections // keep this at unlimited and be careful to clean up connections

View file

@ -195,7 +195,8 @@ var renameNamespaceCmd = &cobra.Command{
Use: "rename OLD_NAME NEW_NAME", Use: "rename OLD_NAME NEW_NAME",
Short: "Renames a namespace", Short: "Renames a namespace",
Args: func(cmd *cobra.Command, args []string) error { Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 { expectedArguments := 2
if len(args) < expectedArguments {
return fmt.Errorf("Missing parameters") return fmt.Errorf("Missing parameters")
} }

View file

@ -7,6 +7,7 @@ import (
"time" "time"
survey "github.com/AlecAivazis/survey/v2" survey "github.com/AlecAivazis/survey/v2"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1" v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/pterm/pterm" "github.com/pterm/pterm"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -450,7 +451,7 @@ func nodesToPtables(
d = append( d = append(
d, d,
[]string{ []string{
strconv.FormatUint(machine.Id, 10), strconv.FormatUint(machine.Id, headscale.BASE_10),
machine.Name, machine.Name,
nodeKey.ShortString(), nodeKey.ShortString(),
namespace, namespace,

View file

@ -12,6 +12,10 @@ import (
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
) )
const (
DEFAULT_PRE_AUTH_KEY_EXPIRY = 24 * time.Hour
)
func init() { func init() {
rootCmd.AddCommand(preauthkeysCmd) rootCmd.AddCommand(preauthkeysCmd)
preauthkeysCmd.PersistentFlags().StringP("namespace", "n", "", "Namespace") preauthkeysCmd.PersistentFlags().StringP("namespace", "n", "", "Namespace")
@ -27,7 +31,7 @@ func init() {
createPreAuthKeyCmd.PersistentFlags(). createPreAuthKeyCmd.PersistentFlags().
Bool("ephemeral", false, "Preauthkey for ephemeral nodes") Bool("ephemeral", false, "Preauthkey for ephemeral nodes")
createPreAuthKeyCmd.Flags(). createPreAuthKeyCmd.Flags().
DurationP("expiration", "e", 24*time.Hour, "Human-readable expiration of the key (30m, 24h, 365d...)") DurationP("expiration", "e", DEFAULT_PRE_AUTH_KEY_EXPIRY, "Human-readable expiration of the key (30m, 24h, 365d...)")
} }
var preauthkeysCmd = &cobra.Command{ var preauthkeysCmd = &cobra.Command{

View file

@ -32,7 +32,7 @@ func loadDERPMapFromPath(path string) (*tailcfg.DERPMap, error) {
} }
func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) { func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), HTTP_READ_TIMEOUT)
defer cancel() defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", addr.String(), nil) req, err := http.NewRequestWithContext(ctx, "GET", addr.String(), nil)
@ -41,7 +41,7 @@ func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) {
} }
client := http.Client{ client := http.Client{
Timeout: 10 * time.Second, Timeout: HTTP_READ_TIMEOUT,
} }
resp, err := client.Do(req) resp, err := client.Do(req)

8
dns.go
View file

@ -10,6 +10,10 @@ import (
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
const (
BYTE_SIZE = 8
)
// generateMagicDNSRootDomains generates a list of DNS entries to be included in `Routes` in `MapResponse`. // generateMagicDNSRootDomains generates a list of DNS entries to be included in `Routes` in `MapResponse`.
// This list of reverse DNS entries instructs the OS on what subnets and domains the Tailscale embedded DNS // This list of reverse DNS entries instructs the OS on what subnets and domains the Tailscale embedded DNS
// server (listening in 100.100.100.100 udp/53) should be used for. // server (listening in 100.100.100.100 udp/53) should be used for.
@ -43,10 +47,10 @@ func generateMagicDNSRootDomains(
maskBits, _ := netRange.Mask.Size() maskBits, _ := netRange.Mask.Size()
// lastOctet is the last IP byte covered by the mask // lastOctet is the last IP byte covered by the mask
lastOctet := maskBits / 8 lastOctet := maskBits / BYTE_SIZE
// wildcardBits is the number of bits not under the mask in the lastOctet // wildcardBits is the number of bits not under the mask in the lastOctet
wildcardBits := 8 - maskBits%8 wildcardBits := BYTE_SIZE - maskBits%BYTE_SIZE
// min is the value in the lastOctet byte of the IP // min is the value in the lastOctet byte of the IP
// max is basically 2^wildcardBits - i.e., the value when all the wildcardBits are set to 1 // max is basically 2^wildcardBits - i.e., the value when all the wildcardBits are set to 1

View file

@ -523,7 +523,7 @@ func (m Machine) toNode(
n := tailcfg.Node{ n := tailcfg.Node{
ID: tailcfg.NodeID(m.ID), // this is the actual ID ID: tailcfg.NodeID(m.ID), // this is the actual ID
StableID: tailcfg.StableNodeID( StableID: tailcfg.StableNodeID(
strconv.FormatUint(m.ID, 10), strconv.FormatUint(m.ID, BASE_10),
), // in headscale, unlike tailcontrol server, IDs are permanent ), // in headscale, unlike tailcontrol server, IDs are permanent
Name: hostname, Name: hostname,
User: tailcfg.UserID(m.NamespaceID), User: tailcfg.UserID(m.NamespaceID),

View file

@ -320,7 +320,7 @@ func getMapResponseUserProfiles(m Machine, peers Machines) []tailcfg.UserProfile
func (n *Namespace) toProto() *v1.Namespace { func (n *Namespace) toProto() *v1.Namespace {
return &v1.Namespace{ return &v1.Namespace{
Id: strconv.FormatUint(uint64(n.ID), 10), Id: strconv.FormatUint(uint64(n.ID), BASE_10),
Name: n.Name, Name: n.Name,
CreatedAt: timestamppb.New(n.CreatedAt), CreatedAt: timestamppb.New(n.CreatedAt),
} }

15
oidc.go
View file

@ -17,6 +17,12 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
const (
OIDC_STATE_CACHE_EXPIRATION = time.Minute * 5
OIDC_STATE_CACHE_CLEANUP_INTERVAL = time.Minute * 10
RANDOM_BYTE_SIZE = 16
)
type IDTokenClaims struct { type IDTokenClaims struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
@ -50,7 +56,10 @@ func (h *Headscale) initOIDC() error {
// init the state cache if it hasn't been already // init the state cache if it hasn't been already
if h.oidcStateCache == nil { if h.oidcStateCache == nil {
h.oidcStateCache = cache.New(time.Minute*5, time.Minute*10) h.oidcStateCache = cache.New(
OIDC_STATE_CACHE_EXPIRATION,
OIDC_STATE_CACHE_CLEANUP_INTERVAL,
)
} }
return nil return nil
@ -67,7 +76,7 @@ func (h *Headscale) RegisterOIDC(c *gin.Context) {
return return
} }
b := make([]byte, 16) b := make([]byte, RANDOM_BYTE_SIZE)
if _, err := rand.Read(b); err != nil { if _, err := rand.Read(b); err != nil {
log.Error().Msg("could not read 16 bytes from rand") log.Error().Msg("could not read 16 bytes from rand")
c.String(http.StatusInternalServerError, "could not read 16 bytes from rand") c.String(http.StatusInternalServerError, "could not read 16 bytes from rand")
@ -78,7 +87,7 @@ func (h *Headscale) RegisterOIDC(c *gin.Context) {
stateStr := hex.EncodeToString(b)[:32] stateStr := hex.EncodeToString(b)[:32]
// place the machine key into the state cache, so it can be retrieved later // place the machine key into the state cache, so it can be retrieved later
h.oidcStateCache.Set(stateStr, mKeyStr, time.Minute*5) h.oidcStateCache.Set(stateStr, mKeyStr, OIDC_STATE_CACHE_EXPIRATION)
authUrl := h.oauth2Config.AuthCodeURL(stateStr) authUrl := h.oauth2Config.AuthCodeURL(stateStr)
log.Debug().Msgf("Redirecting to %s for authentication", authUrl) log.Debug().Msgf("Redirecting to %s for authentication", authUrl)

13
poll.go
View file

@ -15,6 +15,11 @@ import (
"tailscale.com/types/wgkey" "tailscale.com/types/wgkey"
) )
const (
KEEP_ALIVE_INTERVAL = 60 * time.Second
UPDATE_CHECK_INTERVAL = 10 * time.Second
)
// PollNetMapHandler takes care of /machine/:id/map // PollNetMapHandler takes care of /machine/:id/map
// //
// This is the busiest endpoint, as it keeps the HTTP long poll that updates // This is the busiest endpoint, as it keeps the HTTP long poll that updates
@ -127,7 +132,7 @@ func (h *Headscale) PollNetMapHandler(c *gin.Context) {
Str("handler", "PollNetMap"). Str("handler", "PollNetMap").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Client is starting up. Probably interested in a DERP map") Msg("Client is starting up. Probably interested in a DERP map")
c.Data(200, "application/json; charset=utf-8", data) c.Data(http.StatusOK, "application/json; charset=utf-8", data)
return return
} }
@ -159,7 +164,7 @@ func (h *Headscale) PollNetMapHandler(c *gin.Context) {
Str("handler", "PollNetMap"). Str("handler", "PollNetMap").
Str("machine", m.Name). Str("machine", m.Name).
Msg("Client sent endpoint update and is ok with a response without peer list") Msg("Client sent endpoint update and is ok with a response without peer list")
c.Data(200, "application/json; charset=utf-8", data) c.Data(http.StatusOK, "application/json; charset=utf-8", data)
// It sounds like we should update the nodes when we have received a endpoint update // It sounds like we should update the nodes when we have received a endpoint update
// even tho the comments in the tailscale code dont explicitly say so. // even tho the comments in the tailscale code dont explicitly say so.
@ -483,8 +488,8 @@ func (h *Headscale) scheduledPollWorker(
req tailcfg.MapRequest, req tailcfg.MapRequest,
m *Machine, m *Machine,
) { ) {
keepAliveTicker := time.NewTicker(60 * time.Second) keepAliveTicker := time.NewTicker(KEEP_ALIVE_INTERVAL)
updateCheckerTicker := time.NewTicker(10 * time.Second) updateCheckerTicker := time.NewTicker(UPDATE_CHECK_INTERVAL)
for { for {
select { select {

View file

@ -156,7 +156,7 @@ func (h *Headscale) generateKey() (string, error) {
func (key *PreAuthKey) toProto() *v1.PreAuthKey { func (key *PreAuthKey) toProto() *v1.PreAuthKey {
protoKey := v1.PreAuthKey{ protoKey := v1.PreAuthKey{
Namespace: key.Namespace.Name, Namespace: key.Namespace.Name,
Id: strconv.FormatUint(key.ID, 10), Id: strconv.FormatUint(key.ID, BASE_10),
Key: key.Key, Key: key.Key,
Ephemeral: key.Ephemeral, Ephemeral: key.Ephemeral,
Reusable: key.Reusable, Reusable: key.Reusable,