mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			99 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package v2
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"slices"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"tailscale.com/tailcfg"
 | |
| )
 | |
| 
 | |
| // splitDestinationAndPort takes an input string and returns the destination and port as a tuple, or an error if the input is invalid.
 | |
| func splitDestinationAndPort(input string) (string, string, error) {
 | |
| 	// Find the last occurrence of the colon character
 | |
| 	lastColonIndex := strings.LastIndex(input, ":")
 | |
| 
 | |
| 	// Check if the colon character is present and not at the beginning or end of the string
 | |
| 	if lastColonIndex == -1 {
 | |
| 		return "", "", errors.New("input must contain a colon character separating destination and port")
 | |
| 	}
 | |
| 	if lastColonIndex == 0 {
 | |
| 		return "", "", errors.New("input cannot start with a colon character")
 | |
| 	}
 | |
| 	if lastColonIndex == len(input)-1 {
 | |
| 		return "", "", errors.New("input cannot end with a colon character")
 | |
| 	}
 | |
| 
 | |
| 	// Split the string into destination and port based on the last colon
 | |
| 	destination := input[:lastColonIndex]
 | |
| 	port := input[lastColonIndex+1:]
 | |
| 
 | |
| 	return destination, port, nil
 | |
| }
 | |
| 
 | |
| // parsePortRange parses a port definition string and returns a slice of PortRange structs.
 | |
| func parsePortRange(portDef string) ([]tailcfg.PortRange, error) {
 | |
| 	if portDef == "*" {
 | |
| 		return []tailcfg.PortRange{tailcfg.PortRangeAny}, nil
 | |
| 	}
 | |
| 
 | |
| 	var portRanges []tailcfg.PortRange
 | |
| 	parts := strings.Split(portDef, ",")
 | |
| 
 | |
| 	for _, part := range parts {
 | |
| 		if strings.Contains(part, "-") {
 | |
| 			rangeParts := strings.Split(part, "-")
 | |
| 			rangeParts = slices.DeleteFunc(rangeParts, func(e string) bool {
 | |
| 				return e == ""
 | |
| 			})
 | |
| 			if len(rangeParts) != 2 {
 | |
| 				return nil, errors.New("invalid port range format")
 | |
| 			}
 | |
| 
 | |
| 			first, err := parsePort(rangeParts[0])
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			last, err := parsePort(rangeParts[1])
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			if first > last {
 | |
| 				return nil, errors.New("invalid port range: first port is greater than last port")
 | |
| 			}
 | |
| 
 | |
| 			portRanges = append(portRanges, tailcfg.PortRange{First: first, Last: last})
 | |
| 		} else {
 | |
| 			port, err := parsePort(part)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			if port < 1 {
 | |
| 				return nil, errors.New("first port must be >0, or use '*' for wildcard")
 | |
| 			}
 | |
| 
 | |
| 			portRanges = append(portRanges, tailcfg.PortRange{First: port, Last: port})
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return portRanges, nil
 | |
| }
 | |
| 
 | |
| // parsePort parses a single port number from a string.
 | |
| func parsePort(portStr string) (uint16, error) {
 | |
| 	port, err := strconv.Atoi(portStr)
 | |
| 	if err != nil {
 | |
| 		return 0, errors.New("invalid port number")
 | |
| 	}
 | |
| 
 | |
| 	if port < 0 || port > 65535 {
 | |
| 		return 0, errors.New("port number out of range")
 | |
| 	}
 | |
| 
 | |
| 	return uint16(port), nil
 | |
| }
 |