mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-31 16:11:03 +01:00 
			
		
		
		
	Merge branch 'main' into oidc-refactoring
This commit is contained in:
		
						commit
						8a9fe1da4b
					
				
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							| @ -67,15 +67,15 @@ one of the maintainers. | ||||
| 
 | ||||
| ## Client OS support | ||||
| 
 | ||||
| | OS      | Supports headscale                                                                                                | | ||||
| | ------- | ----------------------------------------------------------------------------------------------------------------- | | ||||
| | Linux   | Yes                                                                                                               | | ||||
| | OpenBSD | Yes                                                                                                               | | ||||
| | FreeBSD | Yes                                                                                                               | | ||||
| | macOS   | Yes (see `/apple` on your headscale for more information)                                                         | | ||||
| | Windows | Yes [docs](./docs/windows-client.md)                                                                              | | ||||
| | Android | [You need to compile the client yourself](https://github.com/juanfont/headscale/issues/58#issuecomment-885255270) | | ||||
| | iOS     | Not yet                                                                                                           | | ||||
| | OS      | Supports headscale                                        | | ||||
| | ------- | --------------------------------------------------------- | | ||||
| | Linux   | Yes                                                       | | ||||
| | OpenBSD | Yes                                                       | | ||||
| | FreeBSD | Yes                                                       | | ||||
| | macOS   | Yes (see `/apple` on your headscale for more information) | | ||||
| | Windows | Yes [docs](./docs/windows-client.md)                      | | ||||
| | Android | Yes [docs](./docs/android-client.md)                      | | ||||
| | iOS     | Not yet                                                   | | ||||
| 
 | ||||
| ## Running headscale | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,7 @@ const ( | ||||
| 	apiPrefixLength = 7 | ||||
| 	apiKeyLength    = 32 | ||||
| 
 | ||||
| 	errAPIKeyFailedToParse = Error("Failed to parse ApiKey") | ||||
| 	ErrAPIKeyFailedToParse = Error("Failed to parse ApiKey") | ||||
| ) | ||||
| 
 | ||||
| // APIKey describes the datamodel for API keys used to remotely authenticate with | ||||
| @ -116,7 +116,7 @@ func (h *Headscale) ExpireAPIKey(key *APIKey) error { | ||||
| func (h *Headscale) ValidateAPIKey(keyStr string) (bool, error) { | ||||
| 	prefix, hash, found := strings.Cut(keyStr, ".") | ||||
| 	if !found { | ||||
| 		return false, errAPIKeyFailedToParse | ||||
| 		return false, ErrAPIKeyFailedToParse | ||||
| 	} | ||||
| 
 | ||||
| 	key, err := h.GetAPIKey(prefix) | ||||
|  | ||||
							
								
								
									
										6
									
								
								db.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								db.go
									
									
									
									
									
								
							| @ -248,7 +248,7 @@ func (hi *HostInfo) Scan(destination interface{}) error { | ||||
| 		return json.Unmarshal([]byte(value), hi) | ||||
| 
 | ||||
| 	default: | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", errMachineAddressesInvalid, destination) | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -270,7 +270,7 @@ func (i *IPPrefixes) Scan(destination interface{}) error { | ||||
| 		return json.Unmarshal([]byte(value), i) | ||||
| 
 | ||||
| 	default: | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", errMachineAddressesInvalid, destination) | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -292,7 +292,7 @@ func (i *StringList) Scan(destination interface{}) error { | ||||
| 		return json.Unmarshal([]byte(value), i) | ||||
| 
 | ||||
| 	default: | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", errMachineAddressesInvalid, destination) | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -36,7 +36,7 @@ ACLs could be written either on [huJSON](https://github.com/tailscale/hujson) | ||||
| or YAML. Check the [test ACLs](../tests/acls) for further information. | ||||
| 
 | ||||
| When registering the servers we will need to add the flag | ||||
| `--advertised-tags=tag:<tag1>,tag:<tag2>`, and the user (namespace) that is | ||||
| `--advertise-tags=tag:<tag1>,tag:<tag2>`, and the user (namespace) that is | ||||
| registering the server should be allowed to do it. Since anyone can add tags to | ||||
| a server they can register, the check of the tags is done on headscale server | ||||
| and only valid tags are applied. A tag is valid if the namespace that is | ||||
|  | ||||
							
								
								
									
										19
									
								
								docs/android-client.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								docs/android-client.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| # Connecting an Android client | ||||
| 
 | ||||
| ## Goal | ||||
| 
 | ||||
| This documentation has the goal of showing how a user can use the official Android [Tailscale](https://tailscale.com) client with `headscale`. | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| Install the official Tailscale Android client from the [Google Play Store](https://play.google.com/store/apps/details?id=com.tailscale.ipn) or [F-Droid](https://f-droid.org/packages/com.tailscale.ipn/). | ||||
| 
 | ||||
| Ensure that the installed version is at least 1.30.0, as that is the first release to support custom URLs. | ||||
| 
 | ||||
| ## Configuring the headscale URL | ||||
| 
 | ||||
| After opening the app, the kebab menu icon (three dots) on the top bar on the right must be repeatedly opened and closed until the _Change server_ option appears in the menu. This is where you can enter your headscale URL. | ||||
| 
 | ||||
| A screen recording of this process can be seen in the `tailscale-android` PR which implemented this functionality: <https://github.com/tailscale/tailscale-android/pull/55> | ||||
| 
 | ||||
| After saving and restarting the app, selecting the regular _Sign in_ option (non-SSO) should open up the headscale authentication page. | ||||
							
								
								
									
										24
									
								
								machine.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								machine.go
									
									
									
									
									
								
							| @ -18,14 +18,14 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	errMachineNotFound                  = Error("machine not found") | ||||
| 	errMachineRouteIsNotAvailable       = Error("route is not available on machine") | ||||
| 	errMachineAddressesInvalid          = Error("failed to parse machine addresses") | ||||
| 	errMachineNotFoundRegistrationCache = Error( | ||||
| 	ErrMachineNotFound                  = Error("machine not found") | ||||
| 	ErrMachineRouteIsNotAvailable       = Error("route is not available on machine") | ||||
| 	ErrMachineAddressesInvalid          = Error("failed to parse machine addresses") | ||||
| 	ErrMachineNotFoundRegistrationCache = Error( | ||||
| 		"machine not found in registration cache", | ||||
| 	) | ||||
| 	errCouldNotConvertMachineInterface = Error("failed to convert machine interface") | ||||
| 	errHostnameTooLong                 = Error("Hostname too long") | ||||
| 	ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface") | ||||
| 	ErrHostnameTooLong                 = Error("Hostname too long") | ||||
| 	MachineGivenNameHashLength         = 8 | ||||
| 	MachineGivenNameTrimSize           = 2 | ||||
| ) | ||||
| @ -112,7 +112,7 @@ func (ma *MachineAddresses) Scan(destination interface{}) error { | ||||
| 		return nil | ||||
| 
 | ||||
| 	default: | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", errMachineAddressesInvalid, destination) | ||||
| 		return fmt.Errorf("%w: unexpected data type %T", ErrMachineAddressesInvalid, destination) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -337,7 +337,7 @@ func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, errMachineNotFound | ||||
| 	return nil, ErrMachineNotFound | ||||
| } | ||||
| 
 | ||||
| // GetMachineByID finds a Machine by ID and returns the Machine struct. | ||||
| @ -635,7 +635,7 @@ func (machine Machine) toNode( | ||||
| 			return nil, fmt.Errorf( | ||||
| 				"hostname %q is too long it cannot except 255 ASCII chars: %w", | ||||
| 				hostname, | ||||
| 				errHostnameTooLong, | ||||
| 				ErrHostnameTooLong, | ||||
| 			) | ||||
| 		} | ||||
| 	} else { | ||||
| @ -785,11 +785,11 @@ func (h *Headscale) RegisterMachineFromAuthCallback( | ||||
| 
 | ||||
| 			return machine, err | ||||
| 		} else { | ||||
| 			return nil, errCouldNotConvertMachineInterface | ||||
| 			return nil, ErrCouldNotConvertMachineInterface | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, errMachineNotFoundRegistrationCache | ||||
| 	return nil, ErrMachineNotFoundRegistrationCache | ||||
| } | ||||
| 
 | ||||
| // RegisterMachine is executed from the CLI to register a new Machine using its MachineKey. | ||||
| @ -877,7 +877,7 @@ func (h *Headscale) EnableRoutes(machine *Machine, routeStrs ...string) error { | ||||
| 			return fmt.Errorf( | ||||
| 				"route (%s) is not available on node %s: %w", | ||||
| 				machine.Hostname, | ||||
| 				newRoute, errMachineRouteIsNotAvailable, | ||||
| 				newRoute, ErrMachineRouteIsNotAvailable, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -16,10 +16,10 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	errNamespaceExists          = Error("Namespace already exists") | ||||
| 	errNamespaceNotFound        = Error("Namespace not found") | ||||
| 	errNamespaceNotEmptyOfNodes = Error("Namespace not empty: node(s) found") | ||||
| 	errInvalidNamespaceName     = Error("Invalid namespace name") | ||||
| 	ErrNamespaceExists          = Error("Namespace already exists") | ||||
| 	ErrNamespaceNotFound        = Error("Namespace not found") | ||||
| 	ErrNamespaceNotEmptyOfNodes = Error("Namespace not empty: node(s) found") | ||||
| 	ErrInvalidNamespaceName     = Error("Invalid namespace name") | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -47,7 +47,7 @@ func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { | ||||
| 	} | ||||
| 	namespace := Namespace{} | ||||
| 	if err := h.db.Where("name = ?", name).First(&namespace).Error; err == nil { | ||||
| 		return nil, errNamespaceExists | ||||
| 		return nil, ErrNamespaceExists | ||||
| 	} | ||||
| 	namespace.Name = name | ||||
| 	if err := h.db.Create(&namespace).Error; err != nil { | ||||
| @ -67,7 +67,7 @@ func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { | ||||
| func (h *Headscale) DestroyNamespace(name string) error { | ||||
| 	namespace, err := h.GetNamespace(name) | ||||
| 	if err != nil { | ||||
| 		return errNamespaceNotFound | ||||
| 		return ErrNamespaceNotFound | ||||
| 	} | ||||
| 
 | ||||
| 	machines, err := h.ListMachinesInNamespace(name) | ||||
| @ -75,7 +75,7 @@ func (h *Headscale) DestroyNamespace(name string) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(machines) > 0 { | ||||
| 		return errNamespaceNotEmptyOfNodes | ||||
| 		return ErrNamespaceNotEmptyOfNodes | ||||
| 	} | ||||
| 
 | ||||
| 	keys, err := h.ListPreAuthKeys(name) | ||||
| @ -110,9 +110,9 @@ func (h *Headscale) RenameNamespace(oldName, newName string) error { | ||||
| 	} | ||||
| 	_, err = h.GetNamespace(newName) | ||||
| 	if err == nil { | ||||
| 		return errNamespaceExists | ||||
| 		return ErrNamespaceExists | ||||
| 	} | ||||
| 	if !errors.Is(err, errNamespaceNotFound) { | ||||
| 	if !errors.Is(err, ErrNamespaceNotFound) { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| @ -132,7 +132,7 @@ func (h *Headscale) GetNamespace(name string) (*Namespace, error) { | ||||
| 		result.Error, | ||||
| 		gorm.ErrRecordNotFound, | ||||
| 	) { | ||||
| 		return nil, errNamespaceNotFound | ||||
| 		return nil, ErrNamespaceNotFound | ||||
| 	} | ||||
| 
 | ||||
| 	return &namespace, nil | ||||
| @ -272,7 +272,7 @@ func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) { | ||||
| 			return "", fmt.Errorf( | ||||
| 				"label %v is more than 63 chars: %w", | ||||
| 				elt, | ||||
| 				errInvalidNamespaceName, | ||||
| 				ErrInvalidNamespaceName, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| @ -285,21 +285,21 @@ func CheckForFQDNRules(name string) error { | ||||
| 		return fmt.Errorf( | ||||
| 			"DNS segment must not be over 63 chars. %v doesn't comply with this rule: %w", | ||||
| 			name, | ||||
| 			errInvalidNamespaceName, | ||||
| 			ErrInvalidNamespaceName, | ||||
| 		) | ||||
| 	} | ||||
| 	if strings.ToLower(name) != name { | ||||
| 		return fmt.Errorf( | ||||
| 			"DNS segment should be lowercase. %v doesn't comply with this rule: %w", | ||||
| 			name, | ||||
| 			errInvalidNamespaceName, | ||||
| 			ErrInvalidNamespaceName, | ||||
| 		) | ||||
| 	} | ||||
| 	if invalidCharsInNamespaceRegex.MatchString(name) { | ||||
| 		return fmt.Errorf( | ||||
| 			"DNS segment should only be composed of lowercase ASCII letters numbers, hyphen and dots. %v doesn't comply with theses rules: %w", | ||||
| 			name, | ||||
| 			errInvalidNamespaceName, | ||||
| 			ErrInvalidNamespaceName, | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -26,7 +26,7 @@ func (s *Suite) TestCreateAndDestroyNamespace(c *check.C) { | ||||
| 
 | ||||
| func (s *Suite) TestDestroyNamespaceErrors(c *check.C) { | ||||
| 	err := app.DestroyNamespace("test") | ||||
| 	c.Assert(err, check.Equals, errNamespaceNotFound) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceNotFound) | ||||
| 
 | ||||
| 	namespace, err := app.CreateNamespace("test") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| @ -60,7 +60,7 @@ func (s *Suite) TestDestroyNamespaceErrors(c *check.C) { | ||||
| 	app.db.Save(&machine) | ||||
| 
 | ||||
| 	err = app.DestroyNamespace("test") | ||||
| 	c.Assert(err, check.Equals, errNamespaceNotEmptyOfNodes) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceNotEmptyOfNodes) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TestRenameNamespace(c *check.C) { | ||||
| @ -76,20 +76,20 @@ func (s *Suite) TestRenameNamespace(c *check.C) { | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	_, err = app.GetNamespace("test") | ||||
| 	c.Assert(err, check.Equals, errNamespaceNotFound) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceNotFound) | ||||
| 
 | ||||
| 	_, err = app.GetNamespace("test-renamed") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	err = app.RenameNamespace("test-does-not-exit", "test") | ||||
| 	c.Assert(err, check.Equals, errNamespaceNotFound) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceNotFound) | ||||
| 
 | ||||
| 	namespaceTest2, err := app.CreateNamespace("test2") | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 	c.Assert(namespaceTest2.Name, check.Equals, "test2") | ||||
| 
 | ||||
| 	err = app.RenameNamespace("test2", "test-renamed") | ||||
| 	c.Assert(err, check.Equals, errNamespaceExists) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceExists) | ||||
| } | ||||
| 
 | ||||
| func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { | ||||
| @ -402,7 +402,7 @@ func (s *Suite) TestSetMachineNamespace(c *check.C) { | ||||
| 	c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name) | ||||
| 
 | ||||
| 	err = app.SetMachineNamespace(&machine, "non-existing-namespace") | ||||
| 	c.Assert(err, check.Equals, errNamespaceNotFound) | ||||
| 	c.Assert(err, check.Equals, ErrNamespaceNotFound) | ||||
| 
 | ||||
| 	err = app.SetMachineNamespace(&machine, newNamespace.Name) | ||||
| 	c.Assert(err, check.IsNil) | ||||
|  | ||||
							
								
								
									
										2
									
								
								oidc.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								oidc.go
									
									
									
									
									
								
							| @ -551,7 +551,7 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( | ||||
| 	namespaceName string, | ||||
| ) (*Namespace, error) { | ||||
| 	namespace, err := h.GetNamespace(namespaceName) | ||||
| 	if errors.Is(err, errNamespaceNotFound) { | ||||
| 	if errors.Is(err, ErrNamespaceNotFound) { | ||||
| 		namespace, err = h.CreateNamespace(namespaceName) | ||||
| 
 | ||||
| 		if err != nil { | ||||
|  | ||||
| @ -14,10 +14,10 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	errPreAuthKeyNotFound          = Error("AuthKey not found") | ||||
| 	errPreAuthKeyExpired           = Error("AuthKey expired") | ||||
| 	errSingleUseAuthKeyHasBeenUsed = Error("AuthKey has already been used") | ||||
| 	errNamespaceMismatch           = Error("namespace mismatch") | ||||
| 	ErrPreAuthKeyNotFound          = Error("AuthKey not found") | ||||
| 	ErrPreAuthKeyExpired           = Error("AuthKey expired") | ||||
| 	ErrSingleUseAuthKeyHasBeenUsed = Error("AuthKey has already been used") | ||||
| 	ErrNamespaceMismatch           = Error("namespace mismatch") | ||||
| ) | ||||
| 
 | ||||
| // PreAuthKey describes a pre-authorization key usable in a particular namespace. | ||||
| @ -92,7 +92,7 @@ func (h *Headscale) GetPreAuthKey(namespace string, key string) (*PreAuthKey, er | ||||
| 	} | ||||
| 
 | ||||
| 	if pak.Namespace.Name != namespace { | ||||
| 		return nil, errNamespaceMismatch | ||||
| 		return nil, ErrNamespaceMismatch | ||||
| 	} | ||||
| 
 | ||||
| 	return pak, nil | ||||
| @ -135,11 +135,11 @@ func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) { | ||||
| 		result.Error, | ||||
| 		gorm.ErrRecordNotFound, | ||||
| 	) { | ||||
| 		return nil, errPreAuthKeyNotFound | ||||
| 		return nil, ErrPreAuthKeyNotFound | ||||
| 	} | ||||
| 
 | ||||
| 	if pak.Expiration != nil && pak.Expiration.Before(time.Now()) { | ||||
| 		return nil, errPreAuthKeyExpired | ||||
| 		return nil, ErrPreAuthKeyExpired | ||||
| 	} | ||||
| 
 | ||||
| 	if pak.Reusable || pak.Ephemeral { // we don't need to check if has been used before | ||||
| @ -152,7 +152,7 @@ func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) { | ||||
| 	} | ||||
| 
 | ||||
| 	if len(machines) != 0 || pak.Used { | ||||
| 		return nil, errSingleUseAuthKeyHasBeenUsed | ||||
| 		return nil, ErrSingleUseAuthKeyHasBeenUsed | ||||
| 	} | ||||
| 
 | ||||
| 	return &pak, nil | ||||
|  | ||||
| @ -44,13 +44,13 @@ func (*Suite) TestExpiredPreAuthKey(c *check.C) { | ||||
| 	c.Assert(err, check.IsNil) | ||||
| 
 | ||||
| 	key, err := app.checkKeyValidity(pak.Key) | ||||
| 	c.Assert(err, check.Equals, errPreAuthKeyExpired) | ||||
| 	c.Assert(err, check.Equals, ErrPreAuthKeyExpired) | ||||
| 	c.Assert(key, check.IsNil) | ||||
| } | ||||
| 
 | ||||
| func (*Suite) TestPreAuthKeyDoesNotExist(c *check.C) { | ||||
| 	key, err := app.checkKeyValidity("potatoKey") | ||||
| 	c.Assert(err, check.Equals, errPreAuthKeyNotFound) | ||||
| 	c.Assert(err, check.Equals, ErrPreAuthKeyNotFound) | ||||
| 	c.Assert(key, check.IsNil) | ||||
| } | ||||
| 
 | ||||
| @ -86,7 +86,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) { | ||||
| 	app.db.Save(&machine) | ||||
| 
 | ||||
| 	key, err := app.checkKeyValidity(pak.Key) | ||||
| 	c.Assert(err, check.Equals, errSingleUseAuthKeyHasBeenUsed) | ||||
| 	c.Assert(err, check.Equals, ErrSingleUseAuthKeyHasBeenUsed) | ||||
| 	c.Assert(key, check.IsNil) | ||||
| } | ||||
| 
 | ||||
| @ -174,7 +174,7 @@ func (*Suite) TestExpirePreauthKey(c *check.C) { | ||||
| 	c.Assert(pak.Expiration, check.NotNil) | ||||
| 
 | ||||
| 	key, err := app.checkKeyValidity(pak.Key) | ||||
| 	c.Assert(err, check.Equals, errPreAuthKeyExpired) | ||||
| 	c.Assert(err, check.Equals, ErrPreAuthKeyExpired) | ||||
| 	c.Assert(key, check.IsNil) | ||||
| } | ||||
| 
 | ||||
| @ -188,5 +188,5 @@ func (*Suite) TestNotReusableMarkedAsUsed(c *check.C) { | ||||
| 	app.db.Save(&pak) | ||||
| 
 | ||||
| 	_, err = app.checkKeyValidity(pak.Key) | ||||
| 	c.Assert(err, check.Equals, errSingleUseAuthKeyHasBeenUsed) | ||||
| 	c.Assert(err, check.Equals, ErrSingleUseAuthKeyHasBeenUsed) | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	errRouteIsNotAvailable = Error("route is not available") | ||||
| 	ErrRouteIsNotAvailable = Error("route is not available") | ||||
| ) | ||||
| 
 | ||||
| // Deprecated: use machine function instead | ||||
| @ -106,7 +106,7 @@ func (h *Headscale) EnableNodeRoute( | ||||
| 	} | ||||
| 
 | ||||
| 	if !available { | ||||
| 		return errRouteIsNotAvailable | ||||
| 		return ErrRouteIsNotAvailable | ||||
| 	} | ||||
| 
 | ||||
| 	machine.EnabledRoutes = enabledRoutes | ||||
|  | ||||
							
								
								
									
										8
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								utils.go
									
									
									
									
									
								
							| @ -27,8 +27,8 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	errCannotDecryptReponse = Error("cannot decrypt response") | ||||
| 	errCouldNotAllocateIP   = Error("could not find any suitable IP") | ||||
| 	ErrCannotDecryptResponse = Error("cannot decrypt response") | ||||
| 	ErrCouldNotAllocateIP    = Error("could not find any suitable IP") | ||||
| 
 | ||||
| 	// These constants are copied from the upstream tailscale.com/types/key | ||||
| 	// library, because they are not exported. | ||||
| @ -120,7 +120,7 @@ func decode( | ||||
| 
 | ||||
| 	decrypted, ok := privKey.OpenFrom(*pubKey, msg) | ||||
| 	if !ok { | ||||
| 		return errCannotDecryptReponse | ||||
| 		return ErrCannotDecryptResponse | ||||
| 	} | ||||
| 
 | ||||
| 	if err := json.Unmarshal(decrypted, output); err != nil { | ||||
| @ -181,7 +181,7 @@ func (h *Headscale) getAvailableIP(ipPrefix netaddr.IPPrefix) (*netaddr.IP, erro | ||||
| 
 | ||||
| 	for { | ||||
| 		if !ipPrefix.Contains(ip) { | ||||
| 			return nil, errCouldNotAllocateIP | ||||
| 			return nil, ErrCouldNotAllocateIP | ||||
| 		} | ||||
| 
 | ||||
| 		switch { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user