cmd/tailscale: allow overriding hostname in tailscale up
upf.BoolVar(&upArgs.shieldsUp, "shields-up", false, "don't allow incoming connections")
upf.StringVar(&upArgs.advertiseTags, "advertise-tags", "", "ACL tags to request (comma-separated, e.g. eng,montreal,ssh)")
upf.StringVar(&upArgs.authKey, "authkey", "", "node authorization key")
+ upf.StringVar(&upArgs.hostname, "hostname", "", "hostname to use instead of the one provided by the OS")
upf.BoolVar(&upArgs.enableDERP, "enable-derp", true, "enable the use of DERP servers")
if runtime.GOOS == "linux" || isBSD(runtime.GOOS) {
upf.StringVar(&upArgs.advertiseRoutes, "advertise-routes", "", "routes to advertise to other nodes (comma-separated, e.g. 10.0.0.0/8,192.168.0.0/24)")
snat bool
netfilterMode string
authKey string
+ hostname string
+}
+
+// validateHostname checks that name is a valid non-empty domain name label
+// pursuant to https://tools.ietf.org/html/rfc1034#section-3.1.
+func validateHostname(name string) error {
+ switch {
+ case len(name) == 0:
+ return fmt.Errorf("empty")
+ case len(name) > 63:
+ return fmt.Errorf("longer than 63 characters")
+ }
+
+ name = strings.ToLower(name)
+ first, last := name[0], name[len(name)-1]
+
+ // This is more obviously correct than using package unicode,
+ // though that can work too if we ensure that characters are below MaxASCII.
+ if !('a' <= first && first <= 'z') {
+ return fmt.Errorf("does not start with a letter")
+ }
+ if !(('a' <= last && last <= 'z') || ('0' <= last && last <= '9')) {
+ return fmt.Errorf("does not end with a letter or digit")
+ }
+ for i, c := range name {
+ if !(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || (c == '-')) {
+ return fmt.Errorf("[%d] = %c is not a letter, digit or hyphen", i, c)
+ }
+ }
+
+ return nil
}
// parseIPOrCIDR parses an IP address or a CIDR prefix. If the input
@@ -166,6 +198,10 @@ func runUp(ctx context.Context, args []string) error {
}
}
+ if err := validateHostname(upArgs.hostname); err != nil {
+ log.Fatalf("illegal hostname: %v", err)
+ }
+
// TODO(apenwarr): fix different semantics between prefs and uflags
// TODO(apenwarr): allow setting/using CorpDNS
prefs := ipn.NewPrefs()
@@ -178,6 +214,7 @@ func runUp(ctx context.Context, args []string) error {
prefs.AdvertiseTags = tags
prefs.NoSNAT = !upArgs.snat
prefs.DisableDERP = !upArgs.enableDERP
+ prefs.Hostname = upArgs.hostname
if runtime.GOOS == "linux" {
switch upArgs.netfilterMode {
case "on":
