mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Added file for legacy protocol
This commit is contained in:
		
							parent
							
								
									d0898ecabc
								
							
						
					
					
						commit
						db89fdea23
					
				
							
								
								
									
										199
									
								
								protocol_legacy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								protocol_legacy.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,199 @@ | ||||
| package headscale | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gorilla/mux" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"gorm.io/gorm" | ||||
| 	"tailscale.com/tailcfg" | ||||
| 	"tailscale.com/types/key" | ||||
| ) | ||||
| 
 | ||||
| // RegistrationHandler handles the actual registration process of a machine
 | ||||
| // Endpoint /machine/:mkey.
 | ||||
| func (h *Headscale) RegistrationHandler( | ||||
| 	writer http.ResponseWriter, | ||||
| 	req *http.Request, | ||||
| ) { | ||||
| 	vars := mux.Vars(req) | ||||
| 	machineKeyStr, ok := vars["mkey"] | ||||
| 	if !ok || machineKeyStr == "" { | ||||
| 		log.Error(). | ||||
| 			Str("handler", "RegistrationHandler"). | ||||
| 			Msg("No machine ID in request") | ||||
| 		http.Error(writer, "No machine ID in request", http.StatusBadRequest) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	body, _ := io.ReadAll(req.Body) | ||||
| 
 | ||||
| 	var machineKey key.MachinePublic | ||||
| 	err := machineKey.UnmarshalText([]byte(MachinePublicKeyEnsurePrefix(machineKeyStr))) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Caller(). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot parse machine key") | ||||
| 		machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc() | ||||
| 		http.Error(writer, "Cannot parse machine key", http.StatusBadRequest) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 	registerRequest := tailcfg.RegisterRequest{} | ||||
| 	err = decode(body, ®isterRequest, &machineKey, h.privateKey) | ||||
| 	if err != nil { | ||||
| 		log.Error(). | ||||
| 			Caller(). | ||||
| 			Err(err). | ||||
| 			Msg("Cannot decode message") | ||||
| 		machineRegistrations.WithLabelValues("unknown", "web", "error", "unknown").Inc() | ||||
| 		http.Error(writer, "Cannot decode message", http.StatusBadRequest) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	now := time.Now().UTC() | ||||
| 	machine, err := h.GetMachineByMachineKey(machineKey) | ||||
| 	if errors.Is(err, gorm.ErrRecordNotFound) { | ||||
| 		machineKeyStr := MachinePublicKeyStripPrefix(machineKey) | ||||
| 
 | ||||
| 		// If the machine has AuthKey set, handle registration via PreAuthKeys
 | ||||
| 		if registerRequest.Auth.AuthKey != "" { | ||||
| 			h.handleAuthKey(writer, req, machineKey, registerRequest) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// Check if the node is waiting for interactive login.
 | ||||
| 		//
 | ||||
| 		// TODO(juan): We could use this field to improve our protocol implementation,
 | ||||
| 		// and hold the request until the client closes it, or the interactive
 | ||||
| 		// login is completed (i.e., the user registers the machine).
 | ||||
| 		// This is not implemented yet, as it is no strictly required. The only side-effect
 | ||||
| 		// is that the client will hammer headscale with requests until it gets a
 | ||||
| 		// successful RegisterResponse.
 | ||||
| 		if registerRequest.Followup != "" { | ||||
| 			if _, ok := h.registrationCache.Get(NodePublicKeyStripPrefix(registerRequest.NodeKey)); ok { | ||||
| 				log.Debug(). | ||||
| 					Caller(). | ||||
| 					Str("machine", registerRequest.Hostinfo.Hostname). | ||||
| 					Str("node_key", registerRequest.NodeKey.ShortString()). | ||||
| 					Str("node_key_old", registerRequest.OldNodeKey.ShortString()). | ||||
| 					Str("follow_up", registerRequest.Followup). | ||||
| 					Msg("Machine is waiting for interactive login") | ||||
| 
 | ||||
| 				ticker := time.NewTicker(registrationHoldoff) | ||||
| 				select { | ||||
| 				case <-req.Context().Done(): | ||||
| 					return | ||||
| 				case <-ticker.C: | ||||
| 					h.handleMachineRegistrationNew(writer, req, machineKey, registerRequest) | ||||
| 
 | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		log.Info(). | ||||
| 			Caller(). | ||||
| 			Str("machine", registerRequest.Hostinfo.Hostname). | ||||
| 			Str("node_key", registerRequest.NodeKey.ShortString()). | ||||
| 			Str("node_key_old", registerRequest.OldNodeKey.ShortString()). | ||||
| 			Str("follow_up", registerRequest.Followup). | ||||
| 			Msg("New machine not yet in the database") | ||||
| 
 | ||||
| 		givenName, err := h.GenerateGivenName(registerRequest.Hostinfo.Hostname) | ||||
| 		if err != nil { | ||||
| 			log.Error(). | ||||
| 				Caller(). | ||||
| 				Str("func", "RegistrationHandler"). | ||||
| 				Str("hostinfo.name", registerRequest.Hostinfo.Hostname). | ||||
| 				Err(err) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// The machine did not have a key to authenticate, which means
 | ||||
| 		// that we rely on a method that calls back some how (OpenID or CLI)
 | ||||
| 		// We create the machine and then keep it around until a callback
 | ||||
| 		// happens
 | ||||
| 		newMachine := Machine{ | ||||
| 			MachineKey: machineKeyStr, | ||||
| 			Hostname:   registerRequest.Hostinfo.Hostname, | ||||
| 			GivenName:  givenName, | ||||
| 			NodeKey:    NodePublicKeyStripPrefix(registerRequest.NodeKey), | ||||
| 			LastSeen:   &now, | ||||
| 			Expiry:     &time.Time{}, | ||||
| 		} | ||||
| 
 | ||||
| 		if !registerRequest.Expiry.IsZero() { | ||||
| 			log.Trace(). | ||||
| 				Caller(). | ||||
| 				Str("machine", registerRequest.Hostinfo.Hostname). | ||||
| 				Time("expiry", registerRequest.Expiry). | ||||
| 				Msg("Non-zero expiry time requested") | ||||
| 			newMachine.Expiry = ®isterRequest.Expiry | ||||
| 		} | ||||
| 
 | ||||
| 		h.registrationCache.Set( | ||||
| 			newMachine.NodeKey, | ||||
| 			newMachine, | ||||
| 			registerCacheExpiration, | ||||
| 		) | ||||
| 
 | ||||
| 		h.handleMachineRegistrationNew(writer, req, machineKey, registerRequest) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// The machine is already registered, so we need to pass through reauth or key update.
 | ||||
| 	if machine != nil { | ||||
| 		// If the NodeKey stored in headscale is the same as the key presented in a registration
 | ||||
| 		// request, then we have a node that is either:
 | ||||
| 		// - Trying to log out (sending a expiry in the past)
 | ||||
| 		// - A valid, registered machine, looking for the node map
 | ||||
| 		// - Expired machine wanting to reauthenticate
 | ||||
| 		if machine.NodeKey == NodePublicKeyStripPrefix(registerRequest.NodeKey) { | ||||
| 			// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout)
 | ||||
| 			//   https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648
 | ||||
| 			if !registerRequest.Expiry.IsZero() && | ||||
| 				registerRequest.Expiry.UTC().Before(now) { | ||||
| 				h.handleMachineLogOut(writer, req, machineKey, *machine) | ||||
| 
 | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			// If machine is not expired, and is register, we have a already accepted this machine,
 | ||||
| 			// let it proceed with a valid registration
 | ||||
| 			if !machine.isExpired() { | ||||
| 				h.handleMachineValidRegistration(writer, req, machineKey, *machine) | ||||
| 
 | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
 | ||||
| 		if machine.NodeKey == NodePublicKeyStripPrefix(registerRequest.OldNodeKey) && | ||||
| 			!machine.isExpired() { | ||||
| 			h.handleMachineRefreshKey( | ||||
| 				writer, | ||||
| 				req, | ||||
| 				machineKey, | ||||
| 				registerRequest, | ||||
| 				*machine, | ||||
| 			) | ||||
| 
 | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// The machine has expired
 | ||||
| 		h.handleMachineExpired(writer, req, machineKey, registerRequest, *machine) | ||||
| 
 | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user