Compare commits
2 Commits
mihaip/js-
...
Xe/gitops-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2716667c9d | ||
|
|
affa25097c |
5
.github/workflows/cross-wasm.yml
vendored
5
.github/workflows/cross-wasm.yml
vendored
@@ -31,11 +31,6 @@ jobs:
|
||||
GOARCH: wasm
|
||||
run: go build ./cmd/tsconnect/wasm
|
||||
|
||||
- name: tsconnect static build
|
||||
# Use our custom Go toolchain, we set build tags (to control binary size)
|
||||
# that depend on it.
|
||||
run: ./tool/go run ./cmd/tsconnect build
|
||||
|
||||
- uses: k0kubun/action-slack@v2.0.0
|
||||
with:
|
||||
payload: |
|
||||
|
||||
5
.github/workflows/linux.yml
vendored
5
.github/workflows/linux.yml
vendored
@@ -28,11 +28,6 @@ jobs:
|
||||
- name: Basic build
|
||||
run: go build ./cmd/...
|
||||
|
||||
- name: Build variants
|
||||
run: |
|
||||
go install --tags=ts_include_cli ./cmd/tailscaled
|
||||
go install --tags=ts_omit_aws ./cmd/tailscaled
|
||||
|
||||
- name: Get QEMU
|
||||
run: |
|
||||
# The qemu in Ubuntu 20.04 (Focal) is too old; we need 5.x something
|
||||
|
||||
3
.github/workflows/staticcheck.yml
vendored
3
.github/workflows/staticcheck.yml
vendored
@@ -21,9 +21,6 @@ jobs:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run gofmt (goimports)
|
||||
run: go run golang.org/x/tools/cmd/goimports -d --format-only .
|
||||
|
||||
- name: Run go vet
|
||||
run: go vet ./...
|
||||
|
||||
|
||||
@@ -45,25 +45,4 @@ EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
tags=""
|
||||
ldflags="-X tailscale.com/version.Long=${LONG} -X tailscale.com/version.Short=${SHORT} -X tailscale.com/version.GitCommit=${GIT_HASH}"
|
||||
|
||||
# build_dist.sh arguments must precede go build arguments.
|
||||
while [ "$#" -gt 1 ]; do
|
||||
case "$1" in
|
||||
--extra-small)
|
||||
shift
|
||||
ldflags="$ldflags -w -s"
|
||||
tags="${tags:+$tags,}ts_omit_aws"
|
||||
;;
|
||||
--box)
|
||||
shift
|
||||
tags="${tags:+$tags,}ts_include_cli"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
exec ./tool/go build ${tags:+-tags=$tags} -ldflags "$ldflags" "$@"
|
||||
exec ./tool/go build -ldflags "-X tailscale.com/version.Long=${LONG} -X tailscale.com/version.Short=${SHORT} -X tailscale.com/version.GitCommit=${GIT_HASH}" "$@"
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// ACLRow defines a rule that grants access by a set of users or groups to a set
|
||||
@@ -353,7 +354,7 @@ func (c *Client) PreviewACLForUser(ctx context.Context, acl ACL, user string) (r
|
||||
// Returns ACLPreview on success with matches in a slice. If there are no matches,
|
||||
// the call is still successful but Matches will be an empty slice.
|
||||
// Returns error if the provided ACL is invalid.
|
||||
func (c *Client) PreviewACLForIPPort(ctx context.Context, acl ACL, ipport netip.AddrPort) (res *ACLPreview, err error) {
|
||||
func (c *Client) PreviewACLForIPPort(ctx context.Context, acl ACL, ipport netaddr.IPPort) (res *ACLPreview, err error) {
|
||||
// Format return errors to be descriptive.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
@@ -29,6 +28,7 @@ import (
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
@@ -665,7 +665,7 @@ func (lc *LocalClient) ExpandSNIName(ctx context.Context, name string) (fqdn str
|
||||
|
||||
// Ping sends a ping of the provided type to the provided IP and waits
|
||||
// for its response.
|
||||
func (lc *LocalClient) Ping(ctx context.Context, ip netip.Addr, pingtype tailcfg.PingType) (*ipnstate.PingResult, error) {
|
||||
func (lc *LocalClient) Ping(ctx context.Context, ip netaddr.IP, pingtype tailcfg.PingType) (*ipnstate.PingResult, error) {
|
||||
v := url.Values{}
|
||||
v.Set("ip", ip.String())
|
||||
v.Set("type", string(pingtype))
|
||||
|
||||
@@ -13,14 +13,15 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// Routes contains the lists of subnet routes that are currently advertised by a device,
|
||||
// as well as the subnets that are enabled to be routed by the device.
|
||||
type Routes struct {
|
||||
AdvertisedRoutes []netip.Prefix `json:"advertisedRoutes"`
|
||||
EnabledRoutes []netip.Prefix `json:"enabledRoutes"`
|
||||
AdvertisedRoutes []netaddr.IPPrefix `json:"advertisedRoutes"`
|
||||
EnabledRoutes []netaddr.IPPrefix `json:"enabledRoutes"`
|
||||
}
|
||||
|
||||
// Routes retrieves the list of subnet routes that have been enabled for a device.
|
||||
@@ -55,14 +56,14 @@ func (c *Client) Routes(ctx context.Context, deviceID string) (routes *Routes, e
|
||||
}
|
||||
|
||||
type postRoutesParams struct {
|
||||
Routes []netip.Prefix `json:"routes"`
|
||||
Routes []netaddr.IPPrefix `json:"routes"`
|
||||
}
|
||||
|
||||
// SetRoutes updates the list of subnets that are enabled for a device.
|
||||
// Subnets must be parsable by net/netip.ParsePrefix.
|
||||
// Subnets must be parsable by inet.af/netaddr.ParseIPPrefix.
|
||||
// Subnets do not have to be currently advertised by a device, they may be pre-enabled.
|
||||
// Returns the updated list of enabled and advertised subnet routes in a *Routes object.
|
||||
func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netip.Prefix) (routes *Routes, err error) {
|
||||
func (c *Client) SetRoutes(ctx context.Context, deviceID string, subnets []netaddr.IPPrefix) (routes *Routes, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = fmt.Errorf("tailscale.SetRoutes: %w", err)
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/derp"
|
||||
"tailscale.com/derp/derphttp"
|
||||
"tailscale.com/logpolicy"
|
||||
"tailscale.com/metrics"
|
||||
"tailscale.com/net/stun"
|
||||
"tailscale.com/tsweb"
|
||||
@@ -36,15 +37,16 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
dev = flag.Bool("dev", false, "run in localhost development mode")
|
||||
addr = flag.String("a", ":443", "server HTTPS listen address, in form \":port\", \"ip:port\", or for IPv6 \"[ip]:port\". If the IP is omitted, it defaults to all interfaces.")
|
||||
httpPort = flag.Int("http-port", 80, "The port on which to serve HTTP. Set to -1 to disable. The listener is bound to the same IP (if any) as specified in the -a flag.")
|
||||
stunPort = flag.Int("stun-port", 3478, "The UDP port on which to serve STUN. The listener is bound to the same IP (if any) as specified in the -a flag.")
|
||||
configPath = flag.String("c", "", "config file path")
|
||||
certMode = flag.String("certmode", "letsencrypt", "mode for getting a cert. possible options: manual, letsencrypt")
|
||||
certDir = flag.String("certdir", tsweb.DefaultCertDir("derper-certs"), "directory to store LetsEncrypt certs, if addr's port is :443")
|
||||
hostname = flag.String("hostname", "derp.tailscale.com", "LetsEncrypt host name, if addr's port is :443")
|
||||
runSTUN = flag.Bool("stun", true, "whether to run a STUN server. It will bind to the same IP (if any) as the --addr flag value.")
|
||||
dev = flag.Bool("dev", false, "run in localhost development mode")
|
||||
addr = flag.String("a", ":443", "server HTTPS listen address, in form \":port\", \"ip:port\", or for IPv6 \"[ip]:port\". If the IP is omitted, it defaults to all interfaces.")
|
||||
httpPort = flag.Int("http-port", 80, "The port on which to serve HTTP. Set to -1 to disable. The listener is bound to the same IP (if any) as specified in the -a flag.")
|
||||
stunPort = flag.Int("stun-port", 3478, "The UDP port on which to serve STUN. The listener is bound to the same IP (if any) as specified in the -a flag.")
|
||||
configPath = flag.String("c", "", "config file path")
|
||||
certMode = flag.String("certmode", "letsencrypt", "mode for getting a cert. possible options: manual, letsencrypt")
|
||||
certDir = flag.String("certdir", tsweb.DefaultCertDir("derper-certs"), "directory to store LetsEncrypt certs, if addr's port is :443")
|
||||
hostname = flag.String("hostname", "derp.tailscale.com", "LetsEncrypt host name, if addr's port is :443")
|
||||
logCollection = flag.String("logcollection", "", "If non-empty, logtail collection to log to")
|
||||
runSTUN = flag.Bool("stun", true, "whether to run a STUN server. It will bind to the same IP (if any) as the --addr flag value.")
|
||||
|
||||
meshPSKFile = flag.String("mesh-psk-file", defaultMeshPSKFile(), "if non-empty, path to file containing the mesh pre-shared key file. It should contain some hex string; whitespace is trimmed.")
|
||||
meshWith = flag.String("mesh-with", "", "optional comma-separated list of hostnames to mesh with; the server's own hostname can be in the list")
|
||||
@@ -133,6 +135,7 @@ func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *dev {
|
||||
*logCollection = ""
|
||||
*addr = ":3340" // above the keys DERP
|
||||
log.Printf("Running in dev mode.")
|
||||
tsweb.DevMode = true
|
||||
@@ -143,6 +146,12 @@ func main() {
|
||||
log.Fatalf("invalid server address: %v", err)
|
||||
}
|
||||
|
||||
var logPol *logpolicy.Policy
|
||||
if *logCollection != "" {
|
||||
logPol = logpolicy.New(*logCollection)
|
||||
log.SetOutput(logPol.Logtail)
|
||||
}
|
||||
|
||||
cfg := loadConfig()
|
||||
|
||||
serveTLS := tsweb.IsProd443(*addr) || *certMode == "manual"
|
||||
|
||||
@@ -291,6 +291,12 @@ func testNewACLs(ctx context.Context, tailnet, apiKey, policyFname string) error
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
got := resp.StatusCode
|
||||
want := http.StatusOK
|
||||
if got != want {
|
||||
return fmt.Errorf("wanted HTTP status code %d but got %d", want, got)
|
||||
}
|
||||
|
||||
var ate ACLTestError
|
||||
err = json.NewDecoder(resp.Body).Decode(&ate)
|
||||
if err != nil {
|
||||
@@ -301,12 +307,6 @@ func testNewACLs(ctx context.Context, tailnet, apiKey, policyFname string) error
|
||||
return ate
|
||||
}
|
||||
|
||||
got := resp.StatusCode
|
||||
want := http.StatusOK
|
||||
if got != want {
|
||||
return fmt.Errorf("wanted HTTP status code %d but got %d", want, got)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -135,13 +135,13 @@ func tailscaleIP(who *apitype.WhoIsResponse) string {
|
||||
return ""
|
||||
}
|
||||
for _, nodeIP := range who.Node.Addresses {
|
||||
if nodeIP.Addr().Is4() && nodeIP.IsSingleIP() {
|
||||
return nodeIP.Addr().String()
|
||||
if nodeIP.IP().Is4() && nodeIP.IsSingleIP() {
|
||||
return nodeIP.IP().String()
|
||||
}
|
||||
}
|
||||
for _, nodeIP := range who.Node.Addresses {
|
||||
if nodeIP.IsSingleIP() {
|
||||
return nodeIP.Addr().String()
|
||||
return nodeIP.IP().String()
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
@@ -7,7 +7,6 @@ package cli
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
)
|
||||
@@ -32,6 +31,6 @@ func runBugReport(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(logMarker)
|
||||
outln(logMarker)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var certCmd = &ffcli.Command{
|
||||
ShortHelp: "get TLS certs",
|
||||
ShortUsage: "cert [flags] <domain>",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("cert", flag.ExitOnError)
|
||||
fs := newFlagSet("cert")
|
||||
fs.StringVar(&certArgs.certFile, "cert-file", "", "output cert file or \"-\" for stdout; defaults to DOMAIN.crt if --cert-file and --key-file are both unset")
|
||||
fs.StringVar(&certArgs.keyFile, "key-file", "", "output cert file or \"-\" for stdout; defaults to DOMAIN.key if --cert-file and --key-file are both unset")
|
||||
fs.BoolVar(&certArgs.serve, "serve-demo", false, "if true, serve on port :443 using the cert as a demo, instead of writing out the files to disk")
|
||||
@@ -79,7 +79,7 @@ func runCert(ctx context.Context, args []string) error {
|
||||
domain := args[0]
|
||||
|
||||
printf := func(format string, a ...any) {
|
||||
fmt.Printf(format, a...)
|
||||
printf(format, a...)
|
||||
}
|
||||
if certArgs.certFile == "-" || certArgs.keyFile == "-" {
|
||||
printf = log.Printf
|
||||
@@ -138,7 +138,7 @@ func runCert(ctx context.Context, args []string) error {
|
||||
|
||||
func writeIfChanged(filename string, contents []byte, mode os.FileMode) (changed bool, err error) {
|
||||
if filename == "-" {
|
||||
os.Stdout.Write(contents)
|
||||
Stdout.Write(contents)
|
||||
return false, nil
|
||||
}
|
||||
if old, err := os.ReadFile(filename); err == nil && bytes.Equal(contents, old) {
|
||||
|
||||
@@ -33,6 +33,22 @@ import (
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
var Stderr io.Writer = os.Stderr
|
||||
var Stdout io.Writer = os.Stdout
|
||||
|
||||
func printf(format string, a ...any) {
|
||||
fmt.Fprintf(Stdout, format, a...)
|
||||
}
|
||||
|
||||
// outln is like fmt.Println in the common case, except when Stdout is
|
||||
// changed (as in js/wasm).
|
||||
//
|
||||
// It's not named println because that looks like the Go built-in
|
||||
// which goes to stderr and formats slightly differently.
|
||||
func outln(a ...any) {
|
||||
fmt.Fprintln(Stdout, a...)
|
||||
}
|
||||
|
||||
// ActLikeCLI reports whether a GUI application should act like the
|
||||
// CLI based on os.Args, GOOS, the context the process is running in
|
||||
// (pty, parent PID), etc.
|
||||
@@ -79,6 +95,16 @@ func ActLikeCLI() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func newFlagSet(name string) *flag.FlagSet {
|
||||
onError := flag.ExitOnError
|
||||
if runtime.GOOS == "js" {
|
||||
onError = flag.ContinueOnError
|
||||
}
|
||||
fs := flag.NewFlagSet(name, onError)
|
||||
fs.SetOutput(Stderr)
|
||||
return fs
|
||||
}
|
||||
|
||||
// CleanUpArgs rewrites command line arguments for simplicity and backwards compatibility.
|
||||
// In particular, it rewrites --authkey to --auth-key.
|
||||
func CleanUpArgs(args []string) []string {
|
||||
@@ -112,11 +138,11 @@ func Run(args []string) (err error) {
|
||||
var warnOnce sync.Once
|
||||
tailscale.SetVersionMismatchHandler(func(clientVer, serverVer string) {
|
||||
warnOnce.Do(func() {
|
||||
fmt.Fprintf(os.Stderr, "Warning: client version %q != tailscaled server version %q\n", clientVer, serverVer)
|
||||
fmt.Fprintf(Stderr, "Warning: client version %q != tailscaled server version %q\n", clientVer, serverVer)
|
||||
})
|
||||
})
|
||||
|
||||
rootfs := flag.NewFlagSet("tailscale", flag.ExitOnError)
|
||||
rootfs := newFlagSet("tailscale")
|
||||
rootfs.StringVar(&rootArgs.socket, "socket", paths.DefaultTailscaledSocket(), "path to tailscaled's unix socket")
|
||||
|
||||
rootCmd := &ffcli.Command{
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/tstest"
|
||||
@@ -56,7 +56,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
flags []string // argv to be parsed by FlagSet
|
||||
curPrefs *ipn.Prefs
|
||||
|
||||
curExitNodeIP netip.Addr
|
||||
curExitNodeIP netaddr.IP
|
||||
curUser string // os.Getenv("USER") on the client side
|
||||
goos string // empty means "linux"
|
||||
distro distro.Distro
|
||||
@@ -152,10 +152,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.42.0/24"),
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.42.0/24"),
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
},
|
||||
want: accidentalUpPrefix + " --advertise-routes=10.0.42.0/24 --advertise-exit-node",
|
||||
@@ -168,10 +168,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.42.0/24"),
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.42.0/24"),
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
},
|
||||
want: "",
|
||||
@@ -184,10 +184,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.42.0/24"),
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.42.0/24"),
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
},
|
||||
want: "",
|
||||
@@ -212,8 +212,8 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("1.2.0.0/16"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("1.2.0.0/16"),
|
||||
},
|
||||
},
|
||||
want: accidentalUpPrefix + " --advertise-exit-node --advertise-routes=1.2.0.0/16",
|
||||
@@ -226,10 +226,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
netip.MustParsePrefix("1.2.0.0/16"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
netaddr.MustParseIPPrefix("1.2.0.0/16"),
|
||||
},
|
||||
},
|
||||
want: accidentalUpPrefix + " --advertise-exit-node --advertise-routes=1.2.0.0/16",
|
||||
@@ -255,16 +255,16 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
ControlURL: ipn.DefaultControlURL,
|
||||
RouteAll: true,
|
||||
AllowSingleHosts: false,
|
||||
ExitNodeIP: netip.MustParseAddr("100.64.5.6"),
|
||||
ExitNodeIP: netaddr.MustParseIP("100.64.5.6"),
|
||||
CorpDNS: false,
|
||||
ShieldsUp: true,
|
||||
AdvertiseTags: []string{"tag:foo", "tag:bar"},
|
||||
Hostname: "myhostname",
|
||||
ForceDaemon: true,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/16"),
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.0.0/16"),
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
NetfilterMode: preftype.NetfilterNoDivert,
|
||||
OperatorUser: "alice",
|
||||
@@ -280,14 +280,14 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
ControlURL: ipn.DefaultControlURL,
|
||||
RouteAll: true,
|
||||
AllowSingleHosts: false,
|
||||
ExitNodeIP: netip.MustParseAddr("100.64.5.6"),
|
||||
ExitNodeIP: netaddr.MustParseIP("100.64.5.6"),
|
||||
CorpDNS: false,
|
||||
ShieldsUp: true,
|
||||
AdvertiseTags: []string{"tag:foo", "tag:bar"},
|
||||
Hostname: "myhostname",
|
||||
ForceDaemon: true,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/16"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.0.0/16"),
|
||||
},
|
||||
NetfilterMode: preftype.NetfilterNoDivert,
|
||||
OperatorUser: "alice",
|
||||
@@ -344,10 +344,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
netip.MustParsePrefix("1.2.0.0/16"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
netaddr.MustParseIPPrefix("1.2.0.0/16"),
|
||||
},
|
||||
},
|
||||
want: accidentalUpPrefix + " --operator=expbits --advertise-exit-node --advertise-routes=1.2.0.0/16",
|
||||
@@ -360,10 +360,10 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
netip.MustParsePrefix("1.2.0.0/16"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
netaddr.MustParseIPPrefix("1.2.0.0/16"),
|
||||
},
|
||||
},
|
||||
want: accidentalUpPrefix + " --advertise-routes=1.2.0.0/16 --operator=expbits --advertise-exit-node",
|
||||
@@ -391,14 +391,14 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
CorpDNS: true,
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
|
||||
ExitNodeIP: netip.MustParseAddr("100.64.5.4"),
|
||||
ExitNodeIP: netaddr.MustParseIP("100.64.5.4"),
|
||||
},
|
||||
want: accidentalUpPrefix + " --hostname=foo --exit-node=100.64.5.4",
|
||||
},
|
||||
{
|
||||
name: "error_exit_node_omit_with_id_pref",
|
||||
flags: []string{"--hostname=foo"},
|
||||
curExitNodeIP: netip.MustParseAddr("100.64.5.7"),
|
||||
curExitNodeIP: netaddr.MustParseIP("100.64.5.7"),
|
||||
curPrefs: &ipn.Prefs{
|
||||
ControlURL: ipn.DefaultControlURL,
|
||||
AllowSingleHosts: true,
|
||||
@@ -412,7 +412,7 @@ func TestCheckForAccidentalSettingReverts(t *testing.T) {
|
||||
{
|
||||
name: "error_exit_node_and_allow_lan_omit_with_id_pref", // Isue 3480
|
||||
flags: []string{"--hostname=foo"},
|
||||
curExitNodeIP: netip.MustParseAddr("100.2.3.4"),
|
||||
curExitNodeIP: netaddr.MustParseIP("100.2.3.4"),
|
||||
curPrefs: &ipn.Prefs{
|
||||
ControlURL: ipn.DefaultControlURL,
|
||||
AllowSingleHosts: true,
|
||||
@@ -562,9 +562,9 @@ func TestPrefsFromUpArgs(t *testing.T) {
|
||||
WantRunning: true,
|
||||
AllowSingleHosts: true,
|
||||
CorpDNS: true,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
NetfilterMode: preftype.NetfilterOn,
|
||||
},
|
||||
@@ -631,7 +631,7 @@ func TestPrefsFromUpArgs(t *testing.T) {
|
||||
exitNodeIP: "100.105.106.107",
|
||||
},
|
||||
st: &ipnstate.Status{
|
||||
TailscaleIPs: []netip.Addr{netip.MustParseAddr("100.105.106.107")},
|
||||
TailscaleIPs: []netaddr.IP{netaddr.MustParseIP("100.105.106.107")},
|
||||
},
|
||||
wantErr: `cannot use 100.105.106.107 as an exit node as it is a local IP address to this machine; did you mean --advertise-exit-node?`,
|
||||
},
|
||||
@@ -671,8 +671,8 @@ func TestPrefsFromUpArgs(t *testing.T) {
|
||||
want: &ipn.Prefs{
|
||||
WantRunning: true,
|
||||
NoSNAT: true,
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("fd7a:115c:a1e0:b1a::bb:10.0.0.0/112"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -956,7 +956,7 @@ func TestUpdatePrefs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var cmpIP = cmp.Comparer(func(a, b netip.Addr) bool {
|
||||
var cmpIP = cmp.Comparer(func(a, b netaddr.IP) bool {
|
||||
return a == b
|
||||
})
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ permission to use it.
|
||||
See: https://tailscale.com/kb/1152/synology-outbound/
|
||||
`),
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("configure-host", flag.ExitOnError)
|
||||
fs := newFlagSet("configure-host")
|
||||
return fs
|
||||
})(),
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@@ -25,6 +24,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/control/controlhttp"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
@@ -40,7 +40,7 @@ var debugCmd = &ffcli.Command{
|
||||
Exec: runDebug,
|
||||
LongHelp: `"tailscale debug" contains misc debug facilities; it is not a stable interface.`,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("debug", flag.ExitOnError)
|
||||
fs := newFlagSet("debug")
|
||||
fs.StringVar(&debugArgs.file, "file", "", "get, delete:NAME, or NAME")
|
||||
fs.StringVar(&debugArgs.cpuFile, "cpu-profile", "", "if non-empty, grab a CPU profile for --profile-sec seconds and write it to this file; - for stdout")
|
||||
fs.StringVar(&debugArgs.memFile, "mem-profile", "", "if non-empty, grab a memory profile and write it to this file; - for stdout")
|
||||
@@ -63,7 +63,7 @@ var debugCmd = &ffcli.Command{
|
||||
Exec: runDaemonMetrics,
|
||||
ShortHelp: "print tailscaled's metrics",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("metrics", flag.ExitOnError)
|
||||
fs := newFlagSet("metrics")
|
||||
fs.BoolVar(&metricsArgs.watch, "watch", false, "print JSON dump of delta values")
|
||||
return fs
|
||||
})(),
|
||||
@@ -103,7 +103,7 @@ var debugCmd = &ffcli.Command{
|
||||
Exec: runPrefs,
|
||||
ShortHelp: "print prefs",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("prefs", flag.ExitOnError)
|
||||
fs := newFlagSet("prefs")
|
||||
fs.BoolVar(&prefsArgs.pretty, "pretty", false, "If true, pretty-print output")
|
||||
return fs
|
||||
})(),
|
||||
@@ -113,7 +113,7 @@ var debugCmd = &ffcli.Command{
|
||||
Exec: runWatchIPN,
|
||||
ShortHelp: "subscribe to IPN message bus",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("watch-ipn", flag.ExitOnError)
|
||||
fs := newFlagSet("watch-ipn")
|
||||
fs.BoolVar(&watchIPNArgs.netmap, "netmap", true, "include netmap in messages")
|
||||
return fs
|
||||
})(),
|
||||
@@ -128,7 +128,7 @@ var debugCmd = &ffcli.Command{
|
||||
Exec: runTS2021,
|
||||
ShortHelp: "debug ts2021 protocol connectivity",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("ts2021", flag.ExitOnError)
|
||||
fs := newFlagSet("ts2021")
|
||||
fs.StringVar(&ts2021Args.host, "host", "controlplane.tailscale.com", "hostname of control plane")
|
||||
fs.IntVar(&ts2021Args.version, "version", int(tailcfg.CurrentCapabilityVersion), "protocol version")
|
||||
return fs
|
||||
@@ -146,7 +146,7 @@ var debugArgs struct {
|
||||
|
||||
func writeProfile(dst string, v []byte) error {
|
||||
if dst == "-" {
|
||||
_, err := os.Stdout.Write(v)
|
||||
_, err := Stdout.Write(v)
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(dst, v, 0600)
|
||||
@@ -198,7 +198,7 @@ func runDebug(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
fatalf("%v\n", err)
|
||||
}
|
||||
e := json.NewEncoder(os.Stdout)
|
||||
e := json.NewEncoder(Stdout)
|
||||
e.SetIndent("", "\t")
|
||||
e.Encode(wfs)
|
||||
return nil
|
||||
@@ -212,7 +212,7 @@ func runDebug(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
log.Printf("Size: %v\n", size)
|
||||
io.Copy(os.Stdout, rc)
|
||||
io.Copy(Stdout, rc)
|
||||
return nil
|
||||
}
|
||||
if usedFlag {
|
||||
@@ -226,14 +226,14 @@ func runDebug(ctx context.Context, args []string) error {
|
||||
func runLocalCreds(ctx context.Context, args []string) error {
|
||||
port, token, err := safesocket.LocalTCPPortAndToken()
|
||||
if err == nil {
|
||||
fmt.Printf("curl -u:%s http://localhost:%d/localapi/v0/status\n", token, port)
|
||||
printf("curl -u:%s http://localhost:%d/localapi/v0/status\n", token, port)
|
||||
return nil
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
fmt.Printf("curl http://localhost:%v/localapi/v0/status\n", safesocket.WindowsLocalPort)
|
||||
printf("curl http://localhost:%v/localapi/v0/status\n", safesocket.WindowsLocalPort)
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("curl --unix-socket %s http://foo/localapi/v0/status\n", paths.DefaultTailscaledSocket())
|
||||
printf("curl --unix-socket %s http://foo/localapi/v0/status\n", paths.DefaultTailscaledSocket())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -247,10 +247,10 @@ func runPrefs(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
if prefsArgs.pretty {
|
||||
fmt.Println(prefs.Pretty())
|
||||
outln(prefs.Pretty())
|
||||
} else {
|
||||
j, _ := json.MarshalIndent(prefs, "", "\t")
|
||||
fmt.Println(string(j))
|
||||
outln(string(j))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -268,7 +268,7 @@ func runWatchIPN(ctx context.Context, args []string) error {
|
||||
n.NetMap = nil
|
||||
}
|
||||
j, _ := json.MarshalIndent(n, "", "\t")
|
||||
fmt.Printf("%s\n", j)
|
||||
printf("%s\n", j)
|
||||
})
|
||||
bc.RequestEngineStatus()
|
||||
pump(ctx, bc, c)
|
||||
@@ -282,7 +282,7 @@ func runDERPMap(ctx context.Context, args []string) error {
|
||||
"failed to get local derp map, instead `curl %s/derpmap/default`: %w", ipn.DefaultControlURL, err,
|
||||
)
|
||||
}
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc := json.NewEncoder(Stdout)
|
||||
enc.SetIndent("", "\t")
|
||||
enc.Encode(dm)
|
||||
return nil
|
||||
@@ -299,7 +299,7 @@ func localAPIAction(action string) func(context.Context, []string) error {
|
||||
|
||||
func runEnv(ctx context.Context, args []string) error {
|
||||
for _, e := range os.Environ() {
|
||||
fmt.Println(e)
|
||||
outln(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -338,7 +338,7 @@ func runDaemonGoroutines(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Stdout.Write(goroutines)
|
||||
Stdout.Write(goroutines)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func runDaemonMetrics(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
if !metricsArgs.watch {
|
||||
os.Stdout.Write(out)
|
||||
Stdout.Write(out)
|
||||
return nil
|
||||
}
|
||||
bs := bufio.NewScanner(bytes.NewReader(out))
|
||||
@@ -391,9 +391,9 @@ func runDaemonMetrics(ctx context.Context, args []string) error {
|
||||
if len(changes) > 0 {
|
||||
format := fmt.Sprintf("%%-%ds %%+5d => %%v\n", maxNameLen)
|
||||
for _, c := range changes {
|
||||
fmt.Fprintf(os.Stdout, format, c.name, c.to-c.from, c.to)
|
||||
fmt.Fprintf(Stdout, format, c.name, c.to-c.from, c.to)
|
||||
}
|
||||
io.WriteString(os.Stdout, "\n")
|
||||
io.WriteString(Stdout, "\n")
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
@@ -404,23 +404,23 @@ func runVia(ctx context.Context, args []string) error {
|
||||
default:
|
||||
return errors.New("expect either <site-id> <v4-cidr> or <v6-route>")
|
||||
case 1:
|
||||
ipp, err := netip.ParsePrefix(args[0])
|
||||
ipp, err := netaddr.ParseIPPrefix(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ipp.Addr().Is6() {
|
||||
if !ipp.IP().Is6() {
|
||||
return errors.New("with one argument, expect an IPv6 CIDR")
|
||||
}
|
||||
if !tsaddr.TailscaleViaRange().Contains(ipp.Addr()) {
|
||||
if !tsaddr.TailscaleViaRange().Contains(ipp.IP()) {
|
||||
return errors.New("not a via route")
|
||||
}
|
||||
if ipp.Bits() < 96 {
|
||||
return errors.New("short length, want /96 or more")
|
||||
}
|
||||
v4 := tsaddr.UnmapVia(ipp.Addr())
|
||||
a := ipp.Addr().As16()
|
||||
v4 := tsaddr.UnmapVia(ipp.IP())
|
||||
a := ipp.IP().As16()
|
||||
siteID := binary.BigEndian.Uint32(a[8:12])
|
||||
fmt.Printf("site %v (0x%x), %v\n", siteID, siteID, netip.PrefixFrom(v4, ipp.Bits()-96))
|
||||
fmt.Printf("site %v (0x%x), %v\n", siteID, siteID, netaddr.IPPrefixFrom(v4, ipp.Bits()-96))
|
||||
case 2:
|
||||
siteID, err := strconv.ParseUint(args[0], 0, 32)
|
||||
if err != nil {
|
||||
@@ -429,7 +429,7 @@ func runVia(ctx context.Context, args []string) error {
|
||||
if siteID > 0xff {
|
||||
return fmt.Errorf("site-id values over 255 are currently reserved")
|
||||
}
|
||||
ipp, err := netip.ParsePrefix(args[1])
|
||||
ipp, err := netaddr.ParseIPPrefix(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"tailscale.com/ipn"
|
||||
@@ -24,7 +23,7 @@ var downCmd = &ffcli.Command{
|
||||
}
|
||||
|
||||
func newDownFlagSet() *flag.FlagSet {
|
||||
downf := flag.NewFlagSet("down", flag.ExitOnError)
|
||||
downf := newFlagSet("down")
|
||||
registerAcceptRiskFlag(downf)
|
||||
return downf
|
||||
}
|
||||
@@ -45,7 +44,7 @@ func runDown(ctx context.Context, args []string) error {
|
||||
return fmt.Errorf("error fetching current status: %w", err)
|
||||
}
|
||||
if st.BackendState == "Stopped" {
|
||||
fmt.Fprintf(os.Stderr, "Tailscale was already stopped.\n")
|
||||
fmt.Fprintf(Stderr, "Tailscale was already stopped.\n")
|
||||
return nil
|
||||
}
|
||||
_, err = localClient.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -24,6 +23,7 @@ import (
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"golang.org/x/time/rate"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn"
|
||||
@@ -54,7 +54,7 @@ var fileCpCmd = &ffcli.Command{
|
||||
ShortHelp: "Copy file(s) to a host",
|
||||
Exec: runCp,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("cp", flag.ExitOnError)
|
||||
fs := newFlagSet("cp")
|
||||
fs.StringVar(&cpArgs.name, "name", "", "alternate filename to use, especially useful when <file> is \"-\" (stdin)")
|
||||
fs.BoolVar(&cpArgs.verbose, "verbose", false, "verbose output")
|
||||
fs.BoolVar(&cpArgs.targets, "targets", false, "list possible file cp targets")
|
||||
@@ -85,7 +85,7 @@ func runCp(ctx context.Context, args []string) error {
|
||||
hadBrackets = true
|
||||
target = strings.TrimSuffix(strings.TrimPrefix(target, "["), "]")
|
||||
}
|
||||
if ip, err := netip.ParseAddr(target); err == nil && ip.Is6() && !hadBrackets {
|
||||
if ip, err := netaddr.ParseIP(target); err == nil && ip.Is6() && !hadBrackets {
|
||||
return fmt.Errorf("an IPv6 literal must be written as [%s]", ip)
|
||||
} else if hadBrackets && (err != nil || !ip.Is6()) {
|
||||
return errors.New("unexpected brackets around target")
|
||||
@@ -100,7 +100,7 @@ func runCp(ctx context.Context, args []string) error {
|
||||
return fmt.Errorf("can't send to %s: %v", target, err)
|
||||
}
|
||||
if isOffline {
|
||||
fmt.Fprintf(os.Stderr, "# warning: %s is offline\n", target)
|
||||
fmt.Fprintf(Stderr, "# warning: %s is offline\n", target)
|
||||
}
|
||||
|
||||
if len(files) > 1 {
|
||||
@@ -168,7 +168,7 @@ func runCp(ctx context.Context, args []string) error {
|
||||
}
|
||||
|
||||
func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNodeID, isOffline bool, err error) {
|
||||
ip, err := netip.ParseAddr(ipStr)
|
||||
ip, err := netaddr.ParseIP(ipStr)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
@@ -179,7 +179,7 @@ func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNode
|
||||
for _, ft := range fts {
|
||||
n := ft.Node
|
||||
for _, a := range n.Addresses {
|
||||
if a.Addr() != ip {
|
||||
if a.IP() != ip {
|
||||
continue
|
||||
}
|
||||
isOffline = n.Online != nil && !*n.Online
|
||||
@@ -191,7 +191,7 @@ func getTargetStableID(ctx context.Context, ipStr string) (id tailcfg.StableNode
|
||||
|
||||
// fileTargetErrorDetail returns a non-nil error saying why ip is an
|
||||
// invalid file sharing target.
|
||||
func fileTargetErrorDetail(ctx context.Context, ip netip.Addr) error {
|
||||
func fileTargetErrorDetail(ctx context.Context, ip netaddr.IP) error {
|
||||
found := false
|
||||
if st, err := localClient.Status(ctx); err == nil && st.Self != nil {
|
||||
for _, peer := range st.Peer {
|
||||
@@ -281,7 +281,7 @@ func runCpTargets(ctx context.Context, args []string) error {
|
||||
if detail != "" {
|
||||
detail = "\t" + detail
|
||||
}
|
||||
fmt.Printf("%s\t%s%s\n", n.Addresses[0].Addr(), n.ComputedName, detail)
|
||||
printf("%s\t%s%s\n", n.Addresses[0].IP(), n.ComputedName, detail)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -315,7 +315,7 @@ var fileGetCmd = &ffcli.Command{
|
||||
ShortHelp: "Move files out of the Tailscale file inbox",
|
||||
Exec: runFileGet,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("get", flag.ExitOnError)
|
||||
fs := newFlagSet("get")
|
||||
fs.BoolVar(&getArgs.wait, "wait", false, "wait for a file to arrive if inbox is empty")
|
||||
fs.BoolVar(&getArgs.loop, "loop", false, "run get in a loop, receiving files as they come in")
|
||||
fs.BoolVar(&getArgs.verbose, "verbose", false, "verbose output")
|
||||
@@ -415,7 +415,7 @@ func runFileGetOneBatch(ctx context.Context, dir string) []error {
|
||||
break
|
||||
}
|
||||
if getArgs.verbose {
|
||||
fmt.Printf("waiting for file...")
|
||||
printf("waiting for file...")
|
||||
}
|
||||
if err := waitForFile(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
@@ -436,7 +436,7 @@ func runFileGetOneBatch(ctx context.Context, dir string) []error {
|
||||
continue
|
||||
}
|
||||
if getArgs.verbose {
|
||||
fmt.Printf("wrote %v as %v (%d bytes)\n", wf.Name, writtenFile, size)
|
||||
printf("wrote %v as %v (%d bytes)\n", wf.Name, writtenFile, size)
|
||||
}
|
||||
if err = localClient.DeleteWaitingFile(ctx, wf.Name); err != nil {
|
||||
errs = append(errs, fmt.Errorf("deleting %q from inbox: %v", wf.Name, err))
|
||||
@@ -448,7 +448,7 @@ func runFileGetOneBatch(ctx context.Context, dir string) []error {
|
||||
// persistently stuck files are basically an error
|
||||
errs = append(errs, fmt.Errorf("moved %d/%d files", deleted, len(wfs)))
|
||||
} else if getArgs.verbose {
|
||||
fmt.Printf("moved %d/%d files\n", deleted, len(wfs))
|
||||
printf("moved %d/%d files\n", deleted, len(wfs))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
@@ -471,7 +471,7 @@ func runFileGet(ctx context.Context, args []string) error {
|
||||
for {
|
||||
errs := runFileGetOneBatch(ctx, dir)
|
||||
for _, err := range errs {
|
||||
fmt.Println(err)
|
||||
outln(err)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
// It's possible whatever caused the error(s) (e.g. conflicting target file,
|
||||
@@ -493,7 +493,7 @@ func runFileGet(ctx context.Context, args []string) error {
|
||||
return nil
|
||||
}
|
||||
for _, err := range errs[:len(errs)-1] {
|
||||
fmt.Println(err)
|
||||
outln(err)
|
||||
}
|
||||
return errs[len(errs)-1]
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ var ipCmd = &ffcli.Command{
|
||||
LongHelp: "Show Tailscale IP addresses for peer. Peer defaults to the current machine.",
|
||||
Exec: runIP,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("ip", flag.ExitOnError)
|
||||
fs := newFlagSet("ip")
|
||||
fs.BoolVar(&ipArgs.want1, "1", false, "only print one IP address")
|
||||
fs.BoolVar(&ipArgs.want4, "4", false, "only print IPv4 address")
|
||||
fs.BoolVar(&ipArgs.want6, "6", false, "only print IPv6 address")
|
||||
@@ -85,7 +85,7 @@ func runIP(ctx context.Context, args []string) error {
|
||||
for _, ip := range ips {
|
||||
if ip.Is4() && v4 || ip.Is6() && v6 {
|
||||
match = true
|
||||
fmt.Println(ip)
|
||||
outln(ip)
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
@@ -100,7 +100,7 @@ func runIP(ctx context.Context, args []string) error {
|
||||
}
|
||||
|
||||
func peerMatchingIP(st *ipnstate.Status, ipStr string) (ps *ipnstate.PeerStatus, ok bool) {
|
||||
ip, err := netip.ParseAddr(ipStr)
|
||||
ip, err := netaddr.ParseIP(ipStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func runNC(ctx context.Context, args []string) error {
|
||||
}
|
||||
description, ok := isRunningOrStarting(st)
|
||||
if !ok {
|
||||
fmt.Printf("%s\n", description)
|
||||
printf("%s\n", description)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -33,7 +32,7 @@ var netcheckCmd = &ffcli.Command{
|
||||
ShortHelp: "Print an analysis of local network conditions",
|
||||
Exec: runNetcheck,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("netcheck", flag.ExitOnError)
|
||||
fs := newFlagSet("netcheck")
|
||||
fs.StringVar(&netcheckArgs.format, "format", "", `output format; empty (for human-readable), "json" or "json-line"`)
|
||||
fs.DurationVar(&netcheckArgs.every, "every", 0, "if non-zero, do an incremental report with the given frequency")
|
||||
fs.BoolVar(&netcheckArgs.verbose, "verbose", false, "verbose logs")
|
||||
@@ -60,7 +59,7 @@ func runNetcheck(ctx context.Context, args []string) error {
|
||||
}
|
||||
|
||||
if strings.HasPrefix(netcheckArgs.format, "json") {
|
||||
fmt.Fprintln(os.Stderr, "# Warning: this JSON format is not yet considered a stable interface")
|
||||
fmt.Fprintln(Stderr, "# Warning: this JSON format is not yet considered a stable interface")
|
||||
}
|
||||
|
||||
dm, err := localClient.CurrentDERPMap(ctx)
|
||||
@@ -112,38 +111,38 @@ func printReport(dm *tailcfg.DERPMap, report *netcheck.Report) error {
|
||||
}
|
||||
if j != nil {
|
||||
j = append(j, '\n')
|
||||
os.Stdout.Write(j)
|
||||
Stdout.Write(j)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("\nReport:\n")
|
||||
fmt.Printf("\t* UDP: %v\n", report.UDP)
|
||||
printf("\nReport:\n")
|
||||
printf("\t* UDP: %v\n", report.UDP)
|
||||
if report.GlobalV4 != "" {
|
||||
fmt.Printf("\t* IPv4: yes, %v\n", report.GlobalV4)
|
||||
printf("\t* IPv4: yes, %v\n", report.GlobalV4)
|
||||
} else {
|
||||
fmt.Printf("\t* IPv4: (no addr found)\n")
|
||||
printf("\t* IPv4: (no addr found)\n")
|
||||
}
|
||||
if report.GlobalV6 != "" {
|
||||
fmt.Printf("\t* IPv6: yes, %v\n", report.GlobalV6)
|
||||
printf("\t* IPv6: yes, %v\n", report.GlobalV6)
|
||||
} else if report.IPv6 {
|
||||
fmt.Printf("\t* IPv6: (no addr found)\n")
|
||||
printf("\t* IPv6: (no addr found)\n")
|
||||
} else if report.OSHasIPv6 {
|
||||
fmt.Printf("\t* IPv6: no, but OS has support\n")
|
||||
printf("\t* IPv6: no, but OS has support\n")
|
||||
} else {
|
||||
fmt.Printf("\t* IPv6: no, unavailable in OS\n")
|
||||
printf("\t* IPv6: no, unavailable in OS\n")
|
||||
}
|
||||
fmt.Printf("\t* MappingVariesByDestIP: %v\n", report.MappingVariesByDestIP)
|
||||
fmt.Printf("\t* HairPinning: %v\n", report.HairPinning)
|
||||
fmt.Printf("\t* PortMapping: %v\n", portMapping(report))
|
||||
printf("\t* MappingVariesByDestIP: %v\n", report.MappingVariesByDestIP)
|
||||
printf("\t* HairPinning: %v\n", report.HairPinning)
|
||||
printf("\t* PortMapping: %v\n", portMapping(report))
|
||||
|
||||
// When DERP latency checking failed,
|
||||
// magicsock will try to pick the DERP server that
|
||||
// most of your other nodes are also using
|
||||
if len(report.RegionLatency) == 0 {
|
||||
fmt.Printf("\t* Nearest DERP: unknown (no response to latency probes)\n")
|
||||
printf("\t* Nearest DERP: unknown (no response to latency probes)\n")
|
||||
} else {
|
||||
fmt.Printf("\t* Nearest DERP: %v\n", dm.Regions[report.PreferredDERP].RegionName)
|
||||
fmt.Printf("\t* DERP latency:\n")
|
||||
printf("\t* Nearest DERP: %v\n", dm.Regions[report.PreferredDERP].RegionName)
|
||||
printf("\t* DERP latency:\n")
|
||||
var rids []int
|
||||
for rid := range dm.Regions {
|
||||
rids = append(rids, rid)
|
||||
@@ -170,7 +169,7 @@ func printReport(dm *tailcfg.DERPMap, report *netcheck.Report) error {
|
||||
if netcheckArgs.verbose {
|
||||
derpNum = fmt.Sprintf("derp%d, ", rid)
|
||||
}
|
||||
fmt.Printf("\t\t- %3s: %-7s (%s%s)\n", r.RegionCode, latency, derpNum, r.RegionName)
|
||||
printf("\t\t- %3s: %-7s (%s%s)\n", r.RegionCode, latency, derpNum, r.RegionName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -11,12 +11,12 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
@@ -46,7 +46,7 @@ relay node.
|
||||
`),
|
||||
Exec: runPing,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("ping", flag.ExitOnError)
|
||||
fs := newFlagSet("ping")
|
||||
fs.BoolVar(&pingArgs.verbose, "verbose", false, "verbose output")
|
||||
fs.BoolVar(&pingArgs.untilDirect, "until-direct", true, "stop once a direct path is established")
|
||||
fs.BoolVar(&pingArgs.tsmp, "tsmp", false, "do a TSMP-level ping (through WireGuard, but not either host OS stack)")
|
||||
@@ -88,7 +88,7 @@ func runPing(ctx context.Context, args []string) error {
|
||||
}
|
||||
description, ok := isRunningOrStarting(st)
|
||||
if !ok {
|
||||
fmt.Printf("%s\n", description)
|
||||
printf("%s\n", description)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func runPing(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
if self {
|
||||
fmt.Printf("%v is local Tailscale IP\n", ip)
|
||||
printf("%v is local Tailscale IP\n", ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -116,11 +116,11 @@ func runPing(ctx context.Context, args []string) error {
|
||||
for {
|
||||
n++
|
||||
ctx, cancel := context.WithTimeout(ctx, pingArgs.timeout)
|
||||
pr, err := localClient.Ping(ctx, netip.MustParseAddr(ip), pingType())
|
||||
pr, err := localClient.Ping(ctx, netaddr.MustParseIP(ip), pingType())
|
||||
cancel()
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
fmt.Printf("ping %q timed out\n", ip)
|
||||
printf("ping %q timed out\n", ip)
|
||||
if n == pingArgs.num {
|
||||
if !anyPong {
|
||||
return errors.New("no reply")
|
||||
@@ -133,7 +133,7 @@ func runPing(ctx context.Context, args []string) error {
|
||||
}
|
||||
if pr.Err != "" {
|
||||
if pr.IsLocalIP {
|
||||
fmt.Println(pr.Err)
|
||||
outln(pr.Err)
|
||||
return nil
|
||||
}
|
||||
return errors.New(pr.Err)
|
||||
@@ -149,7 +149,7 @@ func runPing(ctx context.Context, args []string) error {
|
||||
via = string(pingType())
|
||||
}
|
||||
if pingArgs.peerAPI {
|
||||
fmt.Printf("hit peerapi of %s (%s) at %s in %s\n", pr.NodeIP, pr.NodeName, pr.PeerAPIURL, latency)
|
||||
printf("hit peerapi of %s (%s) at %s in %s\n", pr.NodeIP, pr.NodeName, pr.PeerAPIURL, latency)
|
||||
return nil
|
||||
}
|
||||
anyPong = true
|
||||
@@ -157,7 +157,7 @@ func runPing(ctx context.Context, args []string) error {
|
||||
if pr.PeerAPIPort != 0 {
|
||||
extra = fmt.Sprintf(", %d", pr.PeerAPIPort)
|
||||
}
|
||||
fmt.Printf("pong from %s (%s%s) via %v in %v\n", pr.NodeName, pr.NodeIP, extra, via, latency)
|
||||
printf("pong from %s (%s%s) via %v in %v\n", pr.NodeName, pr.NodeIP, extra, via, latency)
|
||||
if pingArgs.tsmp || pingArgs.icmp {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
@@ -18,6 +17,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/tsaddr"
|
||||
@@ -163,10 +163,10 @@ func nodeDNSNameFromArg(st *ipnstate.Status, arg string) (dnsName string, ok boo
|
||||
if arg == "" {
|
||||
return
|
||||
}
|
||||
argIP, _ := netip.ParseAddr(arg)
|
||||
argIP, _ := netaddr.ParseIP(arg)
|
||||
for _, ps := range st.Peer {
|
||||
dnsName = ps.DNSName
|
||||
if argIP.IsValid() {
|
||||
if !argIP.IsZero() {
|
||||
for _, ip := range ps.TailscaleIPs {
|
||||
if ip == argIP {
|
||||
return dnsName, true
|
||||
@@ -202,7 +202,7 @@ func isSSHOverTailscale() bool {
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
ip, err := netip.ParseAddr(ipStr)
|
||||
ip, err := netaddr.ParseIP(ipStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
//go:build !js && !windows
|
||||
// +build !js,!windows
|
||||
|
||||
package cli
|
||||
|
||||
|
||||
17
cmd/tailscale/cli/ssh_exec_js.go
Normal file
17
cmd/tailscale/cli/ssh_exec_js.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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 cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func findSSH() (string, error) {
|
||||
return "", errors.New("Not implemented")
|
||||
}
|
||||
|
||||
func execSSH(ssh string, argv []string) error {
|
||||
return errors.New("Not implemented")
|
||||
}
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"github.com/toqueteos/webbrowser"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/interfaces"
|
||||
@@ -46,7 +46,7 @@ https://github.com/tailscale/tailscale/blob/main/ipn/ipnstate/ipnstate.go
|
||||
`),
|
||||
Exec: runStatus,
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("status", flag.ExitOnError)
|
||||
fs := newFlagSet("status")
|
||||
fs.BoolVar(&statusArgs.json, "json", false, "output in JSON format (WARNING: format subject to change)")
|
||||
fs.BoolVar(&statusArgs.web, "web", false, "run webserver with HTML showing status")
|
||||
fs.BoolVar(&statusArgs.active, "active", false, "filter output to only peers with active sessions (not applicable to web mode)")
|
||||
@@ -92,7 +92,7 @@ func runStatus(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s", j)
|
||||
printf("%s", j)
|
||||
return nil
|
||||
}
|
||||
if statusArgs.web {
|
||||
@@ -101,7 +101,7 @@ func runStatus(ctx context.Context, args []string) error {
|
||||
return err
|
||||
}
|
||||
statusURL := interfaces.HTTPOfListener(ln)
|
||||
fmt.Printf("Serving Tailscale status at %v ...\n", statusURL)
|
||||
printf("Serving Tailscale status at %v ...\n", statusURL)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
ln.Close()
|
||||
@@ -131,16 +131,16 @@ func runStatus(ctx context.Context, args []string) error {
|
||||
// print health check information prior to checking LocalBackend state as
|
||||
// it may provide an explanation to the user if we choose to exit early
|
||||
if len(st.Health) > 0 {
|
||||
fmt.Printf("# Health check:\n")
|
||||
printf("# Health check:\n")
|
||||
for _, m := range st.Health {
|
||||
fmt.Printf("# - %s\n", m)
|
||||
printf("# - %s\n", m)
|
||||
}
|
||||
fmt.Println()
|
||||
outln()
|
||||
}
|
||||
|
||||
description, ok := isRunningOrStarting(st)
|
||||
if !ok {
|
||||
fmt.Println(description)
|
||||
outln(description)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ func runStatus(ctx context.Context, args []string) error {
|
||||
printPS(ps)
|
||||
}
|
||||
}
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
Stdout.Write(buf.Bytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ func ownerLogin(st *ipnstate.Status, ps *ipnstate.PeerStatus) string {
|
||||
return u.LoginName
|
||||
}
|
||||
|
||||
func firstIPString(v []netip.Addr) string {
|
||||
func firstIPString(v []netaddr.IP) string {
|
||||
if len(v) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -25,6 +24,7 @@ import (
|
||||
shellquote "github.com/kballard/go-shellquote"
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
qrcode "github.com/skip2/go-qrcode"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/tsaddr"
|
||||
@@ -85,7 +85,7 @@ var upFlagSet = newUpFlagSet(effectiveGOOS(), &upArgs)
|
||||
func inTest() bool { return flag.Lookup("test.v") != nil }
|
||||
|
||||
func newUpFlagSet(goos string, upArgs *upArgsT) *flag.FlagSet {
|
||||
upf := flag.NewFlagSet("up", flag.ExitOnError)
|
||||
upf := newFlagSet("up")
|
||||
|
||||
upf.BoolVar(&upArgs.qr, "qr", false, "show QR code for login URLs")
|
||||
upf.BoolVar(&upArgs.json, "json", false, "output in JSON format (WARNING: format subject to change)")
|
||||
@@ -195,22 +195,22 @@ type upOutputJSON struct {
|
||||
}
|
||||
|
||||
func warnf(format string, args ...any) {
|
||||
fmt.Printf("Warning: "+format+"\n", args...)
|
||||
printf("Warning: "+format+"\n", args...)
|
||||
}
|
||||
|
||||
var (
|
||||
ipv4default = netip.MustParsePrefix("0.0.0.0/0")
|
||||
ipv6default = netip.MustParsePrefix("::/0")
|
||||
ipv4default = netaddr.MustParseIPPrefix("0.0.0.0/0")
|
||||
ipv6default = netaddr.MustParseIPPrefix("::/0")
|
||||
)
|
||||
|
||||
func validateViaPrefix(ipp netip.Prefix) error {
|
||||
func validateViaPrefix(ipp netaddr.IPPrefix) error {
|
||||
if !tsaddr.IsViaPrefix(ipp) {
|
||||
return fmt.Errorf("%v is not a 4-in-6 prefix", ipp)
|
||||
}
|
||||
if ipp.Bits() < (128 - 32) {
|
||||
return fmt.Errorf("%v 4-in-6 prefix must be at least a /%v", ipp, 128-32)
|
||||
}
|
||||
a := ipp.Addr().As16()
|
||||
a := ipp.IP().As16()
|
||||
// The first 64 bits of a are the via prefix.
|
||||
// The next 32 bits are the "site ID".
|
||||
// The last 32 bits are the IPv4.
|
||||
@@ -223,13 +223,13 @@ func validateViaPrefix(ipp netip.Prefix) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]netip.Prefix, error) {
|
||||
routeMap := map[netip.Prefix]bool{}
|
||||
func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]netaddr.IPPrefix, error) {
|
||||
routeMap := map[netaddr.IPPrefix]bool{}
|
||||
if advertiseRoutes != "" {
|
||||
var default4, default6 bool
|
||||
advroutes := strings.Split(advertiseRoutes, ",")
|
||||
for _, s := range advroutes {
|
||||
ipp, err := netip.ParsePrefix(s)
|
||||
ipp, err := netaddr.ParseIPPrefix(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%q is not a valid IP address or CIDR prefix", s)
|
||||
}
|
||||
@@ -255,10 +255,10 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
|
||||
}
|
||||
}
|
||||
if advertiseDefaultRoute {
|
||||
routeMap[netip.MustParsePrefix("0.0.0.0/0")] = true
|
||||
routeMap[netip.MustParsePrefix("::/0")] = true
|
||||
routeMap[netaddr.MustParseIPPrefix("0.0.0.0/0")] = true
|
||||
routeMap[netaddr.MustParseIPPrefix("::/0")] = true
|
||||
}
|
||||
routes := make([]netip.Prefix, 0, len(routeMap))
|
||||
routes := make([]netaddr.IPPrefix, 0, len(routeMap))
|
||||
for r := range routeMap {
|
||||
routes = append(routes, r)
|
||||
}
|
||||
@@ -266,7 +266,7 @@ func calcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
|
||||
if routes[i].Bits() != routes[j].Bits() {
|
||||
return routes[i].Bits() < routes[j].Bits()
|
||||
}
|
||||
return routes[i].Addr().Less(routes[j].Addr())
|
||||
return routes[i].IP().Less(routes[j].IP())
|
||||
})
|
||||
return routes, nil
|
||||
}
|
||||
@@ -538,7 +538,7 @@ func runUp(ctx context.Context, args []string) (retErr error) {
|
||||
if env.upArgs.json {
|
||||
printUpDoneJSON(ipn.NeedsMachineAuth, "")
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s\n\n", prefs.AdminPageURL())
|
||||
fmt.Fprintf(Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s\n\n", prefs.AdminPageURL())
|
||||
}
|
||||
case ipn.Running:
|
||||
// Done full authentication process
|
||||
@@ -546,7 +546,7 @@ func runUp(ctx context.Context, args []string) (retErr error) {
|
||||
printUpDoneJSON(ipn.Running, "")
|
||||
} else if printed {
|
||||
// Only need to print an update if we printed the "please click" message earlier.
|
||||
fmt.Fprintf(os.Stderr, "Success.\n")
|
||||
fmt.Fprintf(Stderr, "Success.\n")
|
||||
}
|
||||
select {
|
||||
case running <- true:
|
||||
@@ -575,13 +575,13 @@ func runUp(ctx context.Context, args []string) (retErr error) {
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
||||
fmt.Fprintf(Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
||||
if upArgs.qr {
|
||||
q, err := qrcode.New(*url, qrcode.Medium)
|
||||
if err != nil {
|
||||
log.Printf("QR code error: %v", err)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", q.ToString(false))
|
||||
fmt.Fprintf(Stderr, "%s\n", q.ToString(false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,12 +695,12 @@ func checkSSHUpWarnings(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
if len(st.Health) == 1 && strings.Contains(st.Health[0], "SSH") {
|
||||
fmt.Printf("%s\n", st.Health[0])
|
||||
printf("%s\n", st.Health[0])
|
||||
return
|
||||
}
|
||||
fmt.Printf("# Health check:\n")
|
||||
printf("# Health check:\n")
|
||||
for _, m := range st.Health {
|
||||
fmt.Printf(" - %s\n", m)
|
||||
printf(" - %s\n", m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,7 +790,7 @@ type upCheckEnv struct {
|
||||
flagSet *flag.FlagSet
|
||||
upArgs upArgsT
|
||||
backendState string
|
||||
curExitNodeIP netip.Addr
|
||||
curExitNodeIP netaddr.IP
|
||||
distro distro.Distro
|
||||
}
|
||||
|
||||
@@ -913,10 +913,10 @@ func prefsToFlags(env upCheckEnv, prefs *ipn.Prefs) (flagVal map[string]any) {
|
||||
ret := make(map[string]any)
|
||||
|
||||
exitNodeIPStr := func() string {
|
||||
if prefs.ExitNodeIP.IsValid() {
|
||||
if !prefs.ExitNodeIP.IsZero() {
|
||||
return prefs.ExitNodeIP.String()
|
||||
}
|
||||
if prefs.ExitNodeID.IsZero() || !env.curExitNodeIP.IsValid() {
|
||||
if prefs.ExitNodeID.IsZero() || env.curExitNodeIP.IsZero() {
|
||||
return ""
|
||||
}
|
||||
return env.curExitNodeIP.String()
|
||||
@@ -991,13 +991,13 @@ func fmtFlagValueArg(flagName string, val any) string {
|
||||
return fmt.Sprintf("--%s=%v", flagName, shellquote.Join(fmt.Sprint(val)))
|
||||
}
|
||||
|
||||
func hasExitNodeRoutes(rr []netip.Prefix) bool {
|
||||
func hasExitNodeRoutes(rr []netaddr.IPPrefix) bool {
|
||||
var v4, v6 bool
|
||||
for _, r := range rr {
|
||||
if r.Bits() == 0 {
|
||||
if r.Addr().Is4() {
|
||||
if r.IP().Is4() {
|
||||
v4 = true
|
||||
} else if r.Addr().Is6() {
|
||||
} else if r.IP().Is6() {
|
||||
v6 = true
|
||||
}
|
||||
}
|
||||
@@ -1008,11 +1008,11 @@ func hasExitNodeRoutes(rr []netip.Prefix) bool {
|
||||
// withoutExitNodes returns rr unchanged if it has only 1 or 0 /0
|
||||
// routes. If it has both IPv4 and IPv6 /0 routes, then it returns
|
||||
// a copy with all /0 routes removed.
|
||||
func withoutExitNodes(rr []netip.Prefix) []netip.Prefix {
|
||||
func withoutExitNodes(rr []netaddr.IPPrefix) []netaddr.IPPrefix {
|
||||
if !hasExitNodeRoutes(rr) {
|
||||
return rr
|
||||
}
|
||||
var out []netip.Prefix
|
||||
var out []netaddr.IPPrefix
|
||||
for _, r := range rr {
|
||||
if r.Bits() > 0 {
|
||||
out = append(out, r)
|
||||
@@ -1023,11 +1023,11 @@ func withoutExitNodes(rr []netip.Prefix) []netip.Prefix {
|
||||
|
||||
// exitNodeIP returns the exit node IP from p, using st to map
|
||||
// it from its ID form to an IP address if needed.
|
||||
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
|
||||
func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netaddr.IP) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
if p.ExitNodeIP.IsValid() {
|
||||
if !p.ExitNodeIP.IsZero() {
|
||||
return p.ExitNodeIP
|
||||
}
|
||||
id := p.ExitNodeID
|
||||
|
||||
@@ -18,7 +18,7 @@ var versionCmd = &ffcli.Command{
|
||||
ShortUsage: "version [flags]",
|
||||
ShortHelp: "Print Tailscale version",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("version", flag.ExitOnError)
|
||||
fs := newFlagSet("version")
|
||||
fs.BoolVar(&versionArgs.daemon, "daemon", false, "also print local node's daemon version")
|
||||
return fs
|
||||
})(),
|
||||
@@ -34,16 +34,16 @@ func runVersion(ctx context.Context, args []string) error {
|
||||
return fmt.Errorf("too many non-flag arguments: %q", args)
|
||||
}
|
||||
if !versionArgs.daemon {
|
||||
fmt.Println(version.String())
|
||||
outln(version.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Client: %s\n", version.String())
|
||||
printf("Client: %s\n", version.String())
|
||||
|
||||
st, err := localClient.StatusWithoutPeers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Daemon: %s\n", st.Version)
|
||||
printf("Daemon: %s\n", st.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cgi"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -28,6 +27,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/preftype"
|
||||
@@ -75,7 +75,7 @@ Tailscale, as opposed to a CLI or a native app.
|
||||
`),
|
||||
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
webf := flag.NewFlagSet("web", flag.ExitOnError)
|
||||
webf := newFlagSet("web")
|
||||
webf.StringVar(&webArgs.listen, "listen", "localhost:8088", "listen address; use port 0 for automatic")
|
||||
webf.BoolVar(&webArgs.cgi, "cgi", false, "run as CGI script")
|
||||
return webf
|
||||
@@ -393,8 +393,8 @@ func webHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Status: st.BackendState,
|
||||
DeviceName: deviceName,
|
||||
}
|
||||
exitNodeRouteV4 := netip.MustParsePrefix("0.0.0.0/0")
|
||||
exitNodeRouteV6 := netip.MustParsePrefix("::/0")
|
||||
exitNodeRouteV4 := netaddr.MustParseIPPrefix("0.0.0.0/0")
|
||||
exitNodeRouteV6 := netaddr.MustParseIPPrefix("::/0")
|
||||
for _, r := range prefs.AdvertiseRoutes {
|
||||
if r == exitNodeRouteV4 || r == exitNodeRouteV6 {
|
||||
data.AdvertiseExitNode = true
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/depaware)
|
||||
|
||||
filippo.io/edwards25519 from github.com/hdevalence/ed25519consensus
|
||||
filippo.io/edwards25519/field from filippo.io/edwards25519
|
||||
W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/negotiate+
|
||||
W github.com/alexbrainman/sspi/internal/common from github.com/alexbrainman/sspi/negotiate
|
||||
W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy
|
||||
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
||||
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
||||
github.com/hdevalence/ed25519consensus from tailscale.com/tka
|
||||
L github.com/josharian/native from github.com/mdlayher/netlink+
|
||||
L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces
|
||||
L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink
|
||||
@@ -30,10 +26,11 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp
|
||||
github.com/tcnksm/go-httpstat from tailscale.com/net/netcheck
|
||||
github.com/toqueteos/webbrowser from tailscale.com/cmd/tailscale/cli
|
||||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
💣 go4.org/intern from inet.af/netaddr
|
||||
💣 go4.org/mem from tailscale.com/derp+
|
||||
go4.org/netipx from tailscale.com/wgengine/filter
|
||||
go4.org/unsafe/assume-no-moving-gc from go4.org/intern
|
||||
W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/interfaces+
|
||||
inet.af/netaddr from tailscale.com/cmd/tailscale/cli+
|
||||
nhooyr.io/websocket from tailscale.com/derp/derphttp+
|
||||
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
|
||||
nhooyr.io/websocket/internal/xsync from nhooyr.io/websocket
|
||||
@@ -57,7 +54,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/net/dnsfallback from tailscale.com/control/controlhttp
|
||||
tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+
|
||||
💣 tailscale.com/net/interfaces from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/net/netaddr from tailscale.com/disco+
|
||||
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli
|
||||
tailscale.com/net/neterror from tailscale.com/net/netcheck+
|
||||
tailscale.com/net/netknob from tailscale.com/net/netns
|
||||
@@ -73,7 +69,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/safesocket from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/syncs from tailscale.com/net/interfaces+
|
||||
tailscale.com/tailcfg from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/tka from tailscale.com/types/key
|
||||
W tailscale.com/tsconst from tailscale.com/net/interfaces
|
||||
💣 tailscale.com/tstime/mono from tailscale.com/tstime/rate
|
||||
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
|
||||
@@ -83,7 +78,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/types/key from tailscale.com/derp+
|
||||
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/types/netmap from tailscale.com/ipn
|
||||
tailscale.com/types/nettype from tailscale.com/net/netcheck+
|
||||
tailscale.com/types/opt from tailscale.com/net/netcheck+
|
||||
tailscale.com/types/pad32 from tailscale.com/derp
|
||||
tailscale.com/types/persist from tailscale.com/ipn
|
||||
@@ -102,9 +96,8 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/version from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/version/distro from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/wgengine/filter from tailscale.com/types/netmap
|
||||
golang.org/x/crypto/argon2 from tailscale.com/tka
|
||||
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box+
|
||||
golang.org/x/crypto/blake2s from tailscale.com/control/controlbase+
|
||||
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box
|
||||
golang.org/x/crypto/blake2s from tailscale.com/control/controlbase
|
||||
golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305
|
||||
golang.org/x/crypto/chacha20poly1305 from crypto/tls+
|
||||
golang.org/x/crypto/cryptobyte from crypto/ecdsa+
|
||||
@@ -162,7 +155,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
embed from tailscale.com/cmd/tailscale/cli+
|
||||
encoding from encoding/json+
|
||||
encoding/asn1 from crypto/x509+
|
||||
encoding/base32 from tailscale.com/tka
|
||||
encoding/base64 from encoding/json+
|
||||
encoding/binary from compress/gzip+
|
||||
encoding/hex from crypto/x509+
|
||||
@@ -183,7 +175,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
image/color from github.com/skip2/go-qrcode+
|
||||
image/png from github.com/skip2/go-qrcode
|
||||
io from bufio+
|
||||
io/fs from crypto/x509+
|
||||
io/fs from crypto/rand+
|
||||
io/ioutil from golang.org/x/sys/cpu+
|
||||
log from expvar+
|
||||
math from compress/flate+
|
||||
@@ -198,7 +190,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
net/http/cgi from tailscale.com/cmd/tailscale/cli
|
||||
net/http/httptrace from github.com/tcnksm/go-httpstat+
|
||||
net/http/internal from net/http
|
||||
net/netip from net+
|
||||
net/netip from net
|
||||
net/textproto from golang.org/x/net/http/httpguts+
|
||||
net/url from crypto/x509+
|
||||
os from crypto/rand+
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/derp/derphttp"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn"
|
||||
@@ -266,11 +266,11 @@ func debugPortmap(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
gatewayAndSelfIP := func() (gw, self netip.Addr, ok bool) {
|
||||
gatewayAndSelfIP := func() (gw, self netaddr.IP, ok bool) {
|
||||
if v := os.Getenv("TS_DEBUG_GW_SELF"); strings.Contains(v, "/") {
|
||||
i := strings.Index(v, "/")
|
||||
gw = netip.MustParseAddr(v[:i])
|
||||
self = netip.MustParseAddr(v[i+1:])
|
||||
gw = netaddr.MustParseIP(v[:i])
|
||||
self = netaddr.MustParseIP(v[i+1:])
|
||||
return gw, self, true
|
||||
}
|
||||
return linkMon.GatewayAndSelfIP()
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/depaware)
|
||||
|
||||
filippo.io/edwards25519 from github.com/hdevalence/ed25519consensus
|
||||
filippo.io/edwards25519/field from filippo.io/edwards25519
|
||||
W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/internal/common+
|
||||
W github.com/alexbrainman/sspi/internal/common from github.com/alexbrainman/sspi/negotiate
|
||||
W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy
|
||||
@@ -64,13 +62,11 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
L github.com/aws/smithy-go/waiter from github.com/aws/aws-sdk-go-v2/service/ssm
|
||||
L github.com/coreos/go-iptables/iptables from tailscale.com/wgengine/router
|
||||
LD 💣 github.com/creack/pty from tailscale.com/ssh/tailssh
|
||||
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
||||
W 💣 github.com/go-ole/go-ole from github.com/go-ole/go-ole/oleutil+
|
||||
W 💣 github.com/go-ole/go-ole/oleutil from tailscale.com/wgengine/winnet
|
||||
L 💣 github.com/godbus/dbus/v5 from tailscale.com/net/dns+
|
||||
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
||||
github.com/google/btree from gvisor.dev/gvisor/pkg/tcpip/header+
|
||||
github.com/hdevalence/ed25519consensus from tailscale.com/tka
|
||||
L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/net/tstun
|
||||
L github.com/insomniacslk/dhcp/iana from github.com/insomniacslk/dhcp/dhcpv4
|
||||
L github.com/insomniacslk/dhcp/interfaces from github.com/insomniacslk/dhcp/dhcpv4
|
||||
@@ -117,9 +113,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
L github.com/u-root/uio/uio from github.com/insomniacslk/dhcp/dhcpv4+
|
||||
L 💣 github.com/vishvananda/netlink/nl from github.com/tailscale/netlink
|
||||
L github.com/vishvananda/netns from github.com/tailscale/netlink+
|
||||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
💣 go4.org/intern from inet.af/netaddr
|
||||
💣 go4.org/mem from tailscale.com/control/controlbase+
|
||||
go4.org/netipx from tailscale.com/ipn/ipnlocal+
|
||||
go4.org/unsafe/assume-no-moving-gc from go4.org/intern
|
||||
W 💣 golang.zx2c4.com/wintun from golang.zx2c4.com/wireguard/tun
|
||||
💣 golang.zx2c4.com/wireguard/conn from golang.zx2c4.com/wireguard/device+
|
||||
W 💣 golang.zx2c4.com/wireguard/conn/winrio from golang.zx2c4.com/wireguard/conn
|
||||
@@ -172,6 +168,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
gvisor.dev/gvisor/pkg/tcpip/transport/tcpconntrack from gvisor.dev/gvisor/pkg/tcpip/stack
|
||||
gvisor.dev/gvisor/pkg/tcpip/transport/udp from tailscale.com/net/tstun+
|
||||
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
|
||||
inet.af/netaddr from tailscale.com/control/controlclient+
|
||||
inet.af/peercred from tailscale.com/ipn/ipnserver
|
||||
W 💣 inet.af/wf from tailscale.com/wf
|
||||
nhooyr.io/websocket from tailscale.com/derp/derphttp+
|
||||
@@ -219,7 +216,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient+
|
||||
tailscale.com/net/flowtrack from tailscale.com/net/packet+
|
||||
💣 tailscale.com/net/interfaces from tailscale.com/control/controlclient+
|
||||
tailscale.com/net/netaddr from tailscale.com/disco+
|
||||
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
|
||||
tailscale.com/net/neterror from tailscale.com/net/dns/resolver+
|
||||
tailscale.com/net/netknob from tailscale.com/net/netns+
|
||||
@@ -244,7 +240,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/syncs from tailscale.com/control/controlknobs+
|
||||
tailscale.com/tailcfg from tailscale.com/client/tailscale/apitype+
|
||||
LD tailscale.com/tempfork/gliderlabs/ssh from tailscale.com/ssh/tailssh
|
||||
tailscale.com/tka from tailscale.com/types/key
|
||||
W tailscale.com/tsconst from tailscale.com/net/interfaces
|
||||
tailscale.com/tstime from tailscale.com/wgengine/magicsock
|
||||
💣 tailscale.com/tstime/mono from tailscale.com/net/tstun+
|
||||
@@ -257,7 +252,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/types/key from tailscale.com/control/controlbase+
|
||||
tailscale.com/types/logger from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/netmap from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock+
|
||||
tailscale.com/types/nettype from tailscale.com/wgengine/magicsock
|
||||
tailscale.com/types/opt from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/pad32 from tailscale.com/derp
|
||||
tailscale.com/types/persist from tailscale.com/control/controlclient+
|
||||
@@ -274,6 +269,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/util/lineread from tailscale.com/hostinfo+
|
||||
tailscale.com/util/mak from tailscale.com/control/controlclient+
|
||||
tailscale.com/util/multierr from tailscale.com/control/controlclient+
|
||||
tailscale.com/util/netconv from tailscale.com/wgengine/magicsock
|
||||
tailscale.com/util/osshare from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/pidowner from tailscale.com/ipn/ipnserver
|
||||
tailscale.com/util/racebuild from tailscale.com/logpolicy
|
||||
@@ -295,8 +291,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/wgengine/wglog from tailscale.com/wgengine
|
||||
W 💣 tailscale.com/wgengine/winnet from tailscale.com/wgengine/router
|
||||
golang.org/x/crypto/acme from tailscale.com/ipn/localapi
|
||||
golang.org/x/crypto/argon2 from tailscale.com/tka
|
||||
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box+
|
||||
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box
|
||||
golang.org/x/crypto/blake2s from golang.zx2c4.com/wireguard/device+
|
||||
LD golang.org/x/crypto/blowfish from golang.org/x/crypto/ssh/internal/bcrypt_pbkdf+
|
||||
golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305+
|
||||
@@ -367,7 +362,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
embed from tailscale.com+
|
||||
encoding from encoding/json+
|
||||
encoding/asn1 from crypto/x509+
|
||||
encoding/base32 from tailscale.com/tka
|
||||
encoding/base64 from encoding/json+
|
||||
encoding/binary from compress/gzip+
|
||||
encoding/hex from crypto/x509+
|
||||
@@ -384,7 +378,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
hash/maphash from go4.org/mem
|
||||
html from tailscale.com/ipn/ipnlocal+
|
||||
io from bufio+
|
||||
io/fs from crypto/x509+
|
||||
io/fs from crypto/rand+
|
||||
io/ioutil from github.com/godbus/dbus/v5+
|
||||
log from expvar+
|
||||
LD log/syslog from tailscale.com/ssh/tailssh
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
@@ -30,6 +29,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/cmd/tailscaled/childproc"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/envknob"
|
||||
@@ -128,8 +128,6 @@ var subCommands = map[string]*func([]string) error{
|
||||
"be-child": &beChildFunc,
|
||||
}
|
||||
|
||||
var beCLI func() // non-nil if CLI is linked in
|
||||
|
||||
func main() {
|
||||
printVersion := false
|
||||
flag.IntVar(&args.verbose, "verbose", 0, "log verbosity level; 0 is default, 1 or higher are increasingly verbose")
|
||||
@@ -145,11 +143,6 @@ func main() {
|
||||
flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
|
||||
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
||||
|
||||
if len(os.Args) > 0 && filepath.Base(os.Args[0]) == "tailscale" && beCLI != nil {
|
||||
beCLI()
|
||||
return
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
sub := os.Args[1]
|
||||
if fp, ok := subCommands[sub]; ok {
|
||||
@@ -274,6 +267,13 @@ func ipnServerOpts() (o ipnserver.Options) {
|
||||
}
|
||||
|
||||
switch goos {
|
||||
case "js":
|
||||
// The js/wasm client has no state storage so for now
|
||||
// treat all interactive logins as ephemeral.
|
||||
// TODO(bradfitz): if we start using browser LocalStorage
|
||||
// or something, then rethink this.
|
||||
o.LoginFlags = controlclient.LoginEphemeral
|
||||
fallthrough
|
||||
default:
|
||||
o.SurviveDisconnects = true
|
||||
o.AutostartStateKey = ipn.GlobalDaemonStateKey
|
||||
@@ -366,11 +366,11 @@ func run() error {
|
||||
ns.ProcessSubnets = useNetstack || wrapNetstack
|
||||
|
||||
if useNetstack {
|
||||
dialer.UseNetstackForIP = func(ip netip.Addr) bool {
|
||||
dialer.UseNetstackForIP = func(ip netaddr.IP) bool {
|
||||
_, ok := e.PeerForIP(ip)
|
||||
return ok
|
||||
}
|
||||
dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
|
||||
dialer.NetstackDialTCP = func(ctx context.Context, dst netaddr.IPPort) (net.Conn, error) {
|
||||
return ns.DialContextTCP(ctx, dst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -33,6 +32,7 @@ import (
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn/ipnserver"
|
||||
"tailscale.com/ipn/store"
|
||||
@@ -245,7 +245,7 @@ func beFirewallKillswitch() bool {
|
||||
// is passed in via stdin encoded in json.
|
||||
dcd := json.NewDecoder(os.Stdin)
|
||||
for {
|
||||
var routes []netip.Prefix
|
||||
var routes []netaddr.IPPrefix
|
||||
if err := dcd.Decode(&routes); err != nil {
|
||||
log.Fatalf("parent process died or requested exit, exiting (%v)", err)
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//go:build ts_include_cli
|
||||
// +build ts_include_cli
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"tailscale.com/cmd/tailscale/cli"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beCLI = func() {
|
||||
args := os.Args[1:]
|
||||
if err := cli.Run(args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,6 @@ func runBuild() {
|
||||
log.Fatalf("Cannot setup: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Linting...\n")
|
||||
if err := runYarn("lint"); err != nil {
|
||||
log.Fatalf("Linting failed: %v", err)
|
||||
}
|
||||
|
||||
if err := cleanDist(); err != nil {
|
||||
log.Fatalf("Cannot clean %s: %v", *distDir, err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
esbuild "github.com/evanw/esbuild/pkg/api"
|
||||
)
|
||||
@@ -37,7 +36,7 @@ func commonSetup(dev bool) (*esbuild.BuildOptions, error) {
|
||||
}
|
||||
|
||||
return &esbuild.BuildOptions{
|
||||
EntryPoints: []string{"src/index.ts", "src/index.css"},
|
||||
EntryPoints: []string{"src/index.js", "src/index.css"},
|
||||
Loader: map[string]esbuild.Loader{".wasm": esbuild.LoaderFile},
|
||||
Outdir: *distDir,
|
||||
Bundle: true,
|
||||
@@ -45,12 +44,6 @@ func commonSetup(dev bool) (*esbuild.BuildOptions, error) {
|
||||
LogLevel: esbuild.LogLevelInfo,
|
||||
Define: map[string]string{"DEBUG": strconv.FormatBool(dev)},
|
||||
Target: esbuild.ES2017,
|
||||
Plugins: []esbuild.Plugin{{
|
||||
Name: "tailscale-tailwind",
|
||||
Setup: func(build esbuild.PluginBuild) {
|
||||
setupEsbuildTailwind(build, dev)
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -104,14 +97,11 @@ func buildWasm(dev bool) error {
|
||||
// installJSDeps installs the JavaScript dependencies specified by package.json
|
||||
func installJSDeps() error {
|
||||
log.Printf("Installing JS deps...\n")
|
||||
return runYarn()
|
||||
}
|
||||
|
||||
func runYarn(args ...string) error {
|
||||
cmd := exec.Command(*yarnPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
stdoutStderr, err := exec.Command("yarn").CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("yarn failed: %s", stdoutStderr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// EsbuildMetadata is the subset of metadata struct (described by
|
||||
@@ -122,30 +112,3 @@ type EsbuildMetadata struct {
|
||||
EntryPoint string `json:"entryPoint,omitempty"`
|
||||
} `json:"outputs,omitempty"`
|
||||
}
|
||||
|
||||
func setupEsbuildTailwind(build esbuild.PluginBuild, dev bool) {
|
||||
build.OnLoad(esbuild.OnLoadOptions{
|
||||
Filter: "./src/index.css$",
|
||||
}, func(args esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
|
||||
start := time.Now()
|
||||
yarnArgs := []string{"--silent", "tailwind", "-i", args.Path}
|
||||
if !dev {
|
||||
yarnArgs = append(yarnArgs, "--minify")
|
||||
}
|
||||
cmd := exec.Command(*yarnPath, yarnArgs...)
|
||||
tailwindOutput, err := cmd.Output()
|
||||
log.Printf("Ran tailwind in %v\n", time.Since(start))
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
log.Printf("Tailwind stderr: %s", exitErr.Stderr)
|
||||
}
|
||||
return esbuild.OnLoadResult{}, fmt.Errorf("Cannot run tailwind: %w", err)
|
||||
}
|
||||
tailwindOutputStr := string(tailwindOutput)
|
||||
return esbuild.OnLoadResult{
|
||||
Contents: &tailwindOutputStr,
|
||||
Loader: esbuild.LoaderCSS,
|
||||
}, nil
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,34 +5,12 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" type="text/css" href="dist/index.css" />
|
||||
</head>
|
||||
<body class="flex flex-col min-h-screen">
|
||||
<div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2 mb-6">
|
||||
<header class="container mx-auto px-4 flex flex-row items-center">
|
||||
<h1 class="text-3xl font-bold grow">Tailscale Connect</h1>
|
||||
<div class="text-gray-600" id="state">Loading…</div>
|
||||
</header>
|
||||
</div>
|
||||
<form
|
||||
id="ssh-form"
|
||||
class="container mx-auto px-4 hidden flex justify-center"
|
||||
>
|
||||
<input type="text" class="input username" placeholder="Username" />
|
||||
<div class="select-with-arrow mx-2">
|
||||
<select class="select"></select>
|
||||
</div>
|
||||
<input
|
||||
type="submit"
|
||||
class="button bg-green-500 border-green-500 text-white hover:bg-green-600 hover:border-green-600"
|
||||
value="SSH"
|
||||
/>
|
||||
</form>
|
||||
<div id="no-ssh" class="container mx-auto px-4 hidden text-center">
|
||||
None of your machines have
|
||||
<a href="https://tailscale.com/kb/1193/tailscale-ssh/" class="link"
|
||||
>Tailscale SSH</a
|
||||
>
|
||||
enabled. Give it a try!
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>Tailscale Connect</h1>
|
||||
<div id="state">Loading…</div>
|
||||
</div>
|
||||
<div id="peers"></div>
|
||||
<script src="dist/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
{
|
||||
"name": "tsconnect",
|
||||
"name": "@tailscale/ssh",
|
||||
"version": "0.0.1",
|
||||
"license": "BSD-3-Clause",
|
||||
"devDependencies": {
|
||||
"@types/golang-wasm-exec": "^1.15.0",
|
||||
"@types/qrcode": "^1.4.2",
|
||||
"qrcode": "^1.5.0",
|
||||
"tailwindcss": "^3.1.6",
|
||||
"typescript": "^4.7.4",
|
||||
"xterm": "^4.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 80
|
||||
|
||||
@@ -102,7 +102,7 @@ func generateServeIndex(distFS fs.FS) ([]byte, error) {
|
||||
|
||||
var entryPointsToDefaultDistPaths = map[string]string{
|
||||
"src/index.css": "dist/index.css",
|
||||
"src/index.ts": "dist/index.js",
|
||||
"src/index.js": "dist/index.js",
|
||||
}
|
||||
|
||||
func handleServeDist(w http.ResponseWriter, r *http.Request, distFS fs.FS) {
|
||||
|
||||
15
cmd/tsconnect/src/esbuild.d.ts
vendored
15
cmd/tsconnect/src/esbuild.d.ts
vendored
@@ -1,15 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Type definitions for types generated by the esbuild build
|
||||
* process.
|
||||
*/
|
||||
|
||||
declare module "*.wasm" {
|
||||
const path: string
|
||||
export default path
|
||||
}
|
||||
|
||||
declare const DEBUG: boolean
|
||||
@@ -4,72 +4,88 @@
|
||||
|
||||
@import "xterm/css/xterm.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.link {
|
||||
@apply text-blue-600;
|
||||
html {
|
||||
background: #fff;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
@apply underline;
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply font-medium py-1 px-2 rounded-md border border-transparent text-center cursor-pointer;
|
||||
transition-property: background-color, border-color, color, box-shadow;
|
||||
transition-duration: 120ms;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
|
||||
min-width: 80px;
|
||||
}
|
||||
.button:focus {
|
||||
@apply outline-none ring;
|
||||
}
|
||||
.button:disabled {
|
||||
@apply pointer-events-none select-none;
|
||||
button {
|
||||
font-family: inherit;
|
||||
border: solid 1px #ccc;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.input {
|
||||
@apply appearance-none leading-tight rounded-md bg-white border border-gray-300 hover:border-gray-400 transition-colors px-3;
|
||||
height: 2.375rem;
|
||||
#header {
|
||||
background: #f7f5f4;
|
||||
border-bottom: 1px solid #eeebea;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input::placeholder {
|
||||
@apply text-gray-400;
|
||||
#header h1 {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.input:disabled {
|
||||
@apply border-gray-200;
|
||||
@apply bg-gray-50;
|
||||
@apply cursor-not-allowed;
|
||||
#header #state {
|
||||
padding: 0 8px;
|
||||
color: #444342;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
@apply outline-none ring border-transparent;
|
||||
#peers {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.select {
|
||||
@apply appearance-none py-2 px-3 leading-tight rounded-md bg-white border border-gray-300;
|
||||
.login {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.select-with-arrow {
|
||||
@apply relative;
|
||||
.logout {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-with-arrow .select {
|
||||
width: 100%;
|
||||
.peer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.select-with-arrow::after {
|
||||
@apply absolute;
|
||||
content: "";
|
||||
top: 50%;
|
||||
right: 0.5rem;
|
||||
transform: translate(-0.3em, -0.15em);
|
||||
width: 0.6em;
|
||||
height: 0.4em;
|
||||
opacity: 0.6;
|
||||
background-color: currentColor;
|
||||
clip-path: polygon(100% 0%, 0 0%, 50% 100%);
|
||||
.peer:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.peer .name {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.peer .ssh {
|
||||
background-color: #cbf4c9;
|
||||
}
|
||||
|
||||
.term-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.xterm-viewport.xterm-viewport {
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.xterm-viewport::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
.xterm-viewport::-webkit-scrollbar-track {
|
||||
opacity: 0;
|
||||
}
|
||||
.xterm-viewport::-webkit-scrollbar-thumb {
|
||||
min-height: 20px;
|
||||
background-color: #ffffff20;
|
||||
}
|
||||
|
||||
26
cmd/tsconnect/src/index.js
Normal file
26
cmd/tsconnect/src/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
import "./wasm_exec"
|
||||
import wasmUrl from "./main.wasm"
|
||||
import { notifyState, notifyNetMap, notifyBrowseToURL } from "./notifier"
|
||||
import { sessionStateStorage } from "./js-state-store"
|
||||
|
||||
const go = new window.Go()
|
||||
WebAssembly.instantiateStreaming(
|
||||
fetch(`./dist/${wasmUrl}`),
|
||||
go.importObject
|
||||
).then((result) => {
|
||||
go.run(result.instance)
|
||||
const ipn = newIPN({
|
||||
// Persist IPN state in sessionStorage in development, so that we don't need
|
||||
// to re-authorize every time we reload the page.
|
||||
stateStorage: DEBUG ? sessionStateStorage : undefined,
|
||||
})
|
||||
ipn.run({
|
||||
notifyState: notifyState.bind(null, ipn),
|
||||
notifyNetMap: notifyNetMap.bind(null, ipn),
|
||||
notifyBrowseToURL: notifyBrowseToURL.bind(null, ipn),
|
||||
})
|
||||
})
|
||||
@@ -1,54 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import "./wasm_exec"
|
||||
import wasmUrl from "./main.wasm"
|
||||
import { notifyState, notifyNetMap, notifyBrowseToURL } from "./notifier"
|
||||
import { sessionStateStorage } from "./js-state-store"
|
||||
|
||||
const go = new Go()
|
||||
WebAssembly.instantiateStreaming(
|
||||
fetch(`./dist/${wasmUrl}`),
|
||||
go.importObject
|
||||
).then((result) => {
|
||||
// The Go process should never exit, if it does then it's an unhandled panic.
|
||||
go.run(result.instance).then(() => handleGoPanic())
|
||||
const ipn = newIPN({
|
||||
// Persist IPN state in sessionStorage in development, so that we don't need
|
||||
// to re-authorize every time we reload the page.
|
||||
stateStorage: DEBUG ? sessionStateStorage : undefined,
|
||||
})
|
||||
ipn.run({
|
||||
notifyState: notifyState.bind(null, ipn),
|
||||
notifyNetMap: notifyNetMap.bind(null, ipn),
|
||||
notifyBrowseToURL: notifyBrowseToURL.bind(null, ipn),
|
||||
notifyPanicRecover: handleGoPanic,
|
||||
})
|
||||
})
|
||||
|
||||
function handleGoPanic(err?: string) {
|
||||
if (DEBUG && err) {
|
||||
console.error("Go panic", err)
|
||||
}
|
||||
if (panicNode) {
|
||||
panicNode.remove()
|
||||
}
|
||||
panicNode = document.createElement("div")
|
||||
panicNode.className =
|
||||
"rounded bg-red-500 p-2 absolute top-2 right-2 text-white font-bold text-right cursor-pointer"
|
||||
panicNode.textContent = "Tailscale has encountered an error."
|
||||
const panicDetailNode = document.createElement("div")
|
||||
panicDetailNode.className = "text-sm font-normal"
|
||||
panicDetailNode.textContent = "Click to reload"
|
||||
panicNode.appendChild(panicDetailNode)
|
||||
panicNode.addEventListener("click", () => location.reload(), {
|
||||
once: true,
|
||||
})
|
||||
document.body.appendChild(panicNode)
|
||||
setTimeout(() => {
|
||||
panicNode!.remove()
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
let panicNode: HTMLDivElement | undefined
|
||||
@@ -2,9 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/** @fileoverview Callbacks used by jsStateStore to persist IPN state. */
|
||||
/**
|
||||
* @fileoverview Callbacks used by jsStateStore to persist IPN state.
|
||||
*/
|
||||
|
||||
export const sessionStateStorage: IPNStateStorage = {
|
||||
export const sessionStateStorage = {
|
||||
setState(id, value) {
|
||||
window.sessionStorage[`ipn-state-${id}`] = value
|
||||
},
|
||||
@@ -2,32 +2,32 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
import * as qrcode from "qrcode"
|
||||
import QRCode from "qrcode"
|
||||
|
||||
export async function showLoginURL(url: string) {
|
||||
export async function showLoginURL(url) {
|
||||
if (loginNode) {
|
||||
loginNode.remove()
|
||||
}
|
||||
loginNode = document.createElement("div")
|
||||
loginNode.className = "flex flex-col items-center justify-items-center"
|
||||
loginNode.className = "login"
|
||||
const linkNode = document.createElement("a")
|
||||
linkNode.className = "link"
|
||||
linkNode.href = url
|
||||
linkNode.target = "_blank"
|
||||
loginNode.appendChild(linkNode)
|
||||
|
||||
try {
|
||||
const dataURL = await qrcode.toDataURL(url, { width: 512 })
|
||||
const dataURL = await QRCode.toDataURL(url, { width: 512 })
|
||||
const imageNode = document.createElement("img")
|
||||
imageNode.className = "mx-auto"
|
||||
imageNode.src = dataURL
|
||||
imageNode.width = 256
|
||||
imageNode.height = 256
|
||||
imageNode.border = "0"
|
||||
linkNode.appendChild(imageNode)
|
||||
} catch (err) {
|
||||
console.error("Could not generate QR code:", err)
|
||||
}
|
||||
|
||||
linkNode.appendChild(document.createElement("br"))
|
||||
linkNode.appendChild(document.createTextNode(url))
|
||||
|
||||
document.body.appendChild(loginNode)
|
||||
@@ -41,15 +41,14 @@ export function hideLoginURL() {
|
||||
loginNode = undefined
|
||||
}
|
||||
|
||||
let loginNode: HTMLDivElement | undefined
|
||||
let loginNode
|
||||
|
||||
export function showLogoutButton(ipn: IPN) {
|
||||
export function showLogoutButton(ipn) {
|
||||
if (logoutButtonNode) {
|
||||
logoutButtonNode.remove()
|
||||
}
|
||||
logoutButtonNode = document.createElement("button")
|
||||
logoutButtonNode.className =
|
||||
"button bg-gray-500 border-gray-500 text-white hover:bg-gray-600 hover:border-gray-600 ml-2 font-bold"
|
||||
logoutButtonNode.className = "logout"
|
||||
logoutButtonNode.textContent = "Logout"
|
||||
logoutButtonNode.addEventListener(
|
||||
"click",
|
||||
@@ -58,8 +57,7 @@ export function showLogoutButton(ipn: IPN) {
|
||||
},
|
||||
{ once: true }
|
||||
)
|
||||
const headerNode = document.getElementsByTagName("header")[0]!
|
||||
headerNode.appendChild(logoutButtonNode)
|
||||
document.getElementById("header").appendChild(logoutButtonNode)
|
||||
}
|
||||
|
||||
export function hideLogoutButton() {
|
||||
@@ -70,4 +68,4 @@ export function hideLogoutButton() {
|
||||
logoutButtonNode = undefined
|
||||
}
|
||||
|
||||
let logoutButtonNode: HTMLButtonElement | undefined
|
||||
let logoutButtonNode
|
||||
@@ -8,58 +8,68 @@ import {
|
||||
showLogoutButton,
|
||||
hideLogoutButton,
|
||||
} from "./login"
|
||||
import { showSSHForm, hideSSHForm } from "./ssh"
|
||||
import { IPNState } from "./wasm_js"
|
||||
import { showSSHPeers, hideSSHPeers } from "./ssh"
|
||||
|
||||
/**
|
||||
* @fileoverview Notification callback functions (bridged from ipn.Notify)
|
||||
*/
|
||||
|
||||
export function notifyState(ipn: IPN, state: IPNState) {
|
||||
/** Mirrors values from ipn/backend.go */
|
||||
const State = {
|
||||
NoState: 0,
|
||||
InUseOtherUser: 1,
|
||||
NeedsLogin: 2,
|
||||
NeedsMachineAuth: 3,
|
||||
Stopped: 4,
|
||||
Starting: 5,
|
||||
Running: 6,
|
||||
}
|
||||
|
||||
export function notifyState(ipn, state) {
|
||||
let stateLabel
|
||||
switch (state) {
|
||||
case IPNState.NoState:
|
||||
case State.NoState:
|
||||
stateLabel = "Initializing…"
|
||||
break
|
||||
case IPNState.InUseOtherUser:
|
||||
case State.InUseOtherUser:
|
||||
stateLabel = "In-use by another user"
|
||||
break
|
||||
case IPNState.NeedsLogin:
|
||||
case State.NeedsLogin:
|
||||
stateLabel = "Needs Login"
|
||||
hideLogoutButton()
|
||||
hideSSHForm()
|
||||
hideSSHPeers()
|
||||
ipn.login()
|
||||
break
|
||||
case IPNState.NeedsMachineAuth:
|
||||
case State.NeedsMachineAuth:
|
||||
stateLabel = "Needs authorization"
|
||||
break
|
||||
case IPNState.Stopped:
|
||||
case State.Stopped:
|
||||
stateLabel = "Stopped"
|
||||
hideLogoutButton()
|
||||
hideSSHForm()
|
||||
hideSSHPeers()
|
||||
break
|
||||
case IPNState.Starting:
|
||||
case State.Starting:
|
||||
stateLabel = "Starting…"
|
||||
break
|
||||
case IPNState.Running:
|
||||
case State.Running:
|
||||
stateLabel = "Running"
|
||||
hideLoginURL()
|
||||
showLogoutButton(ipn)
|
||||
break
|
||||
}
|
||||
const stateNode = document.getElementById("state") as HTMLDivElement
|
||||
const stateNode = document.getElementById("state")
|
||||
stateNode.textContent = stateLabel ?? ""
|
||||
}
|
||||
|
||||
export function notifyNetMap(ipn: IPN, netMapStr: string) {
|
||||
const netMap = JSON.parse(netMapStr) as IPNNetMap
|
||||
export function notifyNetMap(ipn, netMapStr) {
|
||||
const netMap = JSON.parse(netMapStr)
|
||||
if (DEBUG) {
|
||||
console.log("Received net map: " + JSON.stringify(netMap, null, 2))
|
||||
}
|
||||
|
||||
showSSHForm(netMap.peers, ipn)
|
||||
showSSHPeers(netMap.peers, ipn)
|
||||
}
|
||||
|
||||
export function notifyBrowseToURL(ipn: IPN, url: string) {
|
||||
export function notifyBrowseToURL(ipn, url) {
|
||||
showLoginURL(url)
|
||||
}
|
||||
77
cmd/tsconnect/src/ssh.js
Normal file
77
cmd/tsconnect/src/ssh.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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.
|
||||
|
||||
import { Terminal } from "xterm"
|
||||
|
||||
export function showSSHPeers(peers, ipn) {
|
||||
const peersNode = document.getElementById("peers")
|
||||
peersNode.innerHTML = ""
|
||||
|
||||
const sshPeers = peers.filter((p) => p.tailscaleSSHEnabled)
|
||||
if (!sshPeers.length) {
|
||||
peersNode.textContent = "No machines have Tailscale SSH installed."
|
||||
return
|
||||
}
|
||||
|
||||
for (const peer of sshPeers) {
|
||||
const peerNode = document.createElement("div")
|
||||
peerNode.className = "peer"
|
||||
const nameNode = document.createElement("div")
|
||||
nameNode.className = "name"
|
||||
nameNode.textContent = peer.name
|
||||
peerNode.appendChild(nameNode)
|
||||
|
||||
const sshButtonNode = document.createElement("button")
|
||||
sshButtonNode.className = "ssh"
|
||||
sshButtonNode.addEventListener("click", function () {
|
||||
ssh(peer.name, ipn)
|
||||
})
|
||||
sshButtonNode.textContent = "SSH"
|
||||
peerNode.appendChild(sshButtonNode)
|
||||
|
||||
peersNode.appendChild(peerNode)
|
||||
}
|
||||
}
|
||||
|
||||
export function hideSSHPeers() {
|
||||
const peersNode = document.getElementById("peers")
|
||||
peersNode.innerHTML = ""
|
||||
}
|
||||
|
||||
function ssh(hostname, ipn) {
|
||||
const termContainerNode = document.createElement("div")
|
||||
termContainerNode.className = "term-container"
|
||||
document.body.appendChild(termContainerNode)
|
||||
|
||||
const term = new Terminal({
|
||||
cursorBlink: true,
|
||||
})
|
||||
term.open(termContainerNode)
|
||||
|
||||
// Cancel wheel events from scrolling the page if the terminal has scrollback
|
||||
termContainerNode.addEventListener("wheel", (e) => {
|
||||
if (term.buffer.active.baseY > 0) {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
let onDataHook
|
||||
term.onData((e) => {
|
||||
onDataHook?.(e)
|
||||
})
|
||||
|
||||
term.focus()
|
||||
|
||||
ipn.ssh(
|
||||
hostname,
|
||||
(input) => term.write(input),
|
||||
(hook) => (onDataHook = hook),
|
||||
term.rows,
|
||||
term.cols,
|
||||
() => {
|
||||
term.dispose()
|
||||
termContainerNode.remove()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import { Terminal } from "xterm"
|
||||
|
||||
export function showSSHForm(peers: IPNNetMapPeerNode[], ipn: IPN) {
|
||||
const formNode = document.getElementById("ssh-form") as HTMLDivElement
|
||||
const noSSHNode = document.getElementById("no-ssh") as HTMLDivElement
|
||||
|
||||
const sshPeers = peers.filter(
|
||||
(p) => p.tailscaleSSHEnabled && p.online !== false
|
||||
)
|
||||
if (sshPeers.length == 0) {
|
||||
formNode.classList.add("hidden")
|
||||
noSSHNode.classList.remove("hidden")
|
||||
return
|
||||
}
|
||||
sshPeers.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
const selectNode = formNode.querySelector("select")!
|
||||
selectNode.innerHTML = ""
|
||||
for (const p of sshPeers) {
|
||||
const option = document.createElement("option")
|
||||
option.textContent = p.name.split(".")[0]
|
||||
option.value = p.name
|
||||
selectNode.appendChild(option)
|
||||
}
|
||||
|
||||
const usernameNode = formNode.querySelector(".username") as HTMLInputElement
|
||||
formNode.onsubmit = (e) => {
|
||||
e.preventDefault()
|
||||
const hostname = selectNode.value
|
||||
ssh(hostname, usernameNode.value, ipn)
|
||||
}
|
||||
|
||||
noSSHNode.classList.add("hidden")
|
||||
formNode.classList.remove("hidden")
|
||||
}
|
||||
|
||||
export function hideSSHForm() {
|
||||
const formNode = document.getElementById("ssh-form") as HTMLDivElement
|
||||
formNode.classList.add("hidden")
|
||||
}
|
||||
|
||||
function ssh(hostname: string, username: string, ipn: IPN) {
|
||||
const termContainerNode = document.createElement("div")
|
||||
termContainerNode.className = "p-3"
|
||||
document.body.appendChild(termContainerNode)
|
||||
|
||||
const term = new Terminal({
|
||||
cursorBlink: true,
|
||||
})
|
||||
term.open(termContainerNode)
|
||||
|
||||
// Cancel wheel events from scrolling the page if the terminal has scrollback
|
||||
termContainerNode.addEventListener("wheel", (e) => {
|
||||
if (term.buffer.active.baseY > 0) {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
let onDataHook: ((data: string) => void) | undefined
|
||||
term.onData((e) => {
|
||||
onDataHook?.(e)
|
||||
})
|
||||
|
||||
term.focus()
|
||||
|
||||
ipn.ssh(hostname, username, {
|
||||
writeFn: (input) => term.write(input),
|
||||
setReadFn: (hook) => (onDataHook = hook),
|
||||
rows: term.rows,
|
||||
cols: term.cols,
|
||||
onDone: () => {
|
||||
term.dispose()
|
||||
termContainerNode.remove()
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* @fileoverview Type definitions for types exported by the wasm_js.go Go
|
||||
* module. Not actually a .d.ts file so that we can use enums from it in
|
||||
* esbuild's simplified TypeScript compiler (see https://github.com/evanw/esbuild/issues/2298#issuecomment-1146378367)
|
||||
*/
|
||||
|
||||
declare global {
|
||||
function newIPN(config: IPNConfig): IPN
|
||||
|
||||
interface IPN {
|
||||
run(callbacks: IPNCallbacks): void
|
||||
login(): void
|
||||
logout(): void
|
||||
ssh(
|
||||
host: string,
|
||||
username: string,
|
||||
termConfig: {
|
||||
writeFn: (data: string) => void
|
||||
setReadFn: (readFn: (data: string) => void) => void
|
||||
rows: number
|
||||
cols: number
|
||||
onDone: () => void
|
||||
}
|
||||
): void
|
||||
}
|
||||
|
||||
interface IPNStateStorage {
|
||||
setState(id: string, value: string): void
|
||||
getState(id: string): string
|
||||
}
|
||||
|
||||
type IPNConfig = {
|
||||
stateStorage?: IPNStateStorage
|
||||
}
|
||||
|
||||
type IPNCallbacks = {
|
||||
notifyState: (state: IPNState) => void
|
||||
notifyNetMap: (netMapStr: string) => void
|
||||
notifyBrowseToURL: (url: string) => void
|
||||
notifyPanicRecover: (err: string) => void
|
||||
}
|
||||
|
||||
type IPNNetMap = {
|
||||
self: IPNNetMapSelfNode
|
||||
peers: IPNNetMapPeerNode[]
|
||||
}
|
||||
|
||||
type IPNNetMapNode = {
|
||||
name: string
|
||||
addresses: string[]
|
||||
machineKey: string
|
||||
nodeKey: string
|
||||
}
|
||||
|
||||
type IPNNetMapSelfNode = IPNNetMapNode & {
|
||||
machineStatus: IPNMachineStatus
|
||||
}
|
||||
|
||||
type IPNNetMapPeerNode = IPNNetMapNode & {
|
||||
online?: boolean
|
||||
tailscaleSSHEnabled: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/** Mirrors values from ipn/backend.go */
|
||||
export const enum IPNState {
|
||||
NoState = 0,
|
||||
InUseOtherUser = 1,
|
||||
NeedsLogin = 2,
|
||||
NeedsMachineAuth = 3,
|
||||
Stopped = 4,
|
||||
Starting = 5,
|
||||
Running = 6,
|
||||
}
|
||||
|
||||
/** Mirrors values from MachineStatus in tailcfg.go */
|
||||
export const enum IPNMachineStatus {
|
||||
MachineUnknown = 0,
|
||||
MachineUnauthorized = 1,
|
||||
MachineAuthorized = 2,
|
||||
MachineInvalid = 3,
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html", "./src/**/*.ts"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"isolatedModules": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -18,9 +18,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
addr = flag.String("addr", ":9090", "address to listen on")
|
||||
distDir = flag.String("distdir", "./dist", "path of directory to place build output in")
|
||||
yarnPath = flag.String("yarnpath", "../../tool/yarn", "path yarn executable used to install JavaScript dependencies")
|
||||
addr = flag.String("addr", ":9090", "address to listen on")
|
||||
distDir = flag.String("distdir", "./dist", "path of directory to place build output in")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -19,12 +19,12 @@ import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
@@ -78,10 +78,10 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
if err := ns.Start(); err != nil {
|
||||
log.Fatalf("failed to start netstack: %v", err)
|
||||
}
|
||||
dialer.UseNetstackForIP = func(ip netip.Addr) bool {
|
||||
dialer.UseNetstackForIP = func(ip netaddr.IP) bool {
|
||||
return true
|
||||
}
|
||||
dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) {
|
||||
dialer.NetstackDialTCP = func(ctx context.Context, dst netaddr.IPPort) (net.Conn, error) {
|
||||
return ns.DialContextTCP(ctx, dst)
|
||||
}
|
||||
|
||||
@@ -114,7 +114,6 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
notifyState(state: int): void,
|
||||
notifyNetMap(netMap: object): void,
|
||||
notifyBrowseToURL(url: string): void,
|
||||
notifyPanicRecover(err: string): void,
|
||||
})`)
|
||||
return nil
|
||||
}
|
||||
@@ -138,14 +137,17 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
return nil
|
||||
}),
|
||||
"ssh": js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
if len(args) != 3 {
|
||||
log.Printf("Usage: ssh(hostname, userName, termConfig)")
|
||||
if len(args) != 6 {
|
||||
log.Printf("Usage: ssh(hostname, writeFn, readFn, rows, cols, onDone)")
|
||||
return nil
|
||||
}
|
||||
go jsIPN.ssh(
|
||||
args[0].String(),
|
||||
args[1].String(),
|
||||
args[2])
|
||||
args[1],
|
||||
args[2],
|
||||
args[3].Int(),
|
||||
args[4].Int(),
|
||||
args[5])
|
||||
return nil
|
||||
}),
|
||||
}
|
||||
@@ -164,45 +166,30 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
||||
notifyState(ipn.NoState)
|
||||
|
||||
i.lb.SetNotifyCallback(func(n ipn.Notify) {
|
||||
// Panics in the notify callback are likely due to be due to bugs in
|
||||
// this bridging module (as opposed to actual bugs in Tailscale) and
|
||||
// thus may be recoverable. Let the UI know, and allow the user to
|
||||
// choose if they want to reload the page.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Panic recovered:", r)
|
||||
jsCallbacks.Call("notifyPanicRecover", fmt.Sprint(r))
|
||||
}
|
||||
}()
|
||||
log.Printf("NOTIFY: %+v", n)
|
||||
if n.State != nil {
|
||||
notifyState(*n.State)
|
||||
}
|
||||
if nm := n.NetMap; nm != nil && i.lb.State() == ipn.Running {
|
||||
if nm := n.NetMap; nm != nil {
|
||||
jsNetMap := jsNetMap{
|
||||
Self: jsNetMapSelfNode{
|
||||
jsNetMapNode: jsNetMapNode{
|
||||
Name: nm.Name,
|
||||
Addresses: mapSlice(nm.Addresses, func(a netip.Prefix) string { return a.Addr().String() }),
|
||||
Addresses: mapSlice(nm.Addresses, func(a netaddr.IPPrefix) string { return a.IP().String() }),
|
||||
NodeKey: nm.NodeKey.String(),
|
||||
MachineKey: nm.MachineKey.String(),
|
||||
},
|
||||
MachineStatus: int(nm.MachineStatus),
|
||||
},
|
||||
Peers: mapSlice(nm.Peers, func(p *tailcfg.Node) jsNetMapPeerNode {
|
||||
name := p.Name
|
||||
if name == "" {
|
||||
// In practice this should only happen for Hello.
|
||||
name = p.Hostinfo.Hostname()
|
||||
}
|
||||
return jsNetMapPeerNode{
|
||||
jsNetMapNode: jsNetMapNode{
|
||||
Name: name,
|
||||
Addresses: mapSlice(p.Addresses, func(a netip.Prefix) string { return a.Addr().String() }),
|
||||
Name: p.Name,
|
||||
Addresses: mapSlice(p.Addresses, func(a netaddr.IPPrefix) string { return a.IP().String() }),
|
||||
MachineKey: p.Machine.String(),
|
||||
NodeKey: p.Key.String(),
|
||||
},
|
||||
Online: p.Online,
|
||||
Online: *p.Online,
|
||||
TailscaleSSHEnabled: p.Hostinfo.TailscaleSSHEnabled(),
|
||||
}
|
||||
}),
|
||||
@@ -256,13 +243,7 @@ func (i *jsIPN) logout() {
|
||||
go i.lb.Logout()
|
||||
}
|
||||
|
||||
func (i *jsIPN) ssh(host, username string, termConfig js.Value) {
|
||||
writeFn := termConfig.Get("writeFn")
|
||||
setReadFn := termConfig.Get("setReadFn")
|
||||
rows := termConfig.Get("rows").Int()
|
||||
cols := termConfig.Get("cols").Int()
|
||||
onDone := termConfig.Get("onDone")
|
||||
|
||||
func (i *jsIPN) ssh(host string, writeFn js.Value, setReadFn js.Value, rows, cols int, onDone js.Value) {
|
||||
defer onDone.Invoke()
|
||||
|
||||
write := func(s string) {
|
||||
@@ -283,7 +264,6 @@ func (i *jsIPN) ssh(host, username string, termConfig js.Value) {
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
User: username,
|
||||
}
|
||||
|
||||
sshConn, _, _, err := ssh.NewClientConn(c, host, config)
|
||||
@@ -359,10 +339,11 @@ type jsNetMap struct {
|
||||
}
|
||||
|
||||
type jsNetMapNode struct {
|
||||
Name string `json:"name"`
|
||||
Addresses []string `json:"addresses"`
|
||||
MachineKey string `json:"machineKey"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
Name string `json:"name"`
|
||||
Addresses []string `json:"addresses"`
|
||||
MachineStatus int `json:"machineStatus"`
|
||||
MachineKey string `json:"machineKey"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
}
|
||||
|
||||
type jsNetMapSelfNode struct {
|
||||
@@ -372,8 +353,8 @@ type jsNetMapSelfNode struct {
|
||||
|
||||
type jsNetMapPeerNode struct {
|
||||
jsNetMapNode
|
||||
Online *bool `json:"online,omitempty"`
|
||||
TailscaleSSHEnabled bool `json:"tailscaleSSHEnabled"`
|
||||
Online bool `json:"online"`
|
||||
TailscaleSSHEnabled bool `json:"tailscaleSSHEnabled"`
|
||||
}
|
||||
|
||||
type jsStateStore struct {
|
||||
|
||||
@@ -2,63 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
|
||||
"@nodelib/fs.walk@^1.2.3":
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
|
||||
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
|
||||
dependencies:
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@types/golang-wasm-exec@^1.15.0":
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/golang-wasm-exec/-/golang-wasm-exec-1.15.0.tgz#d0aafbb2b0dc07eaf45dfb83bfb6cdd5b2b3c55c"
|
||||
integrity sha512-FrL97mp7WW8LqNinVkzTVKOIQKuYjQqgucnh41+1vRQ+bf1LT8uh++KRf9otZPXsa6H1p8ruIGz1BmCGttOL6Q==
|
||||
|
||||
"@types/node@*":
|
||||
version "18.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.1.tgz#828e4785ccca13f44e2fb6852ae0ef11e3e20ba5"
|
||||
integrity sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg==
|
||||
|
||||
"@types/qrcode@^1.4.2":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74"
|
||||
integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
acorn-node@^1.8.2:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
|
||||
integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
|
||||
dependencies:
|
||||
acorn "^7.0.0"
|
||||
acorn-walk "^7.0.0"
|
||||
xtend "^4.0.2"
|
||||
|
||||
acorn-walk@^7.0.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
|
||||
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
|
||||
|
||||
acorn@^7.0.0:
|
||||
version "7.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
@@ -71,56 +14,11 @@ ansi-styles@^4.0.0:
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
||||
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
||||
dependencies:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
arg@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
||||
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||
|
||||
braces@^3.0.2, braces@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
camelcase-css@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
camelcase@^5.0.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
||||
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
||||
|
||||
chokidar@^3.5.3:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
dependencies:
|
||||
anymatch "~3.1.2"
|
||||
braces "~3.0.2"
|
||||
glob-parent "~5.1.2"
|
||||
is-binary-path "~2.1.0"
|
||||
is-glob "~4.0.1"
|
||||
normalize-path "~3.0.0"
|
||||
readdirp "~3.6.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
cliui@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
|
||||
@@ -137,50 +35,21 @@ color-convert@^2.0.1:
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@^1.1.4, color-name@~1.1.4:
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
cssesc@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
decamelize@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==
|
||||
|
||||
detective@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
|
||||
integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
|
||||
dependencies:
|
||||
acorn-node "^1.8.2"
|
||||
defined "^1.0.0"
|
||||
minimist "^1.2.6"
|
||||
|
||||
didyoumean@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
|
||||
|
||||
dijkstrajs@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
|
||||
integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==
|
||||
|
||||
dlv@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
|
||||
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
@@ -191,31 +60,6 @@ encode-utf8@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda"
|
||||
integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
|
||||
|
||||
fast-glob@^3.2.11:
|
||||
version "3.2.11"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
|
||||
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "^2.0.2"
|
||||
"@nodelib/fs.walk" "^1.2.3"
|
||||
glob-parent "^5.1.2"
|
||||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
||||
integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
|
||||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
find-up@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||
@@ -224,83 +68,16 @@ find-up@^4.1.0:
|
||||
locate-path "^5.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
get-caller-file@^2.0.1:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob-parent@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
|
||||
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
|
||||
dependencies:
|
||||
is-glob "^4.0.3"
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-core-module@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
|
||||
integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-fullwidth-code-point@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
||||
|
||||
is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
lilconfig@^2.0.5:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
|
||||
integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
|
||||
|
||||
locate-path@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
|
||||
@@ -308,39 +85,6 @@ locate-path@^5.0.0:
|
||||
dependencies:
|
||||
p-locate "^4.1.0"
|
||||
|
||||
merge2@^1.3.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
micromatch@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
|
||||
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
||||
dependencies:
|
||||
braces "^3.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
minimist@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||
|
||||
nanoid@^3.3.4:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
object-hash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
|
||||
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
|
||||
|
||||
p-limit@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
|
||||
@@ -365,84 +109,11 @@ path-exists@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
|
||||
|
||||
path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
picocolors@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
|
||||
|
||||
pngjs@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
|
||||
integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
|
||||
|
||||
postcss-import@^14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
|
||||
integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
|
||||
dependencies:
|
||||
postcss-value-parser "^4.0.0"
|
||||
read-cache "^1.0.0"
|
||||
resolve "^1.1.7"
|
||||
|
||||
postcss-js@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
|
||||
integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
|
||||
dependencies:
|
||||
camelcase-css "^2.0.1"
|
||||
|
||||
postcss-load-config@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
|
||||
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
|
||||
dependencies:
|
||||
lilconfig "^2.0.5"
|
||||
yaml "^1.10.2"
|
||||
|
||||
postcss-nested@5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc"
|
||||
integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
|
||||
dependencies:
|
||||
postcss-selector-parser "^6.0.6"
|
||||
|
||||
postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.6:
|
||||
version "6.0.10"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
|
||||
integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.4.14:
|
||||
version "8.4.14"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
|
||||
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
|
||||
dependencies:
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
qrcode@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
|
||||
@@ -453,30 +124,6 @@ qrcode@^1.5.0:
|
||||
pngjs "^5.0.0"
|
||||
yargs "^15.3.1"
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
quick-lru@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
||||
integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
|
||||
dependencies:
|
||||
pify "^2.3.0"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
@@ -487,37 +134,11 @@ require-main-filename@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
resolve@^1.1.7, resolve@^1.22.1:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
dependencies:
|
||||
is-core-module "^2.9.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
reusify@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
|
||||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
@@ -534,56 +155,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
supports-preserve-symlinks-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
tailwindcss@^3.1.6:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.6.tgz#bcb719357776c39e6376a8d84e9834b2b19a49f1"
|
||||
integrity sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==
|
||||
dependencies:
|
||||
arg "^5.0.2"
|
||||
chokidar "^3.5.3"
|
||||
color-name "^1.1.4"
|
||||
detective "^5.2.1"
|
||||
didyoumean "^1.2.2"
|
||||
dlv "^1.1.3"
|
||||
fast-glob "^3.2.11"
|
||||
glob-parent "^6.0.2"
|
||||
is-glob "^4.0.3"
|
||||
lilconfig "^2.0.5"
|
||||
normalize-path "^3.0.0"
|
||||
object-hash "^3.0.0"
|
||||
picocolors "^1.0.0"
|
||||
postcss "^8.4.14"
|
||||
postcss-import "^14.1.0"
|
||||
postcss-js "^4.0.0"
|
||||
postcss-load-config "^3.1.4"
|
||||
postcss-nested "5.0.6"
|
||||
postcss-selector-parser "^6.0.10"
|
||||
postcss-value-parser "^4.2.0"
|
||||
quick-lru "^5.1.1"
|
||||
resolve "^1.22.1"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
typescript@^4.7.4:
|
||||
version "4.7.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
|
||||
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
which-module@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
||||
@@ -598,11 +169,6 @@ wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
xtend@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
xterm@^4.18.0:
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.18.0.tgz#a1f6ab2c330c3918fb094ae5f4c2562987398ea1"
|
||||
@@ -613,11 +179,6 @@ y18n@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
|
||||
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
|
||||
|
||||
yaml@^1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
yargs-parser@^18.1.2:
|
||||
version "18.1.3"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
|
||||
|
||||
@@ -11,4 +11,3 @@
|
||||
// Its functionality moved into tailscaled.
|
||||
//
|
||||
// See https://github.com/tailscale/tailscale/issues/3802
|
||||
package main
|
||||
|
||||
@@ -7,14 +7,15 @@ package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices
|
||||
|
||||
type StructWithoutPtrs struct {
|
||||
Int int
|
||||
Pfx netip.Prefix
|
||||
Pfx netaddr.IPPrefix
|
||||
}
|
||||
|
||||
type Map struct {
|
||||
@@ -53,6 +54,6 @@ type StructWithSlices struct {
|
||||
Ints []*int
|
||||
|
||||
Slice []string
|
||||
Prefixes []netip.Prefix
|
||||
Prefixes []netaddr.IPPrefix
|
||||
Data []byte
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// Clone makes a deep copy of StructWithPtrs.
|
||||
@@ -50,7 +50,7 @@ func (src *StructWithoutPtrs) Clone() *StructWithoutPtrs {
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _StructWithoutPtrsCloneNeedsRegeneration = StructWithoutPtrs(struct {
|
||||
Int int
|
||||
Pfx netip.Prefix
|
||||
Pfx netaddr.IPPrefix
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of Map.
|
||||
@@ -178,6 +178,6 @@ var _StructWithSlicesCloneNeedsRegeneration = StructWithSlices(struct {
|
||||
Structs []StructWithPtrs
|
||||
Ints []*int
|
||||
Slice []string
|
||||
Prefixes []netip.Prefix
|
||||
Prefixes []netaddr.IPPrefix
|
||||
Data []byte
|
||||
}{})
|
||||
|
||||
@@ -9,9 +9,9 @@ package tests
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/netip"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/types/views"
|
||||
)
|
||||
|
||||
@@ -134,13 +134,13 @@ func (v *StructWithoutPtrsView) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v StructWithoutPtrsView) Int() int { return v.ж.Int }
|
||||
func (v StructWithoutPtrsView) Pfx() netip.Prefix { return v.ж.Pfx }
|
||||
func (v StructWithoutPtrsView) Int() int { return v.ж.Int }
|
||||
func (v StructWithoutPtrsView) Pfx() netaddr.IPPrefix { return v.ж.Pfx }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _StructWithoutPtrsViewNeedsRegeneration = StructWithoutPtrs(struct {
|
||||
Int int
|
||||
Pfx netip.Prefix
|
||||
Pfx netaddr.IPPrefix
|
||||
}{})
|
||||
|
||||
// View returns a readonly view of Map.
|
||||
@@ -311,6 +311,6 @@ var _StructWithSlicesViewNeedsRegeneration = StructWithSlices(struct {
|
||||
Structs []StructWithPtrs
|
||||
Ints []*int
|
||||
Slice []string
|
||||
Prefixes []netip.Prefix
|
||||
Prefixes []netaddr.IPPrefix
|
||||
Data []byte
|
||||
}{})
|
||||
|
||||
@@ -177,7 +177,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
|
||||
case "byte":
|
||||
it.Import("go4.org/mem")
|
||||
writeTemplate("byteSliceField")
|
||||
case "inet.af/netip.Prefix", "net/netip.Prefix":
|
||||
case "inet.af/netaddr.IPPrefix":
|
||||
it.Import("tailscale.com/types/views")
|
||||
writeTemplate("ipPrefixSliceField")
|
||||
default:
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -27,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/control/controlknobs"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
@@ -129,7 +129,7 @@ type Options struct {
|
||||
// Pinger is the LocalBackend.Ping method.
|
||||
type Pinger interface {
|
||||
// Ping is a request to do a ping with the peer handling the given IP.
|
||||
Ping(ctx context.Context, ip netip.Addr, pingType tailcfg.PingType) (*ipnstate.PingResult, error)
|
||||
Ping(ctx context.Context, ip netaddr.IP, pingType tailcfg.PingType) (*ipnstate.PingResult, error)
|
||||
}
|
||||
|
||||
type Decompressor interface {
|
||||
@@ -1167,8 +1167,8 @@ func TrimWGConfig() opt.Bool {
|
||||
// It should not return false positives.
|
||||
//
|
||||
// TODO(bradfitz): Change controlclient.Options.SkipIPForwardingCheck into a
|
||||
// func([]netip.Prefix) error signature instead.
|
||||
func ipForwardingBroken(routes []netip.Prefix, state *interfaces.State) bool {
|
||||
// func([]netaddr.IPPrefix) error signature instead.
|
||||
func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool {
|
||||
warn, err := netutil.CheckIPForwarding(routes, state)
|
||||
if err != nil {
|
||||
// Oh well, we tried. This is just for debugging.
|
||||
@@ -1408,7 +1408,7 @@ func (c *Direct) DoNoiseRequest(req *http.Request) (*http.Response, error) {
|
||||
// doPingerPing sends a Ping to pr.IP using pinger, and sends an http request back to
|
||||
// pr.URL with ping response data.
|
||||
func doPingerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest, pinger Pinger, pingType tailcfg.PingType) {
|
||||
if pr.URL == "" || !pr.IP.IsValid() || pinger == nil {
|
||||
if pr.URL == "" || pr.IP.IsZero() || pinger == nil {
|
||||
logf("invalid ping request: missing url, ip or pinger")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/tsdial"
|
||||
@@ -86,7 +86,7 @@ func TestNewDirect(t *testing.T) {
|
||||
func fakeEndpoints(ports ...uint16) (ret []tailcfg.Endpoint) {
|
||||
for _, port := range ports {
|
||||
ret = append(ret, tailcfg.Endpoint{
|
||||
Addr: netip.AddrPortFrom(netip.Addr{}, port),
|
||||
Addr: netaddr.IPPortFrom(netaddr.IP{}, port),
|
||||
})
|
||||
}
|
||||
return
|
||||
|
||||
@@ -7,9 +7,9 @@ package controlclient
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/netip"
|
||||
"sort"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
@@ -303,13 +303,13 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
|
||||
|
||||
var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY")
|
||||
|
||||
func filterSelfAddresses(in []netip.Prefix) (ret []netip.Prefix) {
|
||||
func filterSelfAddresses(in []netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
|
||||
switch {
|
||||
default:
|
||||
return in
|
||||
case debugSelfIPv6Only:
|
||||
for _, a := range in {
|
||||
if a.Addr().Is6() {
|
||||
if a.IP().Is6() {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"golang.org/x/time/rate"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
@@ -597,17 +597,17 @@ func (c *Client) setSendRateLimiter(sm ServerInfoMessage) {
|
||||
//
|
||||
// If the client is broken in some previously detectable way, it
|
||||
// returns an error.
|
||||
func (c *Client) LocalAddr() (netip.AddrPort, error) {
|
||||
func (c *Client) LocalAddr() (netaddr.IPPort, error) {
|
||||
readErr, _ := c.readErr.Load().(error)
|
||||
if readErr != nil {
|
||||
return netip.AddrPort{}, readErr
|
||||
return netaddr.IPPort{}, readErr
|
||||
}
|
||||
if c.nc == nil {
|
||||
return netip.AddrPort{}, errors.New("nil conn")
|
||||
return netaddr.IPPort{}, errors.New("nil conn")
|
||||
}
|
||||
a := c.nc.LocalAddr()
|
||||
if a == nil {
|
||||
return netip.AddrPort{}, errors.New("nil addr")
|
||||
return netaddr.IPPort{}, errors.New("nil addr")
|
||||
}
|
||||
return netip.ParseAddrPort(a.String())
|
||||
return netaddr.ParseIPPort(a.String())
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@@ -37,6 +36,7 @@ import (
|
||||
"go4.org/mem"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/time/rate"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale"
|
||||
"tailscale.com/disco"
|
||||
"tailscale.com/envknob"
|
||||
@@ -162,8 +162,8 @@ type Server struct {
|
||||
// src.
|
||||
sentTo map[key.NodePublic]map[key.NodePublic]int64 // src => dst => dst's latest sclient.connNum
|
||||
|
||||
// maps from netip.AddrPort to a client's public key
|
||||
keyOfAddr map[netip.AddrPort]key.NodePublic
|
||||
// maps from netaddr.IPPort to a client's public key
|
||||
keyOfAddr map[netaddr.IPPort]key.NodePublic
|
||||
}
|
||||
|
||||
// clientSet represents 1 or more *sclients.
|
||||
@@ -314,7 +314,7 @@ func NewServer(privateKey key.NodePrivate, logf logger.Logf) *Server {
|
||||
watchers: map[*sclient]bool{},
|
||||
sentTo: map[key.NodePublic]map[key.NodePublic]int64{},
|
||||
avgQueueDuration: new(uint64),
|
||||
keyOfAddr: map[netip.AddrPort]key.NodePublic{},
|
||||
keyOfAddr: map[netaddr.IPPort]key.NodePublic{},
|
||||
}
|
||||
s.initMetacert()
|
||||
s.packetsRecvDisco = s.packetsRecvByKind.Get("disco")
|
||||
@@ -663,7 +663,7 @@ func (s *Server) accept(ctx context.Context, nc Conn, brw *bufio.ReadWriter, rem
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
remoteIPPort, _ := netip.ParseAddrPort(remoteAddr)
|
||||
remoteIPPort, _ := netaddr.ParseIPPort(remoteAddr)
|
||||
|
||||
c := &sclient{
|
||||
connNum: connNum,
|
||||
@@ -1246,7 +1246,7 @@ type sclient struct {
|
||||
logf logger.Logf
|
||||
done <-chan struct{} // closed when connection closes
|
||||
remoteAddr string // usually ip:port from net.Conn.RemoteAddr().String()
|
||||
remoteIPPort netip.AddrPort // zero if remoteAddr is not ip:port.
|
||||
remoteIPPort netaddr.IPPort // zero if remoteAddr is not ip:port.
|
||||
sendQueue chan pkt // packets queued to this client; never closed
|
||||
discoSendQueue chan pkt // important packets queued to this client; never closed
|
||||
sendPongCh chan [8]byte // pong replies to send to the client; never closed
|
||||
@@ -1759,8 +1759,8 @@ type BytesSentRecv struct {
|
||||
|
||||
// parseSSOutput parses the output from the specific call to ss in ServeDebugTraffic.
|
||||
// Separated out for ease of testing.
|
||||
func parseSSOutput(raw string) map[netip.AddrPort]BytesSentRecv {
|
||||
newState := map[netip.AddrPort]BytesSentRecv{}
|
||||
func parseSSOutput(raw string) map[netaddr.IPPort]BytesSentRecv {
|
||||
newState := map[netaddr.IPPort]BytesSentRecv{}
|
||||
// parse every 2 lines and get src and dst ips, and kv pairs
|
||||
lines := strings.Split(raw, "\n")
|
||||
for i := 0; i < len(lines); i += 2 {
|
||||
@@ -1768,7 +1768,7 @@ func parseSSOutput(raw string) map[netip.AddrPort]BytesSentRecv {
|
||||
if len(ipInfo) < 5 {
|
||||
continue
|
||||
}
|
||||
src, err := netip.ParseAddrPort(ipInfo[4])
|
||||
src, err := netaddr.ParseIPPort(ipInfo[4])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -1793,7 +1793,7 @@ func parseSSOutput(raw string) map[netip.AddrPort]BytesSentRecv {
|
||||
}
|
||||
|
||||
func (s *Server) ServeDebugTraffic(w http.ResponseWriter, r *http.Request) {
|
||||
prevState := map[netip.AddrPort]BytesSentRecv{}
|
||||
prevState := map[netaddr.IPPort]BytesSentRecv{}
|
||||
enc := json.NewEncoder(w)
|
||||
for r.Context().Err() == nil {
|
||||
output, err := exec.Command("ss", "-i", "-H", "-t").Output()
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -31,6 +30,7 @@ import (
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/derp"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/net/dnscache"
|
||||
@@ -579,11 +579,11 @@ func (c *Client) dialContext(ctx context.Context, proto, addr string) (net.Conn,
|
||||
// address (given in s) is valid. An empty value means to dial, but to
|
||||
// use DNS. The predicate function reports whether the non-empty
|
||||
// string s contained a valid IP address of the right family.
|
||||
func shouldDialProto(s string, pred func(netip.Addr) bool) bool {
|
||||
func shouldDialProto(s string, pred func(netaddr.IP) bool) bool {
|
||||
if s == "" {
|
||||
return true
|
||||
}
|
||||
ip, _ := netip.ParseAddr(s)
|
||||
ip, _ := netaddr.ParseIP(s)
|
||||
return pred(ip)
|
||||
}
|
||||
|
||||
@@ -651,10 +651,10 @@ func (c *Client) dialNode(ctx context.Context, n *tailcfg.DERPNode) (net.Conn, e
|
||||
}
|
||||
}()
|
||||
}
|
||||
if shouldDialProto(n.IPv4, netip.Addr.Is4) {
|
||||
if shouldDialProto(n.IPv4, netaddr.IP.Is4) {
|
||||
startDial(n.IPv4, "tcp4")
|
||||
}
|
||||
if shouldDialProto(n.IPv6, netip.Addr.Is6) {
|
||||
if shouldDialProto(n.IPv6, netaddr.IP.Is6) {
|
||||
startDial(n.IPv6, "tcp6")
|
||||
}
|
||||
if nwait == 0 {
|
||||
@@ -839,15 +839,15 @@ func (c *Client) SendPing(data [8]byte) error {
|
||||
|
||||
// LocalAddr reports c's local TCP address, without any implicit
|
||||
// connect or reconnect.
|
||||
func (c *Client) LocalAddr() (netip.AddrPort, error) {
|
||||
func (c *Client) LocalAddr() (netaddr.IPPort, error) {
|
||||
c.mu.Lock()
|
||||
closed, client := c.closed, c.client
|
||||
c.mu.Unlock()
|
||||
if closed {
|
||||
return netip.AddrPort{}, ErrClientClosed
|
||||
return netaddr.IPPort{}, ErrClientClosed
|
||||
}
|
||||
if client == nil {
|
||||
return netip.AddrPort{}, errors.New("client not connected")
|
||||
return netaddr.IPPort{}, errors.New("client not connected")
|
||||
}
|
||||
return client.LocalAddr()
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"go4.org/mem"
|
||||
"tailscale.com/net/netaddr"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/types/key"
|
||||
)
|
||||
|
||||
@@ -173,7 +172,7 @@ type CallMeMaybe struct {
|
||||
// in this field, but might not yet be in control's endpoints.
|
||||
// (And in the future, control will stop distributing endpoints
|
||||
// when clients are suitably new.)
|
||||
MyNumber []netip.AddrPort
|
||||
MyNumber []netaddr.IPPort
|
||||
}
|
||||
|
||||
const epLength = 16 + 2 // 16 byte IP address + 2 byte port
|
||||
@@ -181,7 +180,7 @@ const epLength = 16 + 2 // 16 byte IP address + 2 byte port
|
||||
func (m *CallMeMaybe) AppendMarshal(b []byte) []byte {
|
||||
ret, p := appendMsgHeader(b, TypeCallMeMaybe, v0, epLength*len(m.MyNumber))
|
||||
for _, ipp := range m.MyNumber {
|
||||
a := ipp.Addr().As16()
|
||||
a := ipp.IP().As16()
|
||||
copy(p[:], a[:])
|
||||
binary.BigEndian.PutUint16(p[16:], ipp.Port())
|
||||
p = p[epLength:]
|
||||
@@ -194,11 +193,11 @@ func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
|
||||
if len(p)%epLength != 0 || ver != 0 || len(p) == 0 {
|
||||
return m, nil
|
||||
}
|
||||
m.MyNumber = make([]netip.AddrPort, 0, len(p)/epLength)
|
||||
m.MyNumber = make([]netaddr.IPPort, 0, len(p)/epLength)
|
||||
for len(p) > 0 {
|
||||
var a [16]byte
|
||||
copy(a[:], p)
|
||||
m.MyNumber = append(m.MyNumber, netip.AddrPortFrom(
|
||||
m.MyNumber = append(m.MyNumber, netaddr.IPPortFrom(
|
||||
netaddr.IPFrom16(a),
|
||||
binary.BigEndian.Uint16(p[16:18])))
|
||||
p = p[epLength:]
|
||||
@@ -212,7 +211,7 @@ func parseCallMeMaybe(ver uint8, p []byte) (m *CallMeMaybe, err error) {
|
||||
// STUN response.
|
||||
type Pong struct {
|
||||
TxID [12]byte
|
||||
Src netip.AddrPort // 18 bytes (16+2) on the wire; v4-mapped ipv6 for IPv4
|
||||
Src netaddr.IPPort // 18 bytes (16+2) on the wire; v4-mapped ipv6 for IPv4
|
||||
}
|
||||
|
||||
const pongLen = 12 + 16 + 2
|
||||
@@ -220,7 +219,7 @@ const pongLen = 12 + 16 + 2
|
||||
func (m *Pong) AppendMarshal(b []byte) []byte {
|
||||
ret, d := appendMsgHeader(b, TypePong, v0, pongLen)
|
||||
d = d[copy(d, m.TxID[:]):]
|
||||
ip16 := m.Src.Addr().As16()
|
||||
ip16 := m.Src.IP().As16()
|
||||
d = d[copy(d, ip16[:]):]
|
||||
binary.BigEndian.PutUint16(d, m.Src.Port())
|
||||
return ret
|
||||
@@ -237,7 +236,7 @@ func parsePong(ver uint8, p []byte) (m *Pong, err error) {
|
||||
srcIP, _ := netaddr.FromStdIP(net.IP(p[:16]))
|
||||
p = p[16:]
|
||||
port := binary.BigEndian.Uint16(p)
|
||||
m.Src = netip.AddrPortFrom(srcIP, port)
|
||||
m.Src = netaddr.IPPortFrom(srcIP, port)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ package disco
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/types/key"
|
||||
)
|
||||
|
||||
@@ -60,9 +60,9 @@ func TestMarshalAndParse(t *testing.T) {
|
||||
{
|
||||
name: "call_me_maybe_endpoints",
|
||||
m: &CallMeMaybe{
|
||||
MyNumber: []netip.AddrPort{
|
||||
netip.MustParseAddrPort("1.2.3.4:567"),
|
||||
netip.MustParseAddrPort("[2001::3456]:789"),
|
||||
MyNumber: []netaddr.IPPort{
|
||||
netaddr.MustParseIPPort("1.2.3.4:567"),
|
||||
netaddr.MustParseIPPort("[2001::3456]:789"),
|
||||
},
|
||||
},
|
||||
want: "03 00 00 00 00 00 00 00 00 00 00 00 ff ff 01 02 03 04 02 37 20 01 00 00 00 00 00 00 00 00 00 00 00 00 34 56 03 15",
|
||||
@@ -93,8 +93,8 @@ func TestMarshalAndParse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func mustIPPort(s string) netip.AddrPort {
|
||||
ipp, err := netip.ParseAddrPort(s)
|
||||
func mustIPPort(s string) netaddr.IPPort {
|
||||
ipp, err := netaddr.ParseIPPort(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
# Overview
|
||||
|
||||
There are quite a few ways of running Tailscale inside a Kubernetes Cluster, some of the common ones are covered in this doc.
|
||||
|
||||
## Instructions
|
||||
|
||||
### Setup
|
||||
|
||||
1. (Optional) Create the following secret which will automate login.<br>
|
||||
You will need to get an [auth key](https://tailscale.com/kb/1085/auth-keys/) from [Tailscale Admin Console](https://login.tailscale.com/admin/authkeys).<br>
|
||||
If you don't provide the key, you can still authenticate using the url in the logs.
|
||||
@@ -16,13 +12,12 @@ There are quite a few ways of running Tailscale inside a Kubernetes Cluster, som
|
||||
metadata:
|
||||
name: tailscale-auth
|
||||
stringData:
|
||||
TS_AUTH_KEY: tskey-...
|
||||
AUTH_KEY: tskey-...
|
||||
```
|
||||
|
||||
1. Tailscale (v1.16+) supports storing state inside a Kubernetes Secret.
|
||||
|
||||
Configure RBAC to allow the Tailscale pod to read/write the `tailscale` secret.
|
||||
|
||||
```bash
|
||||
export SA_NAME=tailscale
|
||||
export TS_KUBE_SECRET=tailscale-auth
|
||||
@@ -30,7 +25,6 @@ There are quite a few ways of running Tailscale inside a Kubernetes Cluster, som
|
||||
```
|
||||
|
||||
### Sample Sidecar
|
||||
|
||||
Running as a sidecar allows you to directly expose a Kubernetes pod over Tailscale. This is particularly useful if you do not wish to expose a service on the public internet. This method allows bi-directional connectivity between the pod and other devices on the Tailnet. You can use [ACLs](https://tailscale.com/kb/1018/acls/) to control traffic flow.
|
||||
|
||||
1. Create and login to the sample nginx pod with a Tailscale sidecar
|
||||
@@ -46,15 +40,12 @@ Running as a sidecar allows you to directly expose a Kubernetes pod over Tailsca
|
||||
```bash
|
||||
curl http://nginx
|
||||
```
|
||||
|
||||
Or, if you have [MagicDNS](https://tailscale.com/kb/1081/magicdns/) disabled:
|
||||
|
||||
```bash
|
||||
curl "http://$(tailscale ip -4 nginx)"
|
||||
```
|
||||
|
||||
#### Userspace Sidecar
|
||||
|
||||
You can also run the sidecar in userspace mode. The obvious benefit is reducing the amount of permissions Tailscale needs to run, the downside is that for outbound connectivity from the pod to the Tailnet you would need to use either the [SOCKS proxy](https://tailscale.com/kb/1112/userspace-networking) or HTTP proxy.
|
||||
|
||||
1. Create and login to the sample nginx pod with a Tailscale sidecar
|
||||
@@ -70,29 +61,23 @@ You can also run the sidecar in userspace mode. The obvious benefit is reducing
|
||||
```bash
|
||||
curl http://nginx
|
||||
```
|
||||
|
||||
Or, if you have [MagicDNS](https://tailscale.com/kb/1081/magicdns/) disabled:
|
||||
|
||||
```bash
|
||||
curl "http://$(tailscale ip -4 nginx)"
|
||||
```
|
||||
|
||||
### Sample Proxy
|
||||
|
||||
Running a Tailscale proxy allows you to provide inbound connectivity to a Kubernetes Service.
|
||||
|
||||
1. Provide the `ClusterIP` of the service you want to reach by either:
|
||||
|
||||
**Creating a new deployment**
|
||||
|
||||
```bash
|
||||
kubectl create deployment nginx --image nginx
|
||||
kubectl expose deployment nginx --port 80
|
||||
export TS_DEST_IP="$(kubectl get svc nginx -o=jsonpath='{.spec.clusterIP}')"
|
||||
```
|
||||
|
||||
**Using an existing service**
|
||||
|
||||
```bash
|
||||
export TS_DEST_IP="$(kubectl get svc <SVC_NAME> -o=jsonpath='{.spec.clusterIP}')"
|
||||
```
|
||||
@@ -122,7 +107,7 @@ Running a Tailscale proxy allows you to provide inbound connectivity to a Kubern
|
||||
Running a Tailscale [subnet router](https://tailscale.com/kb/1019/subnets/) allows you to access
|
||||
the entire Kubernetes cluster network (assuming NetworkPolicies allow) over Tailscale.
|
||||
|
||||
1. Identify the Pod/Service CIDRs that cover your Kubernetes cluster. These will vary depending on [which CNI](https://kubernetes.io/docs/concepts/cluster-administration/networking/) you are using and on the Cloud Provider you are using. Add these to the `TS_ROUTES` variable as comma-separated values.
|
||||
1. Identify the Pod/Service CIDRs that cover your Kubernetes cluster. These will vary depending on [which CNI](https://kubernetes.io/docs/concepts/cluster-administration/networking/) you are using and on the Cloud Provider you are using. Add these to the `TS_ROUTES` variable as comma-separated values.
|
||||
|
||||
```bash
|
||||
SERVICE_CIDR=10.20.0.0/16
|
||||
@@ -139,7 +124,7 @@ the entire Kubernetes cluster network (assuming NetworkPolicies allow) over Tail
|
||||
```
|
||||
|
||||
1. In the [Tailscale admin console](https://login.tailscale.com/admin/machines), ensure that the
|
||||
routes for the subnet-router are enabled.
|
||||
routes for the subnet-router are enabled.
|
||||
|
||||
1. Make sure that any client you want to connect from has `--accept-routes` enabled.
|
||||
|
||||
@@ -148,8 +133,8 @@ the entire Kubernetes cluster network (assuming NetworkPolicies allow) over Tail
|
||||
```bash
|
||||
# Get the Service IP
|
||||
INTERNAL_IP="$(kubectl get svc <SVC_NAME> -o=jsonpath='{.spec.clusterIP}')"
|
||||
# or, the Pod IP
|
||||
# INTERNAL_IP="$(kubectl get po <POD_NAME> -o=jsonpath='{.status.podIP}')"
|
||||
INTERNAL_PORT=8080
|
||||
# or, the Pod IP
|
||||
# INTERNAL_IP="$(kubectl get po <POD_NAME> -o=jsonpath='{.status.podIP}')"
|
||||
INTERNAL_PORT=8080
|
||||
curl http://$INTERNAL_IP:$INTERNAL_PORT
|
||||
```
|
||||
|
||||
8
go.mod
8
go.mod
@@ -54,7 +54,6 @@ require (
|
||||
github.com/u-root/u-root v0.8.0
|
||||
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
|
||||
go4.org/mem v0.0.0-20210711025021-927187094b94
|
||||
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
@@ -64,10 +63,11 @@ require (
|
||||
golang.org/x/tools v0.1.11
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478
|
||||
golang.zx2c4.com/wireguard/windows v0.4.10
|
||||
gvisor.dev/gvisor v0.0.0-20220801230058-850e42eb4444
|
||||
gvisor.dev/gvisor v0.0.0-20220721202624-0b2c11c2773c
|
||||
honnef.co/go/tools v0.4.0-0.dev.0.20220404092545-59d7a2877f83
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321
|
||||
inet.af/peercred v0.0.0-20210906144145-0893ea02156a
|
||||
inet.af/wf v0.0.0-20220728202103-50d96caab2f6
|
||||
inet.af/wf v0.0.0-20211204062712-86aaea0a7310
|
||||
nhooyr.io/websocket v1.8.7
|
||||
)
|
||||
|
||||
@@ -263,6 +263,8 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/yeya24/promlinter v0.1.0 // indirect
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20220328175248-053ad81199eb // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
|
||||
21
go.sum
21
go.sum
@@ -265,6 +265,7 @@ github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56
|
||||
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -920,6 +921,7 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/peterbourgon/ff/v3 v3.0.0/go.mod h1:UILIFjRH5a/ar8TjXYLTkIvSvekZqPm5Eb/qbGk6CT0=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA=
|
||||
@@ -1241,12 +1243,16 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
|
||||
go4.org/mem v0.0.0-20210711025021-927187094b94 h1:OAAkygi2Js191AJP1Ds42MhJRgeofeKGjuoUqNp1QC4=
|
||||
go4.org/mem v0.0.0-20210711025021-927187094b94/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
|
||||
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf h1:IdwJUzqoIo5lkr2EOyKoe5qipUaEjbOKKY5+fzPBZ3A=
|
||||
go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf/go.mod h1:+QXzaoURFd0rGDIjDNpyIkv+F9R7EmeKorvlKRnhqgA=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -1851,8 +1857,8 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gvisor.dev/gvisor v0.0.0-20220801230058-850e42eb4444 h1:0d3ygmOM5RgQB8rmsZNeAY/7Q98fKt1HrGO2XIp4pDI=
|
||||
gvisor.dev/gvisor v0.0.0-20220801230058-850e42eb4444/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
gvisor.dev/gvisor v0.0.0-20220721202624-0b2c11c2773c h1:frrINYSQqhraHqy23/dWqdNt7mRlsGJJBwGHvI3Q+/c=
|
||||
gvisor.dev/gvisor v0.0.0-20220721202624-0b2c11c2773c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1867,10 +1873,13 @@ honnef.co/go/tools v0.4.0-0.dev.0.20220404092545-59d7a2877f83/go.mod h1:vlRD9XEr
|
||||
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
inet.af/netaddr v0.0.0-20210515010201-ad03edc7c841/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU=
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
|
||||
inet.af/peercred v0.0.0-20210906144145-0893ea02156a h1:qdkS8Q5/i10xU2ArJMKYhVa1DORzBfYS/qA2UK2jheg=
|
||||
inet.af/peercred v0.0.0-20210906144145-0893ea02156a/go.mod h1:FjawnflS/udxX+SvpsMgZfdqx2aykOlkISeAsADi5IU=
|
||||
inet.af/wf v0.0.0-20220728202103-50d96caab2f6 h1:BfgDtKnWJTeu+xI1aOEweXdPwqOhB3IbQUDj1XuftcY=
|
||||
inet.af/wf v0.0.0-20220728202103-50d96caab2f6/go.mod h1:bSAQ38BYbY68uwpasXOTZo22dKGy9SNvI6PZFeKomZE=
|
||||
inet.af/wf v0.0.0-20211204062712-86aaea0a7310 h1:0jKHTf+W75kYRyg5bto1UT+r18QmAz2u/5pAs/fx4zo=
|
||||
inet.af/wf v0.0.0-20211204062712-86aaea0a7310/go.mod h1:ViGMZRA6+RA318D7GCncrjv5gHUrPYrNDejjU12tikA=
|
||||
mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws=
|
||||
mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475/go.mod h1:E4LOcu9JQEtnYXtB1Y51drqh2Qr2Ngk9J3YrRCwcbd0=
|
||||
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
|
||||
|
||||
@@ -1 +1 @@
|
||||
tailscale.go1.19
|
||||
tailscale.go1.18
|
||||
|
||||
@@ -1 +1 @@
|
||||
effe2d16a9ed6c4fd97361e8090bb22acc221075
|
||||
149f7d88f11384083d42ccbcdb31693510385ec6
|
||||
|
||||
@@ -48,17 +48,7 @@ func linuxDeviceModel() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func getQnapQtsVersion(versionInfo string) string {
|
||||
for _, field := range strings.Fields(versionInfo) {
|
||||
if suffix := strings.TrimPrefix(field, "QTSFW_"); suffix != field {
|
||||
return "QTS " + suffix
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func osVersionLinux() string {
|
||||
// TODO(bradfitz,dgentry): cache this, or make caller(s) cache it.
|
||||
dist := distro.Get()
|
||||
propFile := "/etc/os-release"
|
||||
switch dist {
|
||||
@@ -69,9 +59,6 @@ func osVersionLinux() string {
|
||||
case distro.WDMyCloud:
|
||||
slurp, _ := ioutil.ReadFile("/etc/version")
|
||||
return fmt.Sprintf("%s", string(bytes.TrimSpace(slurp)))
|
||||
case distro.QNAP:
|
||||
slurp, _ := ioutil.ReadFile("/etc/version_info")
|
||||
return getQnapQtsVersion(string(slurp))
|
||||
}
|
||||
|
||||
m := map[string]string{}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//go:build linux && !android
|
||||
// +build linux,!android
|
||||
|
||||
package hostinfo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQnap(t *testing.T) {
|
||||
version_info := `commit 2910d3a594b068024ed01a64a0fe4168cb001a12
|
||||
Date: 2022-05-30 16:08:45 +0800
|
||||
================================================
|
||||
* QTSFW_5.0.0
|
||||
remotes/origin/QTSFW_5.0.0`
|
||||
|
||||
got := getQnapQtsVersion(version_info)
|
||||
want := "QTS 5.0.0"
|
||||
if got != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
|
||||
got = getQnapQtsVersion("")
|
||||
want = ""
|
||||
if got != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
|
||||
got = getQnapQtsVersion("just a bunch of junk")
|
||||
want = ""
|
||||
if got != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build for_go_mod_tidy_only
|
||||
// +build for_go_mod_tidy_only
|
||||
|
||||
package tooldeps
|
||||
|
||||
import (
|
||||
_ "github.com/tailscale/depaware/depaware"
|
||||
_ "golang.org/x/tools/cmd/goimports"
|
||||
)
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
package ipn
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/netmap"
|
||||
@@ -126,7 +126,7 @@ func (h *Handle) EngineStatus() EngineStatus {
|
||||
return h.engineStatusCache
|
||||
}
|
||||
|
||||
func (h *Handle) LocalAddrs() []netip.Prefix {
|
||||
func (h *Handle) LocalAddrs() []netaddr.IPPrefix {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
@@ -134,7 +134,7 @@ func (h *Handle) LocalAddrs() []netip.Prefix {
|
||||
if nm != nil {
|
||||
return nm.Addresses
|
||||
}
|
||||
return []netip.Prefix{}
|
||||
return []netaddr.IPPrefix{}
|
||||
}
|
||||
|
||||
func (h *Handle) NetMap() *netmap.NetworkMap {
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
package ipn
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/persist"
|
||||
"tailscale.com/types/preftype"
|
||||
@@ -37,7 +36,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
||||
RouteAll bool
|
||||
AllowSingleHosts bool
|
||||
ExitNodeID tailcfg.StableNodeID
|
||||
ExitNodeIP netip.Addr
|
||||
ExitNodeIP netaddr.IP
|
||||
ExitNodeAllowLANAccess bool
|
||||
CorpDNS bool
|
||||
RunSSH bool
|
||||
@@ -48,7 +47,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
|
||||
Hostname string
|
||||
NotepadURLs bool
|
||||
ForceDaemon bool
|
||||
AdvertiseRoutes []netip.Prefix
|
||||
AdvertiseRoutes []netaddr.IPPrefix
|
||||
NoSNAT bool
|
||||
NetfilterMode preftype.NetfilterMode
|
||||
OperatorUser string
|
||||
|
||||
@@ -6,10 +6,10 @@ package ipnlocal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/tailcfg"
|
||||
@@ -20,20 +20,20 @@ import (
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
func ipps(ippStrs ...string) (ipps []netip.Prefix) {
|
||||
func ipps(ippStrs ...string) (ipps []netaddr.IPPrefix) {
|
||||
for _, s := range ippStrs {
|
||||
if ip, err := netip.ParseAddr(s); err == nil {
|
||||
ipps = append(ipps, netip.PrefixFrom(ip, ip.BitLen()))
|
||||
if ip, err := netaddr.ParseIP(s); err == nil {
|
||||
ipps = append(ipps, netaddr.IPPrefixFrom(ip, ip.BitLen()))
|
||||
continue
|
||||
}
|
||||
ipps = append(ipps, netip.MustParsePrefix(s))
|
||||
ipps = append(ipps, netaddr.MustParseIPPrefix(s))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ips(ss ...string) (ips []netip.Addr) {
|
||||
func ips(ss ...string) (ips []netaddr.IP) {
|
||||
for _, s := range ss {
|
||||
ips = append(ips, netip.MustParseAddr(s))
|
||||
ips = append(ips, netaddr.MustParseIP(s))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
prefs: &ipn.Prefs{},
|
||||
want: &dns.Config{
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -80,7 +80,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
prefs: &ipn.Prefs{},
|
||||
want: &dns.Config{
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{
|
||||
"b.net.": ips("100.102.0.1", "100.102.0.2"),
|
||||
"myname.net.": ips("100.101.101.101"),
|
||||
"peera.net.": ips("100.102.0.1", "100.102.0.2"),
|
||||
@@ -115,7 +115,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
want: &dns.Config{
|
||||
OnlyIPv6: true,
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{
|
||||
"b.net.": ips("fe75::2"),
|
||||
"myname.net.": ips("fe75::1"),
|
||||
"peera.net.": ips("fe75::1001"),
|
||||
@@ -139,7 +139,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
prefs: &ipn.Prefs{},
|
||||
want: &dns.Config{
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{
|
||||
"myname.net.": ips("100.101.101.101"),
|
||||
"foo.com.": ips("1.2.3.4"),
|
||||
"bar.com.": ips("1::6"),
|
||||
@@ -159,7 +159,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
CorpDNS: true,
|
||||
},
|
||||
want: &dns.Config{
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{
|
||||
"0.e.1.a.c.5.1.1.a.7.d.f.ip6.arpa.": nil,
|
||||
"100.100.in-addr.arpa.": nil,
|
||||
@@ -259,7 +259,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
CorpDNS: true,
|
||||
},
|
||||
want: &dns.Config{
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
DefaultResolvers: []*dnstype.Resolver{
|
||||
{Addr: "8.8.8.8"},
|
||||
},
|
||||
@@ -282,7 +282,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
ExitNodeID: "some-id",
|
||||
},
|
||||
want: &dns.Config{
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
DefaultResolvers: []*dnstype.Resolver{
|
||||
{Addr: "8.8.4.4"},
|
||||
@@ -302,7 +302,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
CorpDNS: true,
|
||||
},
|
||||
want: &dns.Config{
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
@@ -23,7 +22,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go4.org/netipx"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/envknob"
|
||||
@@ -129,7 +128,7 @@ type LocalBackend struct {
|
||||
shutdownCalled bool // if Shutdown has been called
|
||||
|
||||
filterAtomic atomic.Value // of *filter.Filter
|
||||
containsViaIPFuncAtomic atomic.Value // of func(netip.Addr) bool
|
||||
containsViaIPFuncAtomic atomic.Value // of func(netaddr.IP) bool
|
||||
|
||||
// The mutex protects the following elements.
|
||||
mu sync.Mutex
|
||||
@@ -151,7 +150,7 @@ type LocalBackend struct {
|
||||
hostinfo *tailcfg.Hostinfo
|
||||
// netMap is not mutated in-place once set.
|
||||
netMap *netmap.NetworkMap
|
||||
nodeByAddr map[netip.Addr]*tailcfg.Node
|
||||
nodeByAddr map[netaddr.IP]*tailcfg.Node
|
||||
activeLogin string // last logged LoginName from netMap
|
||||
engineStatus ipn.EngineStatus
|
||||
endpoints []tailcfg.Endpoint
|
||||
@@ -175,11 +174,11 @@ type LocalBackend struct {
|
||||
// same as the Network Extension lifetime and we can thus avoid
|
||||
// double-copying files by writing them to the right location
|
||||
// immediately.
|
||||
// It's also used on several NAS platforms (Synology, TrueNAS, etc)
|
||||
// but in that case DoFinalRename is also set true, which moves the
|
||||
// *.partial file to its final name on completion.
|
||||
// It's also used on Synology & TrueNAS, but in that case DoFinalRename
|
||||
// is also set true, which moves the *.partial file to its final
|
||||
// name on completion.
|
||||
directFileRoot string
|
||||
directFileDoFinalRename bool // false on macOS, true on several NAS platforms
|
||||
directFileDoFinalRename bool // false on macOS, true on Synology & TrueNAS
|
||||
|
||||
// statusLock must be held before calling statusChanged.Wait() or
|
||||
// statusChanged.Broadcast().
|
||||
@@ -232,7 +231,7 @@ func NewLocalBackend(logf logger.Logf, logid string, store ipn.StateStore, diale
|
||||
}
|
||||
|
||||
// Default filter blocks everything and logs nothing, until Start() is called.
|
||||
b.setFilter(filter.NewAllowNone(logf, &netipx.IPSet{}))
|
||||
b.setFilter(filter.NewAllowNone(logf, &netaddr.IPSet{}))
|
||||
|
||||
b.statusChanged = sync.NewCond(&b.statusLock)
|
||||
b.e.SetStatusCallback(b.setWgengineStatus)
|
||||
@@ -497,13 +496,13 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
||||
if p.LastSeen != nil {
|
||||
lastSeen = *p.LastSeen
|
||||
}
|
||||
var tailscaleIPs = make([]netip.Addr, 0, len(p.Addresses))
|
||||
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
|
||||
for _, addr := range p.Addresses {
|
||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
|
||||
tailscaleIPs = append(tailscaleIPs, addr.Addr())
|
||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
|
||||
tailscaleIPs = append(tailscaleIPs, addr.IP())
|
||||
}
|
||||
}
|
||||
exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netip.Prefix) bool {
|
||||
exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netaddr.IPPrefix) bool {
|
||||
return r.Bits() == 0
|
||||
})
|
||||
var tags *views.Slice[string]
|
||||
@@ -541,12 +540,12 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
||||
// WhoIs reports the node and user who owns the node with the given IP:port.
|
||||
// If the IP address is a Tailscale IP, the provided port may be 0.
|
||||
// If ok == true, n and u are valid.
|
||||
func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
|
||||
func (b *LocalBackend) WhoIs(ipp netaddr.IPPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
n, ok = b.nodeByAddr[ipp.Addr()]
|
||||
n, ok = b.nodeByAddr[ipp.IP()]
|
||||
if !ok {
|
||||
var ip netip.Addr
|
||||
var ip netaddr.IP
|
||||
if ipp.Port() != 0 {
|
||||
ip, ok = b.e.WhoIsIPPort(ipp)
|
||||
}
|
||||
@@ -567,7 +566,7 @@ func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.Use
|
||||
|
||||
// PeerCaps returns the capabilities that remote src IP has to
|
||||
// ths current node.
|
||||
func (b *LocalBackend) PeerCaps(src netip.Addr) []string {
|
||||
func (b *LocalBackend) PeerCaps(src netaddr.IP) []string {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.netMap == nil {
|
||||
@@ -581,9 +580,9 @@ func (b *LocalBackend) PeerCaps(src netip.Addr) []string {
|
||||
if !a.IsSingleIP() {
|
||||
continue
|
||||
}
|
||||
dstIP := a.Addr()
|
||||
dstIP := a.IP()
|
||||
if dstIP.BitLen() == src.BitLen() {
|
||||
return filt.AppendCaps(nil, src, a.Addr())
|
||||
return filt.AppendCaps(nil, src, a.IP())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -751,7 +750,7 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
|
||||
|
||||
// If we have a desired IP on file, try to find the corresponding
|
||||
// node.
|
||||
if !b.prefs.ExitNodeIP.IsValid() {
|
||||
if b.prefs.ExitNodeIP.IsZero() {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -763,13 +762,13 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
|
||||
|
||||
for _, peer := range nm.Peers {
|
||||
for _, addr := range peer.Addresses {
|
||||
if !addr.IsSingleIP() || addr.Addr() != b.prefs.ExitNodeIP {
|
||||
if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
|
||||
continue
|
||||
}
|
||||
// Found the node being referenced, upgrade prefs to
|
||||
// reference it directly for next time.
|
||||
b.prefs.ExitNodeID = peer.StableID
|
||||
b.prefs.ExitNodeIP = netip.Addr{}
|
||||
b.prefs.ExitNodeIP = netaddr.IP{}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1122,10 +1121,10 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs *ipn.
|
||||
// quite hard to debug, so save yourself the trouble.
|
||||
var (
|
||||
haveNetmap = netMap != nil
|
||||
addrs []netip.Prefix
|
||||
addrs []netaddr.IPPrefix
|
||||
packetFilter []filter.Match
|
||||
localNetsB netipx.IPSetBuilder
|
||||
logNetsB netipx.IPSetBuilder
|
||||
localNetsB netaddr.IPSetBuilder
|
||||
logNetsB netaddr.IPSetBuilder
|
||||
shieldsUp = prefs == nil || prefs.ShieldsUp // Be conservative when not ready
|
||||
)
|
||||
// Log traffic for Tailscale IPs.
|
||||
@@ -1205,21 +1204,21 @@ func (b *LocalBackend) setFilter(f *filter.Filter) {
|
||||
b.e.SetFilter(f)
|
||||
}
|
||||
|
||||
var removeFromDefaultRoute = []netip.Prefix{
|
||||
var removeFromDefaultRoute = []netaddr.IPPrefix{
|
||||
// RFC1918 LAN ranges
|
||||
netip.MustParsePrefix("192.168.0.0/16"),
|
||||
netip.MustParsePrefix("172.16.0.0/12"),
|
||||
netip.MustParsePrefix("10.0.0.0/8"),
|
||||
netaddr.MustParseIPPrefix("192.168.0.0/16"),
|
||||
netaddr.MustParseIPPrefix("172.16.0.0/12"),
|
||||
netaddr.MustParseIPPrefix("10.0.0.0/8"),
|
||||
// IPv4 link-local
|
||||
netip.MustParsePrefix("169.254.0.0/16"),
|
||||
netaddr.MustParseIPPrefix("169.254.0.0/16"),
|
||||
// IPv4 multicast
|
||||
netip.MustParsePrefix("224.0.0.0/4"),
|
||||
netaddr.MustParseIPPrefix("224.0.0.0/4"),
|
||||
// Tailscale IPv4 range
|
||||
tsaddr.CGNATRange(),
|
||||
// IPv6 Link-local addresses
|
||||
netip.MustParsePrefix("fe80::/10"),
|
||||
netaddr.MustParseIPPrefix("fe80::/10"),
|
||||
// IPv6 multicast
|
||||
netip.MustParsePrefix("ff00::/8"),
|
||||
netaddr.MustParseIPPrefix("ff00::/8"),
|
||||
// Tailscale IPv6 range
|
||||
tsaddr.TailscaleULARange(),
|
||||
}
|
||||
@@ -1231,7 +1230,7 @@ var removeFromDefaultRoute = []netip.Prefix{
|
||||
//
|
||||
// Given that "internal" routes don't leave the device, we choose to
|
||||
// trust them more, allowing access to them when an Exit Node is enabled.
|
||||
func internalAndExternalInterfaces() (internal, external []netip.Prefix, err error) {
|
||||
func internalAndExternalInterfaces() (internal, external []netaddr.IPPrefix, err error) {
|
||||
il, err := interfaces.GetList()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -1239,12 +1238,12 @@ func internalAndExternalInterfaces() (internal, external []netip.Prefix, err err
|
||||
return internalAndExternalInterfacesFrom(il, runtime.GOOS)
|
||||
}
|
||||
|
||||
func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (internal, external []netip.Prefix, err error) {
|
||||
func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (internal, external []netaddr.IPPrefix, err error) {
|
||||
// We use an IPSetBuilder here to canonicalize the prefixes
|
||||
// and to remove any duplicate entries.
|
||||
var internalBuilder, externalBuilder netipx.IPSetBuilder
|
||||
if err := il.ForeachInterfaceAddress(func(iface interfaces.Interface, pfx netip.Prefix) {
|
||||
if tsaddr.IsTailscaleIP(pfx.Addr()) {
|
||||
var internalBuilder, externalBuilder netaddr.IPSetBuilder
|
||||
if err := il.ForeachInterfaceAddress(func(iface interfaces.Interface, pfx netaddr.IPPrefix) {
|
||||
if tsaddr.IsTailscaleIP(pfx.IP()) {
|
||||
return
|
||||
}
|
||||
if pfx.IsSingleIP() {
|
||||
@@ -1285,16 +1284,16 @@ func internalAndExternalInterfacesFrom(il interfaces.List, goos string) (interna
|
||||
return iSet.Prefixes(), eSet.Prefixes(), nil
|
||||
}
|
||||
|
||||
func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netip.Addr, err error) {
|
||||
var b netipx.IPSetBuilder
|
||||
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netip.Prefix) {
|
||||
if tsaddr.IsTailscaleIP(pfx.Addr()) {
|
||||
func interfaceRoutes() (ips *netaddr.IPSet, hostIPs []netaddr.IP, err error) {
|
||||
var b netaddr.IPSetBuilder
|
||||
if err := interfaces.ForeachInterfaceAddress(func(_ interfaces.Interface, pfx netaddr.IPPrefix) {
|
||||
if tsaddr.IsTailscaleIP(pfx.IP()) {
|
||||
return
|
||||
}
|
||||
if pfx.IsSingleIP() {
|
||||
return
|
||||
}
|
||||
hostIPs = append(hostIPs, pfx.Addr())
|
||||
hostIPs = append(hostIPs, pfx.IP())
|
||||
b.AddPrefix(pfx)
|
||||
}); err != nil {
|
||||
return nil, nil, err
|
||||
@@ -1307,8 +1306,8 @@ func interfaceRoutes() (ips *netipx.IPSet, hostIPs []netip.Addr, err error) {
|
||||
// shrinkDefaultRoute returns an IPSet representing the IPs in route,
|
||||
// minus those in removeFromDefaultRoute and localInterfaceRoutes,
|
||||
// plus the IPs in hostIPs.
|
||||
func shrinkDefaultRoute(route netip.Prefix, localInterfaceRoutes *netipx.IPSet, hostIPs []netip.Addr) (*netipx.IPSet, error) {
|
||||
var b netipx.IPSetBuilder
|
||||
func shrinkDefaultRoute(route netaddr.IPPrefix, localInterfaceRoutes *netaddr.IPSet, hostIPs []netaddr.IP) (*netaddr.IPSet, error) {
|
||||
var b netaddr.IPSetBuilder
|
||||
// Add the default route.
|
||||
b.AddPrefix(route)
|
||||
// Remove the local interface routes.
|
||||
@@ -1334,7 +1333,7 @@ func shrinkDefaultRoute(route netip.Prefix, localInterfaceRoutes *netipx.IPSet,
|
||||
|
||||
// dnsCIDRsEqual determines whether two CIDR lists are equal
|
||||
// for DNS map construction purposes (that is, only the first entry counts).
|
||||
func dnsCIDRsEqual(newAddr, oldAddr []netip.Prefix) bool {
|
||||
func dnsCIDRsEqual(newAddr, oldAddr []netaddr.IPPrefix) bool {
|
||||
if len(newAddr) != len(oldAddr) {
|
||||
return false
|
||||
}
|
||||
@@ -1732,7 +1731,7 @@ func (b *LocalBackend) StartLoginInteractive() {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *LocalBackend) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg.PingType) (*ipnstate.PingResult, error) {
|
||||
func (b *LocalBackend) Ping(ctx context.Context, ip netaddr.IP, pingType tailcfg.PingType) (*ipnstate.PingResult, error) {
|
||||
if pingType == tailcfg.PingPeerAPI {
|
||||
t0 := time.Now()
|
||||
node, base, err := b.pingPeerAPI(ctx, ip)
|
||||
@@ -1769,7 +1768,7 @@ func (b *LocalBackend) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg
|
||||
}
|
||||
}
|
||||
|
||||
func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netip.Addr) (peer *tailcfg.Node, peerBase string, err error) {
|
||||
func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netaddr.IP) (peer *tailcfg.Node, peerBase string, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
nm := b.NetMap()
|
||||
@@ -1878,9 +1877,6 @@ func (b *LocalBackend) checkSSHPrefsLocked(p *ipn.Prefs) error {
|
||||
if distro.Get() == distro.Synology && !envknob.UseWIPCode() {
|
||||
return errors.New("The Tailscale SSH server does not run on Synology.")
|
||||
}
|
||||
if distro.Get() == distro.QNAP && !envknob.UseWIPCode() {
|
||||
return errors.New("The Tailscale SSH server does not run on QNAP.")
|
||||
}
|
||||
// otherwise okay
|
||||
case "darwin":
|
||||
// okay only in tailscaled mode for now.
|
||||
@@ -2068,7 +2064,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
|
||||
|
||||
// GetPeerAPIPort returns the port number for the peerapi server
|
||||
// running on the provided IP.
|
||||
func (b *LocalBackend) GetPeerAPIPort(ip netip.Addr) (port uint16, ok bool) {
|
||||
func (b *LocalBackend) GetPeerAPIPort(ip netaddr.IP) (port uint16, ok bool) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
for _, pln := range b.peerAPIListeners {
|
||||
@@ -2086,11 +2082,11 @@ func (b *LocalBackend) GetPeerAPIPort(ip netip.Addr) (port uint16, ok bool) {
|
||||
// or IPv6 IP and the peerapi port for that address).
|
||||
//
|
||||
// The connection will be closed by ServePeerAPIConnection.
|
||||
func (b *LocalBackend) ServePeerAPIConnection(remote, local netip.AddrPort, c net.Conn) {
|
||||
func (b *LocalBackend) ServePeerAPIConnection(remote, local netaddr.IPPort, c net.Conn) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
for _, pln := range b.peerAPIListeners {
|
||||
if pln.ip == local.Addr() {
|
||||
if pln.ip == local.IP() {
|
||||
go pln.ServeConn(remote, c)
|
||||
return
|
||||
}
|
||||
@@ -2288,7 +2284,7 @@ func shouldUseOneCGNATRoute(nm *netmap.NetworkMap, logf logger.Logf, versionOS s
|
||||
func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Logf, versionOS string) *dns.Config {
|
||||
dcfg := &dns.Config{
|
||||
Routes: map[dnsname.FQDN][]*dnstype.Resolver{},
|
||||
Hosts: map[dnsname.FQDN][]netip.Addr{},
|
||||
Hosts: map[dnsname.FQDN][]netaddr.IP{},
|
||||
}
|
||||
|
||||
// selfV6Only is whether we only have IPv6 addresses ourselves.
|
||||
@@ -2301,7 +2297,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
||||
// isn't configured to make MagicDNS resolution truly
|
||||
// magic. Details in
|
||||
// https://github.com/tailscale/tailscale/issues/1886.
|
||||
set := func(name string, addrs []netip.Prefix) {
|
||||
set := func(name string, addrs []netaddr.IPPrefix) {
|
||||
if len(addrs) == 0 || name == "" {
|
||||
return
|
||||
}
|
||||
@@ -2310,11 +2306,11 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
||||
return // TODO: propagate error?
|
||||
}
|
||||
have4 := tsaddr.PrefixesContainsFunc(addrs, tsaddr.PrefixIs4)
|
||||
var ips []netip.Addr
|
||||
var ips []netaddr.IP
|
||||
for _, addr := range addrs {
|
||||
if selfV6Only {
|
||||
if addr.Addr().Is6() {
|
||||
ips = append(ips, addr.Addr())
|
||||
if addr.IP().Is6() {
|
||||
ips = append(ips, addr.IP())
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -2326,10 +2322,10 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
||||
// https://github.com/tailscale/tailscale/issues/1152
|
||||
// tracks adding the right capability reporting to
|
||||
// enable AAAA in MagicDNS.
|
||||
if addr.Addr().Is6() && have4 {
|
||||
if addr.IP().Is6() && have4 {
|
||||
continue
|
||||
}
|
||||
ips = append(ips, addr.Addr())
|
||||
ips = append(ips, addr.IP())
|
||||
}
|
||||
dcfg.Hosts[fqdn] = ips
|
||||
}
|
||||
@@ -2345,7 +2341,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs *ipn.Prefs, logf logger.Log
|
||||
// TODO: more
|
||||
continue
|
||||
}
|
||||
ip, err := netip.ParseAddr(rec.Value)
|
||||
ip, err := netaddr.ParseIP(rec.Value)
|
||||
if err != nil {
|
||||
// Ignore.
|
||||
continue
|
||||
@@ -2521,7 +2517,7 @@ func (b *LocalBackend) initPeerAPIListener() {
|
||||
if len(b.netMap.Addresses) == len(b.peerAPIListeners) {
|
||||
allSame := true
|
||||
for i, pln := range b.peerAPIListeners {
|
||||
if pln.ip != b.netMap.Addresses[i].Addr() {
|
||||
if pln.ip != b.netMap.Addresses[i].IP() {
|
||||
allSame = false
|
||||
break
|
||||
}
|
||||
@@ -2564,20 +2560,20 @@ func (b *LocalBackend) initPeerAPIListener() {
|
||||
var err error
|
||||
skipListen := i > 0 && isNetstack
|
||||
if !skipListen {
|
||||
ln, err = ps.listen(a.Addr(), b.prevIfState)
|
||||
ln, err = ps.listen(a.IP(), b.prevIfState)
|
||||
if err != nil {
|
||||
if peerAPIListenAsync {
|
||||
// Expected. But we fix it later in linkChange
|
||||
// ("peerAPIListeners too low").
|
||||
continue
|
||||
}
|
||||
b.logf("[unexpected] peerapi listen(%q) error: %v", a.Addr(), err)
|
||||
b.logf("[unexpected] peerapi listen(%q) error: %v", a.IP(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
pln := &peerAPIListener{
|
||||
ps: ps,
|
||||
ip: a.Addr(),
|
||||
ip: a.IP(),
|
||||
ln: ln, // nil for 2nd+ on netstack
|
||||
lb: b,
|
||||
}
|
||||
@@ -2586,7 +2582,7 @@ func (b *LocalBackend) initPeerAPIListener() {
|
||||
} else {
|
||||
pln.port = ln.Addr().(*net.TCPAddr).Port
|
||||
}
|
||||
pln.urlStr = "http://" + net.JoinHostPort(a.Addr().String(), strconv.Itoa(pln.port))
|
||||
pln.urlStr = "http://" + net.JoinHostPort(a.IP().String(), strconv.Itoa(pln.port))
|
||||
b.logf("peerapi: serving on %s", pln.urlStr)
|
||||
go pln.serve()
|
||||
b.peerAPIListeners = append(b.peerAPIListeners, pln)
|
||||
@@ -2621,30 +2617,30 @@ func magicDNSRootDomains(nm *netmap.NetworkMap) []dnsname.FQDN {
|
||||
}
|
||||
|
||||
var (
|
||||
ipv4Default = netip.MustParsePrefix("0.0.0.0/0")
|
||||
ipv6Default = netip.MustParsePrefix("::/0")
|
||||
ipv4Default = netaddr.MustParseIPPrefix("0.0.0.0/0")
|
||||
ipv6Default = netaddr.MustParseIPPrefix("::/0")
|
||||
)
|
||||
|
||||
// peerRoutes returns the routerConfig.Routes to access peers.
|
||||
// If there are over cgnatThreshold CGNAT routes, one big CGNAT route
|
||||
// is used instead.
|
||||
func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netip.Prefix) {
|
||||
func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPrefix) {
|
||||
tsULA := tsaddr.TailscaleULARange()
|
||||
cgNAT := tsaddr.CGNATRange()
|
||||
var didULA bool
|
||||
var cgNATIPs []netip.Prefix
|
||||
var cgNATIPs []netaddr.IPPrefix
|
||||
for _, peer := range peers {
|
||||
for _, aip := range peer.AllowedIPs {
|
||||
aip = unmapIPPrefix(aip)
|
||||
// Only add the Tailscale IPv6 ULA once, if we see anybody using part of it.
|
||||
if aip.Addr().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.Addr()) {
|
||||
if aip.IP().Is6() && aip.IsSingleIP() && tsULA.Contains(aip.IP()) {
|
||||
if !didULA {
|
||||
didULA = true
|
||||
routes = append(routes, tsULA)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if aip.IsSingleIP() && cgNAT.Contains(aip.Addr()) {
|
||||
if aip.IsSingleIP() && cgNAT.Contains(aip.IP()) {
|
||||
cgNATIPs = append(cgNATIPs, aip)
|
||||
} else {
|
||||
routes = append(routes, aip)
|
||||
@@ -2664,11 +2660,11 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netip.Prefix)
|
||||
return routes
|
||||
}
|
||||
|
||||
func ipPrefixLess(ri, rj netip.Prefix) bool {
|
||||
if ri.Addr() == rj.Addr() {
|
||||
func ipPrefixLess(ri, rj netaddr.IPPrefix) bool {
|
||||
if ri.IP() == rj.IP() {
|
||||
return ri.Bits() < rj.Bits()
|
||||
}
|
||||
return ri.Addr().Less(rj.Addr())
|
||||
return ri.IP().Less(rj.IP())
|
||||
}
|
||||
|
||||
// routerConfig produces a router.Config from a wireguard config and IPN prefs.
|
||||
@@ -2696,7 +2692,7 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
|
||||
// likely to break some functionality, but if the user expressed a
|
||||
// preference for routing remotely, we want to avoid leaking
|
||||
// traffic at the expense of functionality.
|
||||
if prefs.ExitNodeID != "" || prefs.ExitNodeIP.IsValid() {
|
||||
if prefs.ExitNodeID != "" || !prefs.ExitNodeIP.IsZero() {
|
||||
var default4, default6 bool
|
||||
for _, route := range rs.Routes {
|
||||
switch route {
|
||||
@@ -2735,17 +2731,17 @@ func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs, oneCGNA
|
||||
}
|
||||
|
||||
if tsaddr.PrefixesContainsFunc(rs.LocalAddrs, tsaddr.PrefixIs4) {
|
||||
rs.Routes = append(rs.Routes, netip.PrefixFrom(tsaddr.TailscaleServiceIP(), 32))
|
||||
rs.Routes = append(rs.Routes, netaddr.IPPrefixFrom(tsaddr.TailscaleServiceIP(), 32))
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
func unmapIPPrefix(ipp netip.Prefix) netip.Prefix {
|
||||
return netip.PrefixFrom(ipp.Addr().Unmap(), ipp.Bits())
|
||||
func unmapIPPrefix(ipp netaddr.IPPrefix) netaddr.IPPrefix {
|
||||
return netaddr.IPPrefixFrom(ipp.IP().Unmap(), ipp.Bits())
|
||||
}
|
||||
|
||||
func unmapIPPrefixes(ippsList ...[]netip.Prefix) (ret []netip.Prefix) {
|
||||
func unmapIPPrefixes(ippsList ...[]netaddr.IPPrefix) (ret []netaddr.IPPrefix) {
|
||||
for _, ipps := range ippsList {
|
||||
for _, ipp := range ipps {
|
||||
ret = append(ret, unmapIPPrefix(ipp))
|
||||
@@ -2829,7 +2825,7 @@ func (b *LocalBackend) enterState(newState ipn.State) {
|
||||
case ipn.Running:
|
||||
var addrs []string
|
||||
for _, addr := range netMap.Addresses {
|
||||
addrs = append(addrs, addr.Addr().String())
|
||||
addrs = append(addrs, addr.IP().String())
|
||||
}
|
||||
systemd.Status("Connected; %s; %s", activeLogin, strings.Join(addrs, " "))
|
||||
default:
|
||||
@@ -2988,8 +2984,8 @@ func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Get() && can
|
||||
// ShouldHandleViaIP reports whether whether ip is an IPv6 address in the
|
||||
// Tailscale ULA's v6 "via" range embedding an IPv4 address to be forwarded to
|
||||
// by Tailscale.
|
||||
func (b *LocalBackend) ShouldHandleViaIP(ip netip.Addr) bool {
|
||||
if f, ok := b.containsViaIPFuncAtomic.Load().(func(netip.Addr) bool); ok {
|
||||
func (b *LocalBackend) ShouldHandleViaIP(ip netaddr.IP) bool {
|
||||
if f, ok := b.containsViaIPFuncAtomic.Load().(func(netaddr.IP) bool); ok {
|
||||
return f(ip)
|
||||
}
|
||||
return false
|
||||
@@ -3106,7 +3102,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
||||
|
||||
// Update the nodeByAddr index.
|
||||
if b.nodeByAddr == nil {
|
||||
b.nodeByAddr = map[netip.Addr]*tailcfg.Node{}
|
||||
b.nodeByAddr = map[netaddr.IP]*tailcfg.Node{}
|
||||
}
|
||||
// First pass, mark everything unwanted.
|
||||
for k := range b.nodeByAddr {
|
||||
@@ -3115,7 +3111,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
||||
addNode := func(n *tailcfg.Node) {
|
||||
for _, ipp := range n.Addresses {
|
||||
if ipp.IsSingleIP() {
|
||||
b.nodeByAddr[ipp.Addr()] = n
|
||||
b.nodeByAddr[ipp.IP()] = n
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3295,9 +3291,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case a.Addr().Is4():
|
||||
case a.IP().Is4():
|
||||
have4 = true
|
||||
case a.Addr().Is6():
|
||||
case a.IP().Is6():
|
||||
have6 = true
|
||||
}
|
||||
}
|
||||
@@ -3312,26 +3308,26 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
|
||||
p6 = s.Port
|
||||
}
|
||||
}
|
||||
var ipp netip.AddrPort
|
||||
var ipp netaddr.IPPort
|
||||
switch {
|
||||
case have4 && p4 != 0:
|
||||
ipp = netip.AddrPortFrom(nodeIP(peer, netip.Addr.Is4), p4)
|
||||
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is4), p4)
|
||||
case have6 && p6 != 0:
|
||||
ipp = netip.AddrPortFrom(nodeIP(peer, netip.Addr.Is6), p6)
|
||||
ipp = netaddr.IPPortFrom(nodeIP(peer, netaddr.IP.Is6), p6)
|
||||
}
|
||||
if !ipp.Addr().IsValid() {
|
||||
if ipp.IP().IsZero() {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("http://%v", ipp)
|
||||
}
|
||||
|
||||
func nodeIP(n *tailcfg.Node, pred func(netip.Addr) bool) netip.Addr {
|
||||
func nodeIP(n *tailcfg.Node, pred func(netaddr.IP) bool) netaddr.IP {
|
||||
for _, a := range n.Addresses {
|
||||
if a.IsSingleIP() && pred(a.Addr()) {
|
||||
return a.Addr()
|
||||
if a.IsSingleIP() && pred(a.IP()) {
|
||||
return a.IP()
|
||||
}
|
||||
}
|
||||
return netip.Addr{}
|
||||
return netaddr.IP{}
|
||||
}
|
||||
|
||||
func (b *LocalBackend) CheckIPForwarding() error {
|
||||
@@ -3370,9 +3366,9 @@ func (b *LocalBackend) OfferingExitNode() bool {
|
||||
if r.Bits() != 0 {
|
||||
continue
|
||||
}
|
||||
if r.Addr().Is4() {
|
||||
if r.IP().Is4() {
|
||||
def4 = true
|
||||
} else if r.Addr().Is6() {
|
||||
} else if r.IP().Is6() {
|
||||
def6 = true
|
||||
}
|
||||
}
|
||||
@@ -3544,7 +3540,7 @@ func (b *LocalBackend) handleQuad100Port80Conn(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
io.WriteString(w, "<p>Local addresses:</p><ul>\n")
|
||||
for _, ipp := range b.netMap.Addresses {
|
||||
fmt.Fprintf(w, "<li>%v</li>\n", ipp.Addr())
|
||||
fmt.Fprintf(w, "<li>%v</li>\n", ipp.IP())
|
||||
}
|
||||
io.WriteString(w, "</ul>\n")
|
||||
}
|
||||
|
||||
@@ -8,12 +8,11 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go4.org/netipx"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/store/mem"
|
||||
"tailscale.com/net/interfaces"
|
||||
@@ -26,17 +25,17 @@ import (
|
||||
)
|
||||
|
||||
func TestNetworkMapCompare(t *testing.T) {
|
||||
prefix1, err := netip.ParsePrefix("192.168.0.0/24")
|
||||
prefix1, err := netaddr.ParseIPPrefix("192.168.0.0/24")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
node1 := &tailcfg.Node{Addresses: []netip.Prefix{prefix1}}
|
||||
node1 := &tailcfg.Node{Addresses: []netaddr.IPPrefix{prefix1}}
|
||||
|
||||
prefix2, err := netip.ParsePrefix("10.0.0.0/8")
|
||||
prefix2, err := netaddr.ParseIPPrefix("10.0.0.0/8")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
node2 := &tailcfg.Node{Addresses: []netip.Prefix{prefix2}}
|
||||
node2 := &tailcfg.Node{Addresses: []netaddr.IPPrefix{prefix2}}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -132,7 +131,7 @@ func TestNetworkMapCompare(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func inRemove(ip netip.Addr) bool {
|
||||
func inRemove(ip netaddr.IP) bool {
|
||||
for _, pfx := range removeFromDefaultRoute {
|
||||
if pfx.Contains(ip) {
|
||||
return true
|
||||
@@ -146,7 +145,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
|
||||
route string
|
||||
in []string
|
||||
out []string
|
||||
localIPFn func(netip.Addr) bool // true if this machine's local IP address should be "in" after shrinking.
|
||||
localIPFn func(netaddr.IP) bool // true if this machine's local IP address should be "in" after shrinking.
|
||||
}{
|
||||
{
|
||||
route: "0.0.0.0/0",
|
||||
@@ -166,7 +165,7 @@ func TestShrinkDefaultRoute(t *testing.T) {
|
||||
"fe80::",
|
||||
"2601::1",
|
||||
},
|
||||
localIPFn: func(ip netip.Addr) bool { return !inRemove(ip) && ip.Is4() },
|
||||
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is4() },
|
||||
},
|
||||
{
|
||||
route: "::/0",
|
||||
@@ -174,47 +173,47 @@ func TestShrinkDefaultRoute(t *testing.T) {
|
||||
out: []string{
|
||||
"fe80::1",
|
||||
"ff00::1",
|
||||
tsaddr.TailscaleULARange().Addr().String(),
|
||||
tsaddr.TailscaleULARange().IP().String(),
|
||||
},
|
||||
localIPFn: func(ip netip.Addr) bool { return !inRemove(ip) && ip.Is6() },
|
||||
localIPFn: func(ip netaddr.IP) bool { return !inRemove(ip) && ip.Is6() },
|
||||
},
|
||||
}
|
||||
|
||||
// Construct a fake local network environment to make this test hermetic.
|
||||
// localInterfaceRoutes and hostIPs would normally come from calling interfaceRoutes,
|
||||
// and localAddresses would normally come from calling interfaces.LocalAddresses.
|
||||
var b netipx.IPSetBuilder
|
||||
var b netaddr.IPSetBuilder
|
||||
for _, c := range []string{"127.0.0.0/8", "192.168.9.0/24", "fe80::/32"} {
|
||||
p := netip.MustParsePrefix(c)
|
||||
p := netaddr.MustParseIPPrefix(c)
|
||||
b.AddPrefix(p)
|
||||
}
|
||||
localInterfaceRoutes, err := b.IPSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hostIPs := []netip.Addr{
|
||||
netip.MustParseAddr("127.0.0.1"),
|
||||
netip.MustParseAddr("192.168.9.39"),
|
||||
netip.MustParseAddr("fe80::1"),
|
||||
netip.MustParseAddr("fe80::437d:feff:feca:49a7"),
|
||||
hostIPs := []netaddr.IP{
|
||||
netaddr.MustParseIP("127.0.0.1"),
|
||||
netaddr.MustParseIP("192.168.9.39"),
|
||||
netaddr.MustParseIP("fe80::1"),
|
||||
netaddr.MustParseIP("fe80::437d:feff:feca:49a7"),
|
||||
}
|
||||
localAddresses := []netip.Addr{
|
||||
netip.MustParseAddr("192.168.9.39"),
|
||||
localAddresses := []netaddr.IP{
|
||||
netaddr.MustParseIP("192.168.9.39"),
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
def := netip.MustParsePrefix(test.route)
|
||||
def := netaddr.MustParseIPPrefix(test.route)
|
||||
got, err := shrinkDefaultRoute(def, localInterfaceRoutes, hostIPs)
|
||||
if err != nil {
|
||||
t.Fatalf("shrinkDefaultRoute(%q): %v", test.route, err)
|
||||
}
|
||||
for _, ip := range test.in {
|
||||
if !got.Contains(netip.MustParseAddr(ip)) {
|
||||
if !got.Contains(netaddr.MustParseIP(ip)) {
|
||||
t.Errorf("shrink(%q).Contains(%v) = false, want true", test.route, ip)
|
||||
}
|
||||
}
|
||||
for _, ip := range test.out {
|
||||
if got.Contains(netip.MustParseAddr(ip)) {
|
||||
if got.Contains(netaddr.MustParseIP(ip)) {
|
||||
t.Errorf("shrink(%q).Contains(%v) = true, want false", test.route, ip)
|
||||
}
|
||||
}
|
||||
@@ -228,22 +227,22 @@ func TestShrinkDefaultRoute(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPeerRoutes(t *testing.T) {
|
||||
pp := netip.MustParsePrefix
|
||||
pp := netaddr.MustParseIPPrefix
|
||||
tests := []struct {
|
||||
name string
|
||||
peers []wgcfg.Peer
|
||||
want []netip.Prefix
|
||||
want []netaddr.IPPrefix
|
||||
}{
|
||||
{
|
||||
name: "small_v4",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("100.101.102.103/32"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("100.101.102.103/32"),
|
||||
},
|
||||
},
|
||||
@@ -251,14 +250,14 @@ func TestPeerRoutes(t *testing.T) {
|
||||
name: "big_v4",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("100.101.102.103/32"),
|
||||
pp("100.101.102.104/32"),
|
||||
pp("100.101.102.105/32"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("100.64.0.0/10"),
|
||||
},
|
||||
},
|
||||
@@ -266,12 +265,12 @@ func TestPeerRoutes(t *testing.T) {
|
||||
name: "has_1_v6",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("fd7a:115c:a1e0::/48"),
|
||||
},
|
||||
},
|
||||
@@ -279,13 +278,13 @@ func TestPeerRoutes(t *testing.T) {
|
||||
name: "has_2_v6",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b240/128"),
|
||||
pp("fd7a:115c:a1e0:ab12:4843:cd96:6258:b241/128"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("fd7a:115c:a1e0::/48"),
|
||||
},
|
||||
},
|
||||
@@ -293,7 +292,7 @@ func TestPeerRoutes(t *testing.T) {
|
||||
name: "big_v4_big_v6",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("100.101.102.103/32"),
|
||||
pp("100.101.102.104/32"),
|
||||
pp("100.101.102.105/32"),
|
||||
@@ -302,7 +301,7 @@ func TestPeerRoutes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("100.64.0.0/10"),
|
||||
pp("fd7a:115c:a1e0::/48"),
|
||||
},
|
||||
@@ -311,19 +310,19 @@ func TestPeerRoutes(t *testing.T) {
|
||||
name: "output-should-be-sorted",
|
||||
peers: []wgcfg.Peer{
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("100.64.0.2/32"),
|
||||
pp("10.0.0.0/16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
AllowedIPs: []netip.Prefix{
|
||||
AllowedIPs: []netaddr.IPPrefix{
|
||||
pp("100.64.0.1/32"),
|
||||
pp("10.0.0.0/8"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []netip.Prefix{
|
||||
want: []netaddr.IPPrefix{
|
||||
pp("10.0.0.0/8"),
|
||||
pp("10.0.0.0/16"),
|
||||
pp("100.64.0.1/32"),
|
||||
@@ -362,14 +361,14 @@ func TestPeerAPIBase(t *testing.T) {
|
||||
{
|
||||
name: "self_only_4_them_both",
|
||||
nm: &netmap.NetworkMap{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.1/32"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
||||
},
|
||||
},
|
||||
peer: &tailcfg.Node{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.2/32"),
|
||||
netip.MustParsePrefix("fe70::2/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.2/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::2/128"),
|
||||
},
|
||||
Hostinfo: (&tailcfg.Hostinfo{
|
||||
Services: []tailcfg.Service{
|
||||
@@ -383,14 +382,14 @@ func TestPeerAPIBase(t *testing.T) {
|
||||
{
|
||||
name: "self_only_6_them_both",
|
||||
nm: &netmap.NetworkMap{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("fe70::1/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("fe70::1/128"),
|
||||
},
|
||||
},
|
||||
peer: &tailcfg.Node{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.2/32"),
|
||||
netip.MustParsePrefix("fe70::2/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.2/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::2/128"),
|
||||
},
|
||||
Hostinfo: (&tailcfg.Hostinfo{
|
||||
Services: []tailcfg.Service{
|
||||
@@ -404,15 +403,15 @@ func TestPeerAPIBase(t *testing.T) {
|
||||
{
|
||||
name: "self_both_them_only_4",
|
||||
nm: &netmap.NetworkMap{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.1/32"),
|
||||
netip.MustParsePrefix("fe70::1/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::1/128"),
|
||||
},
|
||||
},
|
||||
peer: &tailcfg.Node{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.2/32"),
|
||||
netip.MustParsePrefix("fe70::2/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.2/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::2/128"),
|
||||
},
|
||||
Hostinfo: (&tailcfg.Hostinfo{
|
||||
Services: []tailcfg.Service{
|
||||
@@ -425,15 +424,15 @@ func TestPeerAPIBase(t *testing.T) {
|
||||
{
|
||||
name: "self_both_them_only_6",
|
||||
nm: &netmap.NetworkMap{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.1/32"),
|
||||
netip.MustParsePrefix("fe70::1/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::1/128"),
|
||||
},
|
||||
},
|
||||
peer: &tailcfg.Node{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.2/32"),
|
||||
netip.MustParsePrefix("fe70::2/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.2/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::2/128"),
|
||||
},
|
||||
Hostinfo: (&tailcfg.Hostinfo{
|
||||
Services: []tailcfg.Service{
|
||||
@@ -446,15 +445,15 @@ func TestPeerAPIBase(t *testing.T) {
|
||||
{
|
||||
name: "self_both_them_no_peerapi_service",
|
||||
nm: &netmap.NetworkMap{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.1/32"),
|
||||
netip.MustParsePrefix("fe70::1/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.1/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::1/128"),
|
||||
},
|
||||
},
|
||||
peer: &tailcfg.Node{
|
||||
Addresses: []netip.Prefix{
|
||||
netip.MustParsePrefix("100.64.1.2/32"),
|
||||
netip.MustParsePrefix("fe70::2/128"),
|
||||
Addresses: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("100.64.1.2/32"),
|
||||
netaddr.MustParseIPPrefix("fe70::2/128"),
|
||||
},
|
||||
},
|
||||
want: "",
|
||||
@@ -542,10 +541,10 @@ func TestFileTargets(t *testing.T) {
|
||||
func TestInternalAndExternalInterfaces(t *testing.T) {
|
||||
type interfacePrefix struct {
|
||||
i interfaces.Interface
|
||||
pfx netip.Prefix
|
||||
pfx netaddr.IPPrefix
|
||||
}
|
||||
|
||||
masked := func(ips ...interfacePrefix) (pfxs []netip.Prefix) {
|
||||
masked := func(ips ...interfacePrefix) (pfxs []netaddr.IPPrefix) {
|
||||
for _, ip := range ips {
|
||||
pfxs = append(pfxs, ip.pfx.Masked())
|
||||
}
|
||||
@@ -558,11 +557,11 @@ func TestInternalAndExternalInterfaces(t *testing.T) {
|
||||
return il
|
||||
}
|
||||
newInterface := func(name, pfx string, wsl2, loopback bool) interfacePrefix {
|
||||
ippfx := netip.MustParsePrefix(pfx)
|
||||
ippfx := netaddr.MustParseIPPrefix(pfx)
|
||||
ip := interfaces.Interface{
|
||||
Interface: &net.Interface{},
|
||||
AltAddrs: []net.Addr{
|
||||
netipx.PrefixIPNet(ippfx),
|
||||
ippfx.IPNet(),
|
||||
},
|
||||
}
|
||||
if loopback {
|
||||
@@ -584,8 +583,8 @@ func TestInternalAndExternalInterfaces(t *testing.T) {
|
||||
name string
|
||||
goos string
|
||||
il interfaces.List
|
||||
wantInt []netip.Prefix
|
||||
wantExt []netip.Prefix
|
||||
wantInt []netaddr.IPPrefix
|
||||
wantExt []netaddr.IPPrefix
|
||||
}{
|
||||
{
|
||||
name: "single-interface",
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
@@ -32,6 +31,7 @@ import (
|
||||
|
||||
"github.com/kortschak/wol"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/hostinfo"
|
||||
@@ -39,7 +39,6 @@ import (
|
||||
"tailscale.com/logtail/backoff"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/interfaces"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/netutil"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/tailcfg"
|
||||
@@ -48,7 +47,7 @@ import (
|
||||
"tailscale.com/wgengine/filter"
|
||||
)
|
||||
|
||||
var initListenConfig func(*net.ListenConfig, netip.Addr, *interfaces.State, string) error
|
||||
var initListenConfig func(*net.ListenConfig, netaddr.IP, *interfaces.State, string) error
|
||||
|
||||
// addH2C is non-nil on platforms where we want to add H2C
|
||||
// ("cleartext" HTTP/2) support to the peerAPI.
|
||||
@@ -387,7 +386,7 @@ func (s *peerAPIServer) OpenFile(baseName string) (rc io.ReadCloser, size int64,
|
||||
return f, fi.Size(), nil
|
||||
}
|
||||
|
||||
func (s *peerAPIServer) listen(ip netip.Addr, ifState *interfaces.State) (ln net.Listener, err error) {
|
||||
func (s *peerAPIServer) listen(ip netaddr.IP, ifState *interfaces.State) (ln net.Listener, err error) {
|
||||
// Android for whatever reason often has problems creating the peerapi listener.
|
||||
// But since we started intercepting it with netstack, it's not even important that
|
||||
// we have a real kernel-level listener. So just create a dummy listener on Android
|
||||
@@ -451,7 +450,7 @@ func (s *peerAPIServer) listen(ip netip.Addr, ifState *interfaces.State) (ln net
|
||||
|
||||
type peerAPIListener struct {
|
||||
ps *peerAPIServer
|
||||
ip netip.Addr
|
||||
ip netaddr.IP
|
||||
lb *LocalBackend
|
||||
|
||||
// ln is the Listener. It can be nil in netstack mode if there are more than
|
||||
@@ -503,7 +502,7 @@ func (pln *peerAPIListener) serve() {
|
||||
}
|
||||
}
|
||||
|
||||
func (pln *peerAPIListener) ServeConn(src netip.AddrPort, c net.Conn) {
|
||||
func (pln *peerAPIListener) ServeConn(src netaddr.IPPort, c net.Conn) {
|
||||
logf := pln.lb.logf
|
||||
peerNode, peerUser, ok := pln.lb.WhoIs(src)
|
||||
if !ok {
|
||||
@@ -530,7 +529,7 @@ func (pln *peerAPIListener) ServeConn(src netip.AddrPort, c net.Conn) {
|
||||
// peerAPIHandler serves the Peer API for a source specific client.
|
||||
type peerAPIHandler struct {
|
||||
ps *peerAPIServer
|
||||
remoteAddr netip.AddrPort
|
||||
remoteAddr netaddr.IPPort
|
||||
isSelf bool // whether peerNode is owned by same user as this node
|
||||
peerNode *tailcfg.Node // peerNode is who's making the request
|
||||
peerUser tailcfg.UserProfile // profile of peerNode
|
||||
@@ -578,7 +577,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
<body>
|
||||
<h1>Hello, %s (%v)</h1>
|
||||
This is my Tailscale device. Your device is %v.
|
||||
`, html.EscapeString(who), h.remoteAddr.Addr(), html.EscapeString(h.peerNode.ComputedName))
|
||||
`, html.EscapeString(who), h.remoteAddr.IP(), html.EscapeString(h.peerNode.ComputedName))
|
||||
|
||||
if h.isSelf {
|
||||
fmt.Fprintf(w, "<p>You are the owner of this node.\n")
|
||||
@@ -609,7 +608,7 @@ func (h *peerAPIHandler) handleServeInterfaces(w http.ResponseWriter, r *http.Re
|
||||
fmt.Fprintf(w, "<th>%v</th> ", v)
|
||||
}
|
||||
fmt.Fprint(w, "</tr>\n")
|
||||
i.ForeachInterface(func(iface interfaces.Interface, ipps []netip.Prefix) {
|
||||
i.ForeachInterface(func(iface interfaces.Interface, ipps []netaddr.IPPrefix) {
|
||||
fmt.Fprint(w, "<tr>")
|
||||
for _, v := range []any{iface.Index, iface.Name, iface.MTU, iface.Flags, ipps} {
|
||||
fmt.Fprintf(w, "<td>%v</td> ", v)
|
||||
@@ -694,7 +693,7 @@ func (h *peerAPIHandler) canWakeOnLAN() bool {
|
||||
}
|
||||
|
||||
func (h *peerAPIHandler) peerHasCap(wantCap string) bool {
|
||||
for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.Addr()) {
|
||||
for _, hasCap := range h.ps.b.PeerCaps(h.remoteAddr.IP()) {
|
||||
if hasCap == wantCap {
|
||||
return true
|
||||
}
|
||||
@@ -802,7 +801,7 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
d := time.Since(t0).Round(time.Second / 10)
|
||||
h.logf("got put of %s in %v from %v/%v", approxSize(finalSize), d, h.remoteAddr.Addr(), h.peerNode.ComputedName)
|
||||
h.logf("got put of %s in %v from %v/%v", approxSize(finalSize), d, h.remoteAddr.IP, h.peerNode.ComputedName)
|
||||
|
||||
// TODO: set modtime
|
||||
// TODO: some real response
|
||||
@@ -926,11 +925,12 @@ func (h *peerAPIHandler) handleWakeOnLAN(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
for ifName, ips := range st.InterfaceIPs {
|
||||
for _, ip := range ips {
|
||||
if ip.Addr().IsLoopback() || ip.Addr().Is6() {
|
||||
if ip.IP().IsLoopback() || ip.IP().Is6() {
|
||||
continue
|
||||
}
|
||||
ipa := ip.IP().IPAddr()
|
||||
local := &net.UDPAddr{
|
||||
IP: ip.Addr().AsSlice(),
|
||||
IP: ipa.IP,
|
||||
Port: 0,
|
||||
}
|
||||
remote := &net.UDPAddr{
|
||||
@@ -982,11 +982,11 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
|
||||
// arbitrary. DNS runs over TCP and UDP, so sure... we check
|
||||
// TCP.
|
||||
dstIP := netaddr.IPv4(0, 0, 0, 0)
|
||||
remoteIP := h.remoteAddr.Addr()
|
||||
remoteIP := h.remoteAddr.IP()
|
||||
if remoteIP.Is6() {
|
||||
// autogroup:internet for IPv6 is defined to start with 2000::/3,
|
||||
// so use 2000::0 as the probe "the internet" address.
|
||||
dstIP = netip.MustParseAddr("2000::")
|
||||
dstIP = netaddr.MustParseIP("2000::")
|
||||
}
|
||||
verdict := f.CheckTCP(remoteIP, dstIP, 53)
|
||||
return verdict == filter.Accept
|
||||
@@ -1169,9 +1169,9 @@ func writePrettyDNSReply(w io.Writer, res []byte) (err error) {
|
||||
// it's listening on the provided IP address and on TCP port 1.
|
||||
//
|
||||
// See docs on fakePeerAPIListener.
|
||||
func newFakePeerAPIListener(ip netip.Addr) net.Listener {
|
||||
func newFakePeerAPIListener(ip netaddr.IP) net.Listener {
|
||||
return &fakePeerAPIListener{
|
||||
addr: net.TCPAddrFromAddrPort(netip.AddrPortFrom(ip, 1)),
|
||||
addr: netaddr.IPPortFrom(ip, 1).TCPAddr(),
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ package ipnlocal
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/interfaces"
|
||||
"tailscale.com/net/netns"
|
||||
)
|
||||
@@ -24,7 +24,7 @@ func init() {
|
||||
// initListenConfigNetworkExtension configures nc for listening on IP
|
||||
// through the iOS/macOS Network/System Extension (Packet Tunnel
|
||||
// Provider) sandbox.
|
||||
func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netip.Addr, st *interfaces.State, tunIfName string) error {
|
||||
func initListenConfigNetworkExtension(nc *net.ListenConfig, ip netaddr.IP, st *interfaces.State, tunIfName string) error {
|
||||
tunIf, ok := st.Interface[tunIfName]
|
||||
if !ok {
|
||||
return fmt.Errorf("no interface with name %q", tunIfName)
|
||||
|
||||
@@ -13,14 +13,13 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go4.org/netipx"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstest"
|
||||
@@ -583,7 +582,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
|
||||
t.Errorf("for isSelf = false; want true")
|
||||
}
|
||||
h.isSelf = false
|
||||
h.remoteAddr = netip.MustParseAddrPort("100.150.151.152:12345")
|
||||
h.remoteAddr = netaddr.MustParseIPPort("100.150.151.152:12345")
|
||||
|
||||
eng, _ := wgengine.NewFakeUserspaceEngine(logger.Discard, 0)
|
||||
h.ps = &peerAPIServer{
|
||||
@@ -595,9 +594,9 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
|
||||
t.Fatal("unexpectedly offering exit node")
|
||||
}
|
||||
h.ps.b.prefs = &ipn.Prefs{
|
||||
AdvertiseRoutes: []netip.Prefix{
|
||||
netip.MustParsePrefix("0.0.0.0/0"),
|
||||
netip.MustParsePrefix("::/0"),
|
||||
AdvertiseRoutes: []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("0.0.0.0/0"),
|
||||
netaddr.MustParseIPPrefix("::/0"),
|
||||
},
|
||||
}
|
||||
if !h.ps.b.OfferingExitNode() {
|
||||
@@ -608,7 +607,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
|
||||
t.Errorf("unexpectedly doing DNS without filter")
|
||||
}
|
||||
|
||||
h.ps.b.setFilter(filter.NewAllowNone(logger.Discard, new(netipx.IPSet)))
|
||||
h.ps.b.setFilter(filter.NewAllowNone(logger.Discard, new(netaddr.IPSet)))
|
||||
if h.replyToDNSQueries() {
|
||||
t.Errorf("unexpectedly doing DNS without filter")
|
||||
}
|
||||
@@ -621,7 +620,7 @@ func TestPeerAPIReplyToDNSQueries(t *testing.T) {
|
||||
}
|
||||
|
||||
// Also test IPv6.
|
||||
h.remoteAddr = netip.MustParseAddrPort("[fe70::1]:12345")
|
||||
h.remoteAddr = netaddr.MustParseIPPort("[fe70::1]:12345")
|
||||
if !h.replyToDNSQueries() {
|
||||
t.Errorf("unexpectedly IPv6 deny; wanted to be a DNS server")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package ipnlocal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
@@ -26,7 +25,6 @@ import (
|
||||
|
||||
"github.com/tailscale/golang-x-crypto/ssh"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/util/mak"
|
||||
)
|
||||
|
||||
var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS")
|
||||
@@ -37,39 +35,34 @@ var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS")
|
||||
var keyTypes = []string{"rsa", "ecdsa", "ed25519"}
|
||||
|
||||
func (b *LocalBackend) GetSSH_HostKeys() (keys []ssh.Signer, err error) {
|
||||
var existing map[string]ssh.Signer
|
||||
if os.Geteuid() == 0 {
|
||||
existing = b.getSystemSSH_HostKeys()
|
||||
keys, err = b.getSystemSSH_HostKeys()
|
||||
if err != nil || len(keys) > 0 {
|
||||
return keys, err
|
||||
}
|
||||
// Otherwise, perhaps they don't have OpenSSH etc installed.
|
||||
// Generate our own keys...
|
||||
}
|
||||
return b.getTailscaleSSH_HostKeys(existing)
|
||||
return b.getTailscaleSSH_HostKeys()
|
||||
}
|
||||
|
||||
// getTailscaleSSH_HostKeys returns the three (rsa, ecdsa, ed25519) SSH host
|
||||
// keys, reusing the provided ones in existing if present in the map.
|
||||
func (b *LocalBackend) getTailscaleSSH_HostKeys(existing map[string]ssh.Signer) (keys []ssh.Signer, err error) {
|
||||
var keyDir string // lazily initialized $TAILSCALE_VAR/ssh dir.
|
||||
func (b *LocalBackend) getTailscaleSSH_HostKeys() (keys []ssh.Signer, err error) {
|
||||
root := b.TailscaleVarRoot()
|
||||
if root == "" {
|
||||
return nil, errors.New("no var root for ssh keys")
|
||||
}
|
||||
keyDir := filepath.Join(root, "ssh")
|
||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, typ := range keyTypes {
|
||||
if s, ok := existing[typ]; ok {
|
||||
keys = append(keys, s)
|
||||
continue
|
||||
}
|
||||
if keyDir == "" {
|
||||
root := b.TailscaleVarRoot()
|
||||
if root == "" {
|
||||
return nil, errors.New("no var root for ssh keys")
|
||||
}
|
||||
keyDir = filepath.Join(root, "ssh")
|
||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
hostKey, err := b.hostKeyFileOrCreate(keyDir, typ)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating SSH host key type %q in %q: %w", typ, keyDir, err)
|
||||
return nil, err
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(hostKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SSH host key type %q from %q: %w", typ, keyDir, err)
|
||||
return nil, err
|
||||
}
|
||||
keys = append(keys, signer)
|
||||
}
|
||||
@@ -121,21 +114,24 @@ func (b *LocalBackend) hostKeyFileOrCreate(keyDir, typ string) ([]byte, error) {
|
||||
return pemGen, err
|
||||
}
|
||||
|
||||
func (b *LocalBackend) getSystemSSH_HostKeys() (ret map[string]ssh.Signer) {
|
||||
func (b *LocalBackend) getSystemSSH_HostKeys() (ret []ssh.Signer, err error) {
|
||||
// TODO(bradfitz): cache this?
|
||||
for _, typ := range keyTypes {
|
||||
filename := "/etc/ssh/ssh_host_" + typ + "_key"
|
||||
hostKey, err := ioutil.ReadFile(filename)
|
||||
if err != nil || len(bytes.TrimSpace(hostKey)) == 0 {
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(hostKey)
|
||||
if err != nil {
|
||||
b.logf("warning: error reading host key %s: %v (generating one instead)", filename, err)
|
||||
continue
|
||||
return nil, fmt.Errorf("error reading private key %s: %w", filename, err)
|
||||
}
|
||||
mak.Set(&ret, typ, signer)
|
||||
ret = append(ret, signer)
|
||||
}
|
||||
return ret
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (b *LocalBackend) getSSHHostKeyPublicStrings() (ret []string) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
func TestSSHKeyGen(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
lb := &LocalBackend{varRoot: dir}
|
||||
keys, err := lb.getTailscaleSSH_HostKeys(nil)
|
||||
keys, err := lb.getTailscaleSSH_HostKeys()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func TestSSHKeyGen(t *testing.T) {
|
||||
t.Fatalf("keys = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
keys2, err := lb.getTailscaleSSH_HostKeys(nil)
|
||||
keys2, err := lb.getTailscaleSSH_HostKeys()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -30,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"inet.af/peercred"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/envknob"
|
||||
@@ -146,15 +146,15 @@ func (s *Server) getConnIdentity(c net.Conn) (ci connIdentity, err error) {
|
||||
ci.Creds, _ = peercred.Get(c)
|
||||
return ci, nil
|
||||
}
|
||||
la, err := netip.ParseAddrPort(c.LocalAddr().String())
|
||||
la, err := netaddr.ParseIPPort(c.LocalAddr().String())
|
||||
if err != nil {
|
||||
return ci, fmt.Errorf("parsing local address: %w", err)
|
||||
}
|
||||
ra, err := netip.ParseAddrPort(c.RemoteAddr().String())
|
||||
ra, err := netaddr.ParseIPPort(c.RemoteAddr().String())
|
||||
if err != nil {
|
||||
return ci, fmt.Errorf("parsing local remote: %w", err)
|
||||
}
|
||||
if !la.Addr().IsLoopback() || !ra.Addr().IsLoopback() {
|
||||
if !la.IP().IsLoopback() || !ra.IP().IsLoopback() {
|
||||
return ci, errors.New("non-loopback connection")
|
||||
}
|
||||
tab, err := netstat.Get()
|
||||
@@ -772,7 +772,7 @@ func New(logf logger.Logf, logid string, store ipn.StateStore, eng wgengine.Engi
|
||||
|
||||
dg := distro.Get()
|
||||
switch dg {
|
||||
case distro.Synology, distro.TrueNAS, distro.QNAP:
|
||||
case distro.Synology, distro.TrueNAS:
|
||||
// See if they have a "Taildrop" share.
|
||||
// See https://github.com/tailscale/tailscale/issues/2179#issuecomment-982821319
|
||||
path, err := findTaildropDir(dg)
|
||||
@@ -1065,7 +1065,7 @@ func (s *Server) ServeHTMLStatus(w http.ResponseWriter, r *http.Request) {
|
||||
st.WriteHTML(w)
|
||||
}
|
||||
|
||||
func peerPid(entries []netstat.Entry, la, ra netip.AddrPort) int {
|
||||
func peerPid(entries []netstat.Entry, la, ra netaddr.IPPort) int {
|
||||
for _, e := range entries {
|
||||
if e.Local == ra && e.Remote == la {
|
||||
return e.Pid
|
||||
@@ -1123,8 +1123,6 @@ func findTaildropDir(dg distro.Distro) (string, error) {
|
||||
return findSynologyTaildropDir(name)
|
||||
case distro.TrueNAS:
|
||||
return findTrueNASTaildropDir(name)
|
||||
case distro.QNAP:
|
||||
return findQnapTaildropDir(name)
|
||||
}
|
||||
return "", fmt.Errorf("%s is an unsupported distro for Taildrop dir", dg)
|
||||
}
|
||||
@@ -1165,28 +1163,6 @@ func findTrueNASTaildropDir(name string) (dir string, err error) {
|
||||
return "", fmt.Errorf("shared folder %q not found", name)
|
||||
}
|
||||
|
||||
// findQnapTaildropDir checks if a Shared Folder named "Taildrop" exists.
|
||||
func findQnapTaildropDir(name string) (string, error) {
|
||||
dir := fmt.Sprintf("/share/%s", name)
|
||||
fi, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("shared folder %q not found", name)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// share/Taildrop is usually a symlink to CACHEDEV1_DATA/Taildrop/ or some such.
|
||||
fullpath, err := filepath.EvalSymlinks(dir)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("symlink to shared folder %q not found", name)
|
||||
}
|
||||
if fi, err = os.Stat(fullpath); err == nil && fi.IsDir() {
|
||||
return dir, nil // return the symlink, how QNAP set it up
|
||||
}
|
||||
return "", fmt.Errorf("shared folder %q not found", name)
|
||||
}
|
||||
|
||||
func loadExtraEnv() (env []string, err error) {
|
||||
if runtime.GOOS != "windows" {
|
||||
return nil, nil
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
"html"
|
||||
"io"
|
||||
"log"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/views"
|
||||
@@ -35,7 +35,7 @@ type Status struct {
|
||||
BackendState string
|
||||
|
||||
AuthURL string // current URL provided by control to authorize client
|
||||
TailscaleIPs []netip.Addr // Tailscale IP(s) assigned to this node
|
||||
TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node
|
||||
Self *PeerStatus
|
||||
|
||||
// ExitNodeStatus describes the current exit node.
|
||||
@@ -94,7 +94,7 @@ type ExitNodeStatus struct {
|
||||
Online bool
|
||||
|
||||
// TailscaleIPs are the exit node's IP addresses assigned to the node.
|
||||
TailscaleIPs []netip.Prefix
|
||||
TailscaleIPs []netaddr.IPPrefix
|
||||
}
|
||||
|
||||
func (s *Status) Peers() []key.NodePublic {
|
||||
@@ -124,7 +124,7 @@ type PeerStatus struct {
|
||||
DNSName string
|
||||
OS string // HostInfo.OS
|
||||
UserID tailcfg.UserID
|
||||
TailscaleIPs []netip.Addr // Tailscale IP(s) assigned to this node
|
||||
TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node
|
||||
|
||||
// Tags are the list of ACL tags applied to this node.
|
||||
// See tailscale.com/tailcfg#Node.Tags for more information.
|
||||
@@ -240,7 +240,7 @@ func (sb *StatusBuilder) AddUser(id tailcfg.UserID, up tailcfg.UserProfile) {
|
||||
}
|
||||
|
||||
// AddIP adds a Tailscale IP address to the status.
|
||||
func (sb *StatusBuilder) AddTailscaleIP(ip netip.Addr) {
|
||||
func (sb *StatusBuilder) AddTailscaleIP(ip netaddr.IP) {
|
||||
sb.mu.Lock()
|
||||
defer sb.mu.Unlock()
|
||||
if sb.locked {
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -25,6 +24,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
@@ -222,10 +222,10 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
b := h.b
|
||||
var ipp netip.AddrPort
|
||||
var ipp netaddr.IPPort
|
||||
if v := r.FormValue("addr"); v != "" {
|
||||
var err error
|
||||
ipp, err = netip.ParseAddrPort(v)
|
||||
ipp, err = netaddr.ParseIPPort(v)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid 'addr' parameter", 400)
|
||||
return
|
||||
@@ -242,7 +242,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
|
||||
res := &apitype.WhoIsResponse{
|
||||
Node: n,
|
||||
UserProfile: &u,
|
||||
Caps: b.PeerCaps(ipp.Addr()),
|
||||
Caps: b.PeerCaps(ipp.IP()),
|
||||
}
|
||||
j, err := json.MarshalIndent(res, "", "\t")
|
||||
if err != nil {
|
||||
@@ -667,7 +667,7 @@ func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "missing 'ip' parameter", 400)
|
||||
return
|
||||
}
|
||||
ip, err := netip.ParseAddr(ipStr)
|
||||
ip, err := netaddr.ParseIP(ipStr)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid IP", 400)
|
||||
return
|
||||
|
||||
25
ipn/prefs.go
25
ipn/prefs.go
@@ -11,16 +11,15 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/persist"
|
||||
@@ -99,7 +98,7 @@ type Prefs struct {
|
||||
// blackhole route will be installed on the local system to
|
||||
// prevent any traffic escaping to the local network.
|
||||
ExitNodeID tailcfg.StableNodeID
|
||||
ExitNodeIP netip.Addr
|
||||
ExitNodeIP netaddr.IP
|
||||
|
||||
// ExitNodeAllowLANAccess indicates whether locally accessible subnets should be
|
||||
// routed directly or via the exit node.
|
||||
@@ -168,7 +167,7 @@ type Prefs struct {
|
||||
// AdvertiseRoutes specifies CIDR prefixes to advertise into the
|
||||
// Tailscale network as reachable through the current
|
||||
// node.
|
||||
AdvertiseRoutes []netip.Prefix
|
||||
AdvertiseRoutes []netaddr.IPPrefix
|
||||
|
||||
// NoSNAT specifies whether to source NAT traffic going to
|
||||
// destinations in AdvertiseRoutes. The default is to apply source
|
||||
@@ -309,7 +308,7 @@ func (p *Prefs) pretty(goos string) string {
|
||||
if p.ShieldsUp {
|
||||
sb.WriteString("shields=true ")
|
||||
}
|
||||
if p.ExitNodeIP.IsValid() {
|
||||
if !p.ExitNodeIP.IsZero() {
|
||||
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeIP, p.ExitNodeAllowLANAccess)
|
||||
} else if !p.ExitNodeID.IsZero() {
|
||||
fmt.Fprintf(&sb, "exit=%v lan=%t ", p.ExitNodeID, p.ExitNodeAllowLANAccess)
|
||||
@@ -383,7 +382,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
||||
p.Persist.Equals(p2.Persist)
|
||||
}
|
||||
|
||||
func compareIPNets(a, b []netip.Prefix) bool {
|
||||
func compareIPNets(a, b []netaddr.IPPrefix) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
@@ -478,13 +477,13 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
|
||||
return
|
||||
}
|
||||
p.AdvertiseRoutes = append(p.AdvertiseRoutes,
|
||||
netip.PrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0),
|
||||
netip.PrefixFrom(netip.IPv6Unspecified(), 0))
|
||||
netaddr.IPPrefixFrom(netaddr.IPv4(0, 0, 0, 0), 0),
|
||||
netaddr.IPPrefixFrom(netaddr.IPv6Unspecified(), 0))
|
||||
}
|
||||
|
||||
// peerWithTailscaleIP returns the peer in st with the provided
|
||||
// Tailscale IP.
|
||||
func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
|
||||
func peerWithTailscaleIP(st *ipnstate.Status, ip netaddr.IP) (ps *ipnstate.PeerStatus, ok bool) {
|
||||
for _, ps := range st.Peer {
|
||||
for _, ip2 := range ps.TailscaleIPs {
|
||||
if ip == ip2 {
|
||||
@@ -495,7 +494,7 @@ func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerS
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
|
||||
func isRemoteIP(st *ipnstate.Status, ip netaddr.IP) bool {
|
||||
for _, selfIP := range st.TailscaleIPs {
|
||||
if ip == selfIP {
|
||||
return false
|
||||
@@ -507,7 +506,7 @@ func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
|
||||
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.
|
||||
func (p *Prefs) ClearExitNode() {
|
||||
p.ExitNodeID = ""
|
||||
p.ExitNodeIP = netip.Addr{}
|
||||
p.ExitNodeIP = netaddr.IP{}
|
||||
}
|
||||
|
||||
// ExitNodeLocalIPError is returned when the requested IP address for an exit
|
||||
@@ -520,11 +519,11 @@ func (e ExitNodeLocalIPError) Error() string {
|
||||
return fmt.Sprintf("cannot use %s as an exit node as it is a local IP address to this machine", e.hostOrIP)
|
||||
}
|
||||
|
||||
func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netip.Addr, err error) {
|
||||
func exitNodeIPOfArg(s string, st *ipnstate.Status) (ip netaddr.IP, err error) {
|
||||
if s == "" {
|
||||
return ip, os.ErrInvalid
|
||||
}
|
||||
ip, err = netip.ParseAddr(s)
|
||||
ip, err = netaddr.ParseIP(s)
|
||||
if err == nil {
|
||||
// If we're online already and have a netmap, double check that the IP
|
||||
// address specified is valid.
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/netip"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -17,8 +16,8 @@ import (
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tstest"
|
||||
"tailscale.com/types/key"
|
||||
@@ -63,9 +62,9 @@ func TestPrefsEqual(t *testing.T) {
|
||||
have, prefsHandles)
|
||||
}
|
||||
|
||||
nets := func(strs ...string) (ns []netip.Prefix) {
|
||||
nets := func(strs ...string) (ns []netaddr.IPPrefix) {
|
||||
for _, s := range strs {
|
||||
n, err := netip.ParsePrefix(s)
|
||||
n, err := netaddr.ParseIPPrefix(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -138,13 +137,13 @@ func TestPrefsEqual(t *testing.T) {
|
||||
},
|
||||
|
||||
{
|
||||
&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
|
||||
&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
|
||||
&Prefs{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
|
||||
&Prefs{ExitNodeIP: netip.MustParseAddr("1.2.3.4")},
|
||||
&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
|
||||
&Prefs{ExitNodeIP: netaddr.MustParseIP("1.2.3.4")},
|
||||
true,
|
||||
},
|
||||
|
||||
@@ -227,12 +226,12 @@ func TestPrefsEqual(t *testing.T) {
|
||||
|
||||
{
|
||||
&Prefs{AdvertiseRoutes: nil},
|
||||
&Prefs{AdvertiseRoutes: []netip.Prefix{}},
|
||||
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&Prefs{AdvertiseRoutes: []netip.Prefix{}},
|
||||
&Prefs{AdvertiseRoutes: []netip.Prefix{}},
|
||||
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}},
|
||||
&Prefs{AdvertiseRoutes: []netaddr.IPPrefix{}},
|
||||
true,
|
||||
},
|
||||
{
|
||||
@@ -416,7 +415,7 @@ func TestPrefsPretty(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Prefs{
|
||||
ExitNodeIP: netip.MustParseAddr("1.2.3.4"),
|
||||
ExitNodeIP: netaddr.MustParseIP("1.2.3.4"),
|
||||
},
|
||||
"linux",
|
||||
`Prefs{ra=false mesh=false dns=false want=false exit=1.2.3.4 lan=false routes=[] nf=off Persist=nil}`,
|
||||
@@ -659,8 +658,8 @@ func TestPrefsExitNode(t *testing.T) {
|
||||
if p.AdvertisesExitNode() {
|
||||
t.Errorf("default shouldn't advertise exit node")
|
||||
}
|
||||
p.AdvertiseRoutes = []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/16"),
|
||||
p.AdvertiseRoutes = []netaddr.IPPrefix{
|
||||
netaddr.MustParseIPPrefix("10.0.0.0/16"),
|
||||
}
|
||||
p.SetAdvertiseExitNode(true)
|
||||
if got, want := len(p.AdvertiseRoutes), 3; got != want {
|
||||
@@ -683,12 +682,12 @@ func TestPrefsExitNode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExitNodeIPOfArg(t *testing.T) {
|
||||
mustIP := netip.MustParseAddr
|
||||
mustIP := netaddr.MustParseIP
|
||||
tests := []struct {
|
||||
name string
|
||||
arg string
|
||||
st *ipnstate.Status
|
||||
want netip.Addr
|
||||
want netaddr.IP
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
@@ -714,7 +713,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
BackendState: "Running",
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.2.3.4")},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -727,7 +726,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
BackendState: "Running",
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.2.3.4")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.2.3.4")},
|
||||
ExitNodeOption: true,
|
||||
},
|
||||
},
|
||||
@@ -748,7 +747,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "skippy.foo.",
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")},
|
||||
ExitNodeOption: true,
|
||||
},
|
||||
},
|
||||
@@ -763,7 +762,7 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "skippy.foo.",
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -777,12 +776,12 @@ func TestExitNodeIPOfArg(t *testing.T) {
|
||||
Peer: map[key.NodePublic]*ipnstate.PeerStatus{
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "skippy.foo.",
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")},
|
||||
ExitNodeOption: true,
|
||||
},
|
||||
key.NewNode().Public(): {
|
||||
DNSName: "SKIPPY.foo.",
|
||||
TailscaleIPs: []netip.Addr{mustIP("1.0.0.2")},
|
||||
TailscaleIPs: []netaddr.IP{mustIP("1.0.0.2")},
|
||||
ExitNodeOption: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux && !ts_omit_aws
|
||||
// +build linux,!ts_omit_aws
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
// Package awsstore contains an ipn.StateStore implementation using AWS SSM.
|
||||
package awsstore
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux || ts_omit_aws
|
||||
// +build !linux ts_omit_aws
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package awsstore
|
||||
|
||||
@@ -12,9 +12,8 @@ import (
|
||||
"runtime"
|
||||
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func New(logger.Logf, string) (ipn.StateStore, error) {
|
||||
func NewStore(string) (ipn.StateStore, error) {
|
||||
return nil, fmt.Errorf("AWS store is not supported on %v", runtime.GOOS)
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ func New(collection string) *Policy {
|
||||
}
|
||||
}
|
||||
|
||||
conf := logtail.Config{
|
||||
c := logtail.Config{
|
||||
Collection: newc.Collection,
|
||||
PrivateID: newc.PrivateID,
|
||||
Stderr: logWriter{console},
|
||||
@@ -534,16 +534,16 @@ func New(collection string) *Policy {
|
||||
HTTPC: &http.Client{Transport: NewLogtailTransport(logtail.DefaultHost)},
|
||||
}
|
||||
if collection == logtail.CollectionNode {
|
||||
conf.MetricsDelta = clientmetric.EncodeLogTailMetricsDelta
|
||||
conf.IncludeProcID = true
|
||||
conf.IncludeProcSequence = true
|
||||
c.MetricsDelta = clientmetric.EncodeLogTailMetricsDelta
|
||||
c.IncludeProcID = true
|
||||
c.IncludeProcSequence = true
|
||||
}
|
||||
|
||||
if val := getLogTarget(); val != "" {
|
||||
log.Println("You have enabled a non-default log target. Doing without being told to by Tailscale staff or your network administrator will make getting support difficult.")
|
||||
conf.BaseURL = val
|
||||
c.BaseURL = val
|
||||
u, _ := url.Parse(val)
|
||||
conf.HTTPC = &http.Client{Transport: NewLogtailTransport(u.Host)}
|
||||
c.HTTPC = &http.Client{Transport: NewLogtailTransport(u.Host)}
|
||||
}
|
||||
|
||||
filchOptions := filch.Options{
|
||||
@@ -551,12 +551,12 @@ func New(collection string) *Policy {
|
||||
}
|
||||
filchPrefix := filepath.Join(dir, cmdName)
|
||||
|
||||
// NAS disks cannot hibernate if we're writing logs to them all the time.
|
||||
// Synology disks cannot hibernate if we're writing logs to them all the time.
|
||||
// https://github.com/tailscale/tailscale/issues/3551
|
||||
if runtime.GOOS == "linux" && (distro.Get() == distro.Synology || distro.Get() == distro.QNAP) {
|
||||
tmpfsLogs := "/tmp/tailscale-logs"
|
||||
if err := os.MkdirAll(tmpfsLogs, 0755); err == nil {
|
||||
filchPrefix = filepath.Join(tmpfsLogs, cmdName)
|
||||
if runtime.GOOS == "linux" && distro.Get() == distro.Synology {
|
||||
synologyTmpfsLogs := "/tmp/tailscale-logs"
|
||||
if err := os.MkdirAll(synologyTmpfsLogs, 0755); err == nil {
|
||||
filchPrefix = filepath.Join(synologyTmpfsLogs, cmdName)
|
||||
filchOptions.MaxFileSize = 1 << 20
|
||||
} else {
|
||||
// not a fatal error, we can leave the log files on the spinning disk
|
||||
@@ -566,16 +566,16 @@ func New(collection string) *Policy {
|
||||
|
||||
filchBuf, filchErr := filch.New(filchPrefix, filchOptions)
|
||||
if filchBuf != nil {
|
||||
conf.Buffer = filchBuf
|
||||
c.Buffer = filchBuf
|
||||
if filchBuf.OrigStderr != nil {
|
||||
conf.Stderr = filchBuf.OrigStderr
|
||||
c.Stderr = filchBuf.OrigStderr
|
||||
}
|
||||
}
|
||||
lw := logtail.NewLogger(conf, log.Printf)
|
||||
lw := logtail.NewLogger(c, log.Printf)
|
||||
|
||||
var logOutput io.Writer = lw
|
||||
|
||||
if runtime.GOOS == "windows" && conf.Collection == logtail.CollectionNode {
|
||||
if runtime.GOOS == "windows" && c.Collection == logtail.CollectionNode {
|
||||
logID := newc.PublicID.String()
|
||||
exe, _ := os.Executable()
|
||||
if strings.EqualFold(filepath.Base(exe), "tailscaled.exe") {
|
||||
|
||||
@@ -21,8 +21,6 @@ type Buffer interface {
|
||||
TryReadLine() ([]byte, error)
|
||||
|
||||
// Write writes a log line into the ring buffer.
|
||||
//
|
||||
// Write takes ownership of the provided slice.
|
||||
Write([]byte) (int, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -167,9 +167,8 @@ type Logger struct {
|
||||
|
||||
procID uint32
|
||||
includeProcSequence bool
|
||||
|
||||
writeLock sync.Mutex // guards increments of procSequence
|
||||
procSequence uint64
|
||||
writeLock sync.Mutex // guards increments of procSequence
|
||||
procSequence uint64
|
||||
|
||||
shutdownStart chan struct{} // closed when shutdown begins
|
||||
shutdownDone chan struct{} // closed when shutdown complete
|
||||
@@ -455,7 +454,7 @@ func Disable() {
|
||||
logtailDisabled.Set(true)
|
||||
}
|
||||
|
||||
func (l *Logger) sendLocked(jsonBlob []byte) (int, error) {
|
||||
func (l *Logger) send(jsonBlob []byte) (int, error) {
|
||||
if logtailDisabled.Get() {
|
||||
return len(jsonBlob), nil
|
||||
}
|
||||
@@ -579,7 +578,7 @@ func (l *Logger) encodeText(buf []byte, skipClientTime bool, procID uint32, proc
|
||||
return b
|
||||
}
|
||||
|
||||
func (l *Logger) encodeLocked(buf []byte, level int) []byte {
|
||||
func (l *Logger) encode(buf []byte, level int) []byte {
|
||||
if l.includeProcSequence {
|
||||
l.procSequence++
|
||||
}
|
||||
@@ -660,12 +659,10 @@ func (l *Logger) Write(buf []byte) (int, error) {
|
||||
l.stderr.Write(withNL)
|
||||
}
|
||||
}
|
||||
|
||||
l.writeLock.Lock()
|
||||
defer l.writeLock.Unlock()
|
||||
|
||||
b := l.encodeLocked(buf, level)
|
||||
_, err := l.sendLocked(b)
|
||||
b := l.encode(buf, level)
|
||||
_, err := l.send(b)
|
||||
l.writeLock.Unlock()
|
||||
return len(buf), err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ package dns
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/types/dnstype"
|
||||
@@ -40,13 +40,13 @@ type Config struct {
|
||||
// Adding an entry to Hosts merely creates the record. If you want
|
||||
// it to resolve, you also need to add appropriate routes to
|
||||
// Routes.
|
||||
Hosts map[dnsname.FQDN][]netip.Addr
|
||||
Hosts map[dnsname.FQDN][]netaddr.IP
|
||||
// OnlyIPv6, if true, uses the IPv6 service IP (for MagicDNS)
|
||||
// instead of the IPv4 version (100.100.100.100).
|
||||
OnlyIPv6 bool
|
||||
}
|
||||
|
||||
func (c *Config) serviceIP() netip.Addr {
|
||||
func (c *Config) serviceIP() netaddr.IP {
|
||||
if c.OnlyIPv6 {
|
||||
return tsaddr.TailscaleServiceIPv6()
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func sameResolverNames(a, b []*dnstype.Resolver) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func sameIPs(a, b []netip.Addr) bool {
|
||||
func sameIPs(a, b []netaddr.IP) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -21,6 +20,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/dns/resolvconffile"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/dnsname"
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
)
|
||||
|
||||
// writeResolvConf writes DNS configuration in resolv.conf format to the given writer.
|
||||
func writeResolvConf(w io.Writer, servers []netip.Addr, domains []dnsname.FQDN) error {
|
||||
func writeResolvConf(w io.Writer, servers []netaddr.IP, domains []dnsname.FQDN) error {
|
||||
c := &resolvconffile.Config{
|
||||
Nameservers: servers,
|
||||
SearchDomains: domains,
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -16,6 +15,7 @@ import (
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
@@ -81,7 +81,7 @@ func testDirect(t *testing.T, fs wholeFileFS) {
|
||||
|
||||
m := directManager{logf: t.Logf, fs: fs}
|
||||
if err := m.SetDNS(OSConfig{
|
||||
Nameservers: []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("8.8.4.4")},
|
||||
Nameservers: []netaddr.IP{netaddr.MustParseIP("8.8.8.8"), netaddr.MustParseIP("8.8.4.4")},
|
||||
SearchDomains: []dnsname.FQDN{"ts.net.", "ts-dns.test."},
|
||||
MatchDomains: []dnsname.FQDN{"ignored."},
|
||||
}); err != nil {
|
||||
@@ -108,7 +108,7 @@ search ts.net ts-dns.test
|
||||
assertBaseState(t)
|
||||
|
||||
// Test that Close cleans up resolv.conf.
|
||||
if err := m.SetDNS(OSConfig{Nameservers: []netip.Addr{netip.MustParseAddr("8.8.8.8")}}); err != nil {
|
||||
if err := m.SetDNS(OSConfig{Nameservers: []netaddr.IP{netaddr.MustParseIP("8.8.8.8")}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := m.Close(); err != nil {
|
||||
@@ -149,22 +149,22 @@ func TestReadResolve(t *testing.T) {
|
||||
}{
|
||||
{in: `nameserver 192.168.0.100`,
|
||||
want: OSConfig{
|
||||
Nameservers: []netip.Addr{
|
||||
netip.MustParseAddr("192.168.0.100"),
|
||||
Nameservers: []netaddr.IP{
|
||||
netaddr.MustParseIP("192.168.0.100"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{in: `nameserver 192.168.0.100 # comment`,
|
||||
want: OSConfig{
|
||||
Nameservers: []netip.Addr{
|
||||
netip.MustParseAddr("192.168.0.100"),
|
||||
Nameservers: []netaddr.IP{
|
||||
netaddr.MustParseIP("192.168.0.100"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{in: `nameserver 192.168.0.100#`,
|
||||
want: OSConfig{
|
||||
Nameservers: []netip.Addr{
|
||||
netip.MustParseAddr("192.168.0.100"),
|
||||
Nameservers: []netaddr.IP{
|
||||
netaddr.MustParseIP("192.168.0.100"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/packet"
|
||||
@@ -67,7 +67,7 @@ const reconfigTimeout = time.Second
|
||||
|
||||
type response struct {
|
||||
pkt []byte
|
||||
to netip.AddrPort // response destination (request source)
|
||||
to netaddr.IPPort // response destination (request source)
|
||||
}
|
||||
|
||||
// Manager manages system DNS settings.
|
||||
@@ -175,7 +175,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
|
||||
// through quad-100.
|
||||
rcfg.Routes = routes
|
||||
rcfg.Routes["."] = cfg.DefaultResolvers
|
||||
ocfg.Nameservers = []netip.Addr{cfg.serviceIP()}
|
||||
ocfg.Nameservers = []netaddr.IP{cfg.serviceIP()}
|
||||
return rcfg, ocfg, nil
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
|
||||
// or routes + MagicDNS, or just MagicDNS, or on an OS that cannot
|
||||
// split-DNS. Install a split config pointing at quad-100.
|
||||
rcfg.Routes = routes
|
||||
ocfg.Nameservers = []netip.Addr{cfg.serviceIP()}
|
||||
ocfg.Nameservers = []netaddr.IP{cfg.serviceIP()}
|
||||
|
||||
// If the OS can't do native split-dns, read out the underlying
|
||||
// resolver config and blend it into our config.
|
||||
@@ -239,10 +239,10 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
|
||||
// toIPsOnly returns only the IP portion of dnstype.Resolver.
|
||||
// Only safe to use if the resolvers slice has been cleared of
|
||||
// DoH or custom-port entries with something like hasDefaultIPResolversOnly.
|
||||
func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netip.Addr) {
|
||||
func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netaddr.IP) {
|
||||
for _, r := range resolvers {
|
||||
if ipp, ok := r.IPPort(); ok && ipp.Port() == 53 {
|
||||
ret = append(ret, ipp.Addr())
|
||||
ret = append(ret, ipp.IP())
|
||||
}
|
||||
}
|
||||
return ret
|
||||
@@ -252,7 +252,7 @@ func toIPsOnly(resolvers []*dnstype.Resolver) (ret []netip.Addr) {
|
||||
// called with a DNS request payload.
|
||||
//
|
||||
// TODO(tom): Rip out once all platforms use netstack.
|
||||
func (m *Manager) EnqueuePacket(bs []byte, proto ipproto.Proto, from, to netip.AddrPort) error {
|
||||
func (m *Manager) EnqueuePacket(bs []byte, proto ipproto.Proto, from, to netaddr.IPPort) error {
|
||||
if to.Port() != 53 || proto != ipproto.UDP {
|
||||
return nil
|
||||
}
|
||||
@@ -299,11 +299,11 @@ func (m *Manager) NextPacket() ([]byte, error) {
|
||||
|
||||
var buf []byte
|
||||
switch {
|
||||
case resp.to.Addr().Is4():
|
||||
case resp.to.IP().Is4():
|
||||
h := packet.UDP4Header{
|
||||
IP4Header: packet.IP4Header{
|
||||
Src: magicDNSIP,
|
||||
Dst: resp.to.Addr(),
|
||||
Dst: resp.to.IP(),
|
||||
},
|
||||
SrcPort: 53,
|
||||
DstPort: resp.to.Port(),
|
||||
@@ -312,11 +312,11 @@ func (m *Manager) NextPacket() ([]byte, error) {
|
||||
buf = make([]byte, offset+hlen+len(resp.pkt))
|
||||
copy(buf[offset+hlen:], resp.pkt)
|
||||
h.Marshal(buf[offset:])
|
||||
case resp.to.Addr().Is6():
|
||||
case resp.to.IP().Is6():
|
||||
h := packet.UDP6Header{
|
||||
IP6Header: packet.IP6Header{
|
||||
Src: magicDNSIPv6,
|
||||
Dst: resp.to.Addr(),
|
||||
Dst: resp.to.IP(),
|
||||
},
|
||||
SrcPort: 53,
|
||||
DstPort: resp.to.Port(),
|
||||
@@ -334,7 +334,7 @@ func (m *Manager) NextPacket() ([]byte, error) {
|
||||
// Query executes a DNS query recieved from the given address. The query is
|
||||
// provided in bs as a wire-encoded DNS query without any transport header.
|
||||
// This method is called for requests arriving over UDP and TCP.
|
||||
func (m *Manager) Query(ctx context.Context, bs []byte, from netip.AddrPort) ([]byte, error) {
|
||||
func (m *Manager) Query(ctx context.Context, bs []byte, from netaddr.IPPort) ([]byte, error) {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
return nil, net.ErrClosed
|
||||
@@ -368,10 +368,10 @@ type dnsTCPSession struct {
|
||||
m *Manager
|
||||
|
||||
conn net.Conn
|
||||
srcAddr netip.AddrPort
|
||||
srcAddr netaddr.IPPort
|
||||
|
||||
readClosing chan struct{}
|
||||
responses chan []byte // DNS replies pending writing
|
||||
readClosing chan struct{}
|
||||
responses chan []byte // DNS replies pending writing
|
||||
|
||||
ctx context.Context
|
||||
closeCtx context.CancelFunc
|
||||
@@ -455,13 +455,13 @@ func (s *dnsTCPSession) handleReads() {
|
||||
|
||||
// HandleTCPConn implements magicDNS over TCP, taking a connection and
|
||||
// servicing DNS requests sent down it.
|
||||
func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netip.AddrPort) {
|
||||
func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netaddr.IPPort) {
|
||||
s := dnsTCPSession{
|
||||
m: m,
|
||||
conn: conn,
|
||||
srcAddr: srcAddr,
|
||||
responses: make(chan []byte),
|
||||
readClosing: make(chan struct{}),
|
||||
m: m,
|
||||
conn: conn,
|
||||
srcAddr: srcAddr,
|
||||
responses: make(chan []byte),
|
||||
readClosing: make(chan struct{}),
|
||||
}
|
||||
s.ctx, s.closeCtx = context.WithCancel(m.ctx)
|
||||
go s.handleReads()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user