ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Package cloudenv reports which known cloud environment we're running in.
|
|
|
|
package cloudenv
|
|
|
|
|
|
|
|
import (
|
2022-06-30 05:58:44 +00:00
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
2022-06-30 02:32:41 +00:00
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
2022-06-30 05:58:44 +00:00
|
|
|
"time"
|
2022-08-04 17:43:49 +00:00
|
|
|
|
|
|
|
"tailscale.com/syncs"
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
)
|
|
|
|
|
2022-06-30 05:58:44 +00:00
|
|
|
// CommonNonRoutableMetadataIP is the IP address of the metadata server
|
|
|
|
// on Amazon EC2, Google Compute Engine, and Azure. It's not routable.
|
|
|
|
// (169.254.0.0/16 is a Link Local range: RFC 3927)
|
|
|
|
const CommonNonRoutableMetadataIP = "169.254.169.254"
|
|
|
|
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
// GoogleMetadataAndDNSIP is the metadata IP used by Google Cloud.
|
|
|
|
// It's also the *.internal DNS server, and proxies to 8.8.8.8.
|
|
|
|
const GoogleMetadataAndDNSIP = "169.254.169.254"
|
|
|
|
|
2022-06-30 02:32:41 +00:00
|
|
|
// AWSResolverIP is the IP address of the AWS DNS server.
|
|
|
|
// See https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html
|
|
|
|
const AWSResolverIP = "169.254.169.253"
|
|
|
|
|
2022-06-30 05:58:44 +00:00
|
|
|
// AzureResolverIP is Azure's DNS resolver IP.
|
|
|
|
// See https://docs.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16
|
|
|
|
const AzureResolverIP = "168.63.129.16"
|
|
|
|
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
// Cloud is a recognize cloud environment with properties that
|
|
|
|
// Tailscale can specialize for in places.
|
|
|
|
type Cloud string
|
|
|
|
|
|
|
|
const (
|
2022-06-30 05:58:44 +00:00
|
|
|
AWS = Cloud("aws") // Amazon Web Services (EC2 in particular)
|
|
|
|
Azure = Cloud("azure") // Microsoft Azure
|
|
|
|
GCP = Cloud("gcp") // Google Cloud
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
)
|
|
|
|
|
2022-06-30 02:32:41 +00:00
|
|
|
// ResolverIP returns the cloud host's recursive DNS server or the
|
|
|
|
// empty string if not available.
|
|
|
|
func (c Cloud) ResolverIP() string {
|
|
|
|
switch c {
|
|
|
|
case GCP:
|
|
|
|
return GoogleMetadataAndDNSIP
|
|
|
|
case AWS:
|
|
|
|
return AWSResolverIP
|
2022-06-30 05:58:44 +00:00
|
|
|
case Azure:
|
|
|
|
return AzureResolverIP
|
2022-06-30 02:32:41 +00:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasInternalTLD reports whether c is a cloud environment
|
|
|
|
// whose ResolverIP serves *.internal records.
|
|
|
|
func (c Cloud) HasInternalTLD() bool {
|
|
|
|
switch c {
|
|
|
|
case GCP, AWS:
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-08-04 17:43:49 +00:00
|
|
|
var cloudAtomic syncs.AtomicValue[Cloud]
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
|
|
|
|
// Get returns the current cloud, or the empty string if unknown.
|
|
|
|
func Get() Cloud {
|
2022-08-04 17:43:49 +00:00
|
|
|
if c, ok := cloudAtomic.LoadOk(); ok {
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
return c
|
|
|
|
}
|
2022-08-04 17:43:49 +00:00
|
|
|
c := getCloud()
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
cloudAtomic.Store(c) // even if empty
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2022-06-30 05:58:44 +00:00
|
|
|
func readFileTrimmed(name string) string {
|
|
|
|
v, _ := os.ReadFile(name)
|
|
|
|
return strings.TrimSpace(string(v))
|
|
|
|
}
|
|
|
|
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
func getCloud() Cloud {
|
2022-06-30 05:58:44 +00:00
|
|
|
var hitMetadata bool
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "android", "ios", "darwin":
|
|
|
|
// Assume these aren't running on a cloud.
|
|
|
|
return ""
|
|
|
|
case "linux":
|
|
|
|
biosVendor := readFileTrimmed("/sys/class/dmi/id/bios_vendor")
|
2022-06-30 02:32:41 +00:00
|
|
|
if biosVendor == "Amazon EC2" || strings.HasSuffix(biosVendor, ".amazon") {
|
|
|
|
return AWS
|
|
|
|
}
|
2022-06-30 05:58:44 +00:00
|
|
|
|
|
|
|
prod := readFileTrimmed("/sys/class/dmi/id/product_name")
|
|
|
|
if prod == "Google Compute Engine" {
|
|
|
|
return GCP
|
|
|
|
}
|
|
|
|
if prod == "Google" { // old GCP VMs, it seems
|
|
|
|
hitMetadata = true
|
|
|
|
}
|
|
|
|
if prod == "Virtual Machine" || biosVendor == "Microsoft Corporation" {
|
|
|
|
// Azure, or maybe all Hyper-V?
|
|
|
|
hitMetadata = true
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// TODO(bradfitz): use Win32_SystemEnclosure from WMI or something on
|
|
|
|
// Windows to see if it's a physical machine and skip the cloud check
|
|
|
|
// early. Otherwise use similar clues as Linux about whether we should
|
|
|
|
// burn up to 2 seconds waiting for a metadata server that might not be
|
|
|
|
// there. And for BSDs, look where the /sys stuff is.
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if !hitMetadata {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
const maxWait = 2 * time.Second
|
|
|
|
tr := &http.Transport{
|
|
|
|
DisableKeepAlives: true,
|
|
|
|
Dial: (&net.Dialer{
|
|
|
|
Timeout: maxWait,
|
|
|
|
}).Dial,
|
2022-06-30 02:32:41 +00:00
|
|
|
}
|
2022-06-30 05:58:44 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), maxWait)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
// We want to hit CommonNonRoutableMetadataIP to see if we're on AWS, GCP,
|
|
|
|
// or Azure. All three (and many others) use the same metadata IP.
|
|
|
|
//
|
|
|
|
// But to avoid triggering the AWS CloudWatch "MetadataNoToken" metric (for which
|
|
|
|
// there might be an alert registered?), make our initial request be a token
|
|
|
|
// request. This only works on AWS, but the failing HTTP response on other clouds gives
|
|
|
|
// us enough clues about which cloud we're on.
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "PUT", "http://"+CommonNonRoutableMetadataIP+"/latest/api/token", strings.NewReader(""))
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("cloudenv: [unexpected] error creating request: %v", err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
req.Header.Set("X-Aws-Ec2-Metadata-Token-Ttl-Seconds", "5")
|
|
|
|
|
|
|
|
res, err := tr.RoundTrip(req)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
res.Body.Close()
|
|
|
|
if res.Header.Get("Metadata-Flavor") == "Google" {
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
return GCP
|
|
|
|
}
|
2022-06-30 05:58:44 +00:00
|
|
|
server := res.Header.Get("Server")
|
|
|
|
if server == "EC2ws" {
|
|
|
|
return AWS
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(server, "Microsoft") {
|
|
|
|
// e.g. "Microsoft-IIS/10.0"
|
|
|
|
req, _ := http.NewRequestWithContext(ctx, "GET", "http://"+CommonNonRoutableMetadataIP+"/metadata/instance/compute?api-version=2021-02-01", nil)
|
|
|
|
req.Header.Set("Metadata", "true")
|
|
|
|
res, err := tr.RoundTrip(req)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
var meta struct {
|
|
|
|
AzEnvironment string `json:"azEnvironment"`
|
|
|
|
}
|
|
|
|
if err := json.NewDecoder(res.Body).Decode(&meta); err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(meta.AzEnvironment, "Azure") {
|
|
|
|
return Azure
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
ipn/ipnlocal, net/dns*, util/cloudenv: specialize DNS config on Google Cloud
This does three things:
* If you're on GCP, it adds a *.internal DNS split route to the
metadata server, so we never break GCP DNS names. This lets people
have some Tailscale nodes on GCP and some not (e.g. laptops at home)
without having to add a Tailnet-wide *.internal DNS route.
If you already have such a route, though, it won't overwrite it.
* If the 100.100.100.100 DNS forwarder has nowhere to forward to,
it forwards it to the GCP metadata IP, which forwards to 8.8.8.8.
This means there are never errNoUpstreams ("upstream nameservers not set")
errors on GCP due to e.g. mangled /etc/resolv.conf (GCP default VMs
don't have systemd-resolved, so it's likely a DNS supremacy fight)
* makes the DNS fallback mechanism use the GCP metadata IP as a
fallback before our hosted HTTP-based fallbacks
I created a default GCP VM from their web wizard. It has no
systemd-resolved.
I then made its /etc/resolv.conf be empty and deleted its GCP
hostnames in /etc/hosts.
I then logged in to a tailnet with no global DNS settings.
With this, tailscaled writes /etc/resolv.conf (direct mode, as no
systemd-resolved) and sets it to 100.100.100.100, which then has
regular DNS via the metadata IP and *.internal DNS via the metadata IP
as well. If the tailnet configures explicit DNS servers, those are used
instead, except for *.internal.
This also adds a new util/cloudenv package based on version/distro
where the cloud type is only detected once. We'll likely expand it in
the future for other clouds, doing variants of this change for other
popular cloud environments.
Fixes #4911
RELNOTES=Google Cloud DNS improvements
Change-Id: I19f3c2075983669b2b2c0f29a548da8de373c7cf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-06-29 20:19:34 +00:00
|
|
|
// TODO: more, as needed.
|
|
|
|
return ""
|
|
|
|
}
|