mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-21 14:11:56 +00:00
WIP snapshot
Next up: view support for maps, etc.
This commit is contained in:
parent
b14db5d943
commit
c7b7546587
216
cmd/viewer/viewer.go
Normal file
216
cmd/viewer/viewer.go
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Viewer is a tool to automate the creation of a view type.
|
||||||
|
//
|
||||||
|
// The generated View method provides a readonly view of the struct.
|
||||||
|
//
|
||||||
|
// This tool makes lots of implicit assumptions about the types you feed it.
|
||||||
|
// In particular, it can only write relatively "shallow" View methods.
|
||||||
|
// That is, if a type contains another named struct type, viewer assumes that
|
||||||
|
// named type will also have a View method.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"tailscale.com/util/codegen"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
flagTypes = flag.String("type", "", "comma-separated list of types; required")
|
||||||
|
flagOutput = flag.String("output", "", "output file; required")
|
||||||
|
flagBuildTags = flag.String("tags", "", "compiler build tags to apply")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("viewer: ")
|
||||||
|
flag.Parse()
|
||||||
|
if len(*flagTypes) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
typeNames := strings.Split(*flagTypes, ",")
|
||||||
|
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedName,
|
||||||
|
Tests: false,
|
||||||
|
}
|
||||||
|
if *flagBuildTags != "" {
|
||||||
|
cfg.BuildFlags = []string{"-tags=" + *flagBuildTags}
|
||||||
|
}
|
||||||
|
pkgs, err := packages.Load(cfg, ".")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(pkgs) != 1 {
|
||||||
|
log.Fatalf("wrong number of packages: %d", len(pkgs))
|
||||||
|
}
|
||||||
|
pkg := pkgs[0]
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
imports := make(map[string]struct{})
|
||||||
|
namedTypes := codegen.NamedTypes(pkg)
|
||||||
|
for _, typeName := range typeNames {
|
||||||
|
typ, ok := namedTypes[typeName]
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("could not find type %s", typeName)
|
||||||
|
}
|
||||||
|
gen(buf, imports, typ, pkg.Types)
|
||||||
|
}
|
||||||
|
|
||||||
|
contents := new(bytes.Buffer)
|
||||||
|
fmt.Fprintf(contents, header, *flagTypes, pkg.Name)
|
||||||
|
fmt.Fprintf(contents, "import (\n")
|
||||||
|
for s := range imports {
|
||||||
|
fmt.Fprintf(contents, "\t%q\n", s)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(contents, ")\n\n")
|
||||||
|
contents.Write(buf.Bytes())
|
||||||
|
|
||||||
|
output := *flagOutput
|
||||||
|
if output == "" {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
if err := codegen.WriteFormatted(contents.Bytes(), output); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = `// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Code generated by the following command; DO NOT EDIT.
|
||||||
|
// tailscale.com/cmd/viewer -type %s
|
||||||
|
|
||||||
|
package %s
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisPkg *types.Package) {
|
||||||
|
pkgQual := func(pkg *types.Package) string {
|
||||||
|
if thisPkg == pkg {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
imports[pkg.Path()] = struct{}{}
|
||||||
|
return pkg.Name()
|
||||||
|
}
|
||||||
|
importedName := func(t types.Type) string {
|
||||||
|
return types.TypeString(t, pkgQual)
|
||||||
|
}
|
||||||
|
|
||||||
|
t, ok := typ.Underlying().(*types.Struct)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := typ.Obj().Name()
|
||||||
|
viewName := name + "View"
|
||||||
|
fmt.Fprintf(buf, "// View makes a readonly view of %s.\n", name)
|
||||||
|
fmt.Fprintf(buf, "func (src *%s) View() %s {\n", name, viewName)
|
||||||
|
fmt.Fprintf(buf, " return %s{src}\n", viewName)
|
||||||
|
fmt.Fprintf(buf, "}\n")
|
||||||
|
|
||||||
|
fmt.Fprintf(buf, "// %s is a readonly view of %s.\n", viewName, name)
|
||||||
|
fmt.Fprintf(buf, "type %s struct{ ж *%s }\n", viewName, name)
|
||||||
|
fmt.Fprintf(buf, "func (v %s) Valid() bool { return v.ж != nil }\n", viewName)
|
||||||
|
|
||||||
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
|
fname := t.Field(i).Name()
|
||||||
|
ft := t.Field(i).Type()
|
||||||
|
if !codegen.ContainsPointers(ft) {
|
||||||
|
fmt.Fprintf(buf, "func (v %s) %s() %s { return v.ж.%s }\n", viewName, fname, importedName(ft), fname)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if named, _ := ft.(*types.Named); named != nil && !hasBasicUnderlying(ft) {
|
||||||
|
genViewCall(buf, viewName, fname, importedName(ft))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch ft := ft.Underlying().(type) {
|
||||||
|
case *types.Slice:
|
||||||
|
if !codegen.ContainsPointers(ft.Elem()) {
|
||||||
|
// OK to return the slice as-is, since they can't modify the contents.
|
||||||
|
fmt.Fprintf(buf, "func (v %s) %s() %s { return v.ж.%s }\n", viewName, fname, importedName(ft), fname)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n := importedName(ft.Elem())
|
||||||
|
if ptrTyp, isPtr := ft.Elem().(*types.Pointer); isPtr {
|
||||||
|
n = importedName(ptrTyp.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate slice view.
|
||||||
|
styp := fmt.Sprintf("_%s_%s", viewName, fname)
|
||||||
|
fmt.Fprintf(buf, "type %s []%s\n", styp, importedName(ft.Elem()))
|
||||||
|
fmt.Fprintf(buf, "func (s %s) Len() int { return len(s) }\n", styp)
|
||||||
|
fmt.Fprintf(buf, "func (s %s) At(i int) %sView { return s[i].View() }\n", styp, n)
|
||||||
|
|
||||||
|
fmt.Fprintf(buf, "func (v %s) %s() interface { Len() int; At(int) %sView } {\n", viewName, fname, n)
|
||||||
|
fmt.Fprintf(buf, " return %s(v.ж.%s)\n", styp, fname)
|
||||||
|
fmt.Fprintf(buf, "}\n")
|
||||||
|
case *types.Pointer:
|
||||||
|
if named, _ := ft.Elem().(*types.Named); named != nil && codegen.ContainsPointers(ft.Elem()) {
|
||||||
|
genViewCall(buf, viewName, fname, importedName(named))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if codegen.ContainsPointers(ft.Elem()) {
|
||||||
|
log.Fatalf("unhandled: pointers in pointers (%v)", ft)
|
||||||
|
}
|
||||||
|
n := importedName(ft.Elem())
|
||||||
|
fmt.Fprintf(buf, "func (v %s) %s() *%s {\n", viewName, fname, n)
|
||||||
|
fmt.Fprintf(buf, " ptr := v.ж.%s\n", fname)
|
||||||
|
fmt.Fprintf(buf, " if ptr == nil {\n")
|
||||||
|
fmt.Fprintf(buf, " return nil\n")
|
||||||
|
fmt.Fprintf(buf, " }\n")
|
||||||
|
fmt.Fprintf(buf, " cp := *ptr\n")
|
||||||
|
fmt.Fprintf(buf, " return &cp\n")
|
||||||
|
fmt.Fprintf(buf, "}\n")
|
||||||
|
case *types.Map:
|
||||||
|
// TODO: Generate map view, like the slice view.
|
||||||
|
// We need:
|
||||||
|
// * Len() int
|
||||||
|
// * Load(k) v
|
||||||
|
// * LoadOK(k) (v, bool)
|
||||||
|
// * Range(func(k, v) bool)
|
||||||
|
//
|
||||||
|
// Note that we need to handle a variety of elem types:
|
||||||
|
// basic types (float64), types with a View method,
|
||||||
|
// slices of the foregoing.
|
||||||
|
//
|
||||||
|
// This may require recursion to handle completely,
|
||||||
|
// or we can follow cloner's lead and just manually
|
||||||
|
// inline one level deep the code generation
|
||||||
|
// that we happen to need right now.
|
||||||
|
// (If we figure out recursion in this context,
|
||||||
|
// we might want to backport to cloner, too.)
|
||||||
|
log.Printf("TODO: Handle %s (%s)", name, ft)
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(buf, `panic("TODO: %s (%T)")`, fname, ft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Write(codegen.AssertStructUnchanged(t, thisPkg, name, "View", imports))
|
||||||
|
}
|
||||||
|
|
||||||
|
func genViewCall(buf *bytes.Buffer, viewName, fieldName, importedName string) {
|
||||||
|
fmt.Fprintf(buf, "func (v %s) %s() %sView { return v.ж.%s.View() }\n", viewName, fieldName, importedName, fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasBasicUnderlying(typ types.Type) bool {
|
||||||
|
switch typ.Underlying().(type) {
|
||||||
|
case *types.Slice, *types.Map:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -285,7 +285,7 @@ func (c *Auto) authRoutine() {
|
|||||||
// don't send status updates for context errors,
|
// don't send status updates for context errors,
|
||||||
// since context cancelation is always on purpose.
|
// since context cancelation is always on purpose.
|
||||||
if ctx.Err() == nil {
|
if ctx.Err() == nil {
|
||||||
c.sendStatus("authRoutine-report", err, "", nil)
|
c.sendStatus("authRoutine-report", err, "", netmap.NetworkMapView{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ func (c *Auto) authRoutine() {
|
|||||||
c.synced = false
|
c.synced = false
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
c.sendStatus("authRoutine-wantout", nil, "", nil)
|
c.sendStatus("authRoutine-wantout", nil, "", netmap.NetworkMapView{})
|
||||||
bo.BackOff(ctx, nil)
|
bo.BackOff(ctx, nil)
|
||||||
} else { // ie. goal.wantLoggedIn
|
} else { // ie. goal.wantLoggedIn
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
@ -355,7 +355,7 @@ func (c *Auto) authRoutine() {
|
|||||||
c.synced = false
|
c.synced = false
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
c.sendStatus("authRoutine-url", err, url, nil)
|
c.sendStatus("authRoutine-url", err, url, netmap.NetworkMapView{})
|
||||||
bo.BackOff(ctx, err)
|
bo.BackOff(ctx, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -367,7 +367,7 @@ func (c *Auto) authRoutine() {
|
|||||||
c.state = StateAuthenticated
|
c.state = StateAuthenticated
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
c.sendStatus("authRoutine-success", nil, "", nil)
|
c.sendStatus("authRoutine-success", nil, "", netmap.NetworkMapView{})
|
||||||
c.cancelMapSafely()
|
c.cancelMapSafely()
|
||||||
bo.BackOff(ctx, nil)
|
bo.BackOff(ctx, nil)
|
||||||
}
|
}
|
||||||
@ -435,7 +435,7 @@ func (c *Auto) mapRoutine() {
|
|||||||
// don't send status updates for context errors,
|
// don't send status updates for context errors,
|
||||||
// since context cancelation is always on purpose.
|
// since context cancelation is always on purpose.
|
||||||
if ctx.Err() == nil {
|
if ctx.Err() == nil {
|
||||||
c.sendStatus("mapRoutine1", err, "", nil)
|
c.sendStatus("mapRoutine1", err, "", netmap.NetworkMapView{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ func (c *Auto) mapRoutine() {
|
|||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
health.SetInPollNetMap(false)
|
health.SetInPollNetMap(false)
|
||||||
|
|
||||||
err := c.direct.PollNetMap(ctx, -1, func(nm *netmap.NetworkMap) {
|
err := c.direct.PollNetMap(ctx, -1, func(nm netmap.NetworkMapView) {
|
||||||
health.SetInPollNetMap(true)
|
health.SetInPollNetMap(true)
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
|
||||||
@ -482,7 +482,7 @@ func (c *Auto) mapRoutine() {
|
|||||||
if c.loggedIn {
|
if c.loggedIn {
|
||||||
c.state = StateSynchronized
|
c.state = StateSynchronized
|
||||||
}
|
}
|
||||||
exp := nm.Expiry
|
exp := nm.Expiry()
|
||||||
c.expiry = &exp
|
c.expiry = &exp
|
||||||
stillAuthed := c.loggedIn
|
stillAuthed := c.loggedIn
|
||||||
state := c.state
|
state := c.state
|
||||||
@ -563,7 +563,7 @@ func (c *Auto) SetNetInfo(ni *tailcfg.NetInfo) {
|
|||||||
c.sendNewMapRequest()
|
c.sendNewMapRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Auto) sendStatus(who string, err error, url string, nm *netmap.NetworkMap) {
|
func (c *Auto) sendStatus(who string, err error, url string, nm netmap.NetworkMapView) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
state := c.state
|
state := c.state
|
||||||
loggedIn := c.loggedIn
|
loggedIn := c.loggedIn
|
||||||
@ -583,13 +583,13 @@ func (c *Auto) sendStatus(who string, err error, url string, nm *netmap.NetworkM
|
|||||||
if state == StateNotAuthenticated {
|
if state == StateNotAuthenticated {
|
||||||
logoutFin = new(empty.Message)
|
logoutFin = new(empty.Message)
|
||||||
}
|
}
|
||||||
if nm != nil && loggedIn && synced {
|
if nm.Valid() && loggedIn && synced {
|
||||||
pp := c.direct.GetPersist()
|
pp := c.direct.GetPersist()
|
||||||
p = &pp
|
p = &pp
|
||||||
} else {
|
} else {
|
||||||
// don't send netmap status, as it's misleading when we're
|
// don't send netmap status, as it's misleading when we're
|
||||||
// not logged in.
|
// not logged in.
|
||||||
nm = nil
|
nm = netmap.NetworkMapView{}
|
||||||
}
|
}
|
||||||
new := Status{
|
new := Status{
|
||||||
LoginFinished: loginFin,
|
LoginFinished: loginFin,
|
||||||
|
@ -535,7 +535,7 @@ func inTest() bool { return flag.Lookup("test.v") != nil }
|
|||||||
//
|
//
|
||||||
// maxPolls is how many network maps to download; common values are 1
|
// maxPolls is how many network maps to download; common values are 1
|
||||||
// or -1 (to keep a long-poll query open to the server).
|
// or -1 (to keep a long-poll query open to the server).
|
||||||
func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error {
|
func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(netmap.NetworkMapView)) error {
|
||||||
return c.sendMapRequest(ctx, maxPolls, cb)
|
return c.sendMapRequest(ctx, maxPolls, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,7 +552,7 @@ func (c *Direct) SendLiteMapUpdate(ctx context.Context) error {
|
|||||||
const pollTimeout = 120 * time.Second
|
const pollTimeout = 120 * time.Second
|
||||||
|
|
||||||
// cb nil means to omit peers.
|
// cb nil means to omit peers.
|
||||||
func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error {
|
func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(netmap.NetworkMapView)) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
persist := c.persist
|
persist := c.persist
|
||||||
serverURL := c.serverURL
|
serverURL := c.serverURL
|
||||||
@ -822,7 +822,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
|
|||||||
c.expiry = &nm.Expiry
|
c.expiry = &nm.Expiry
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
cb(nm)
|
cb(nm.View())
|
||||||
}
|
}
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
|
@ -139,7 +139,7 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
|
|||||||
}
|
}
|
||||||
|
|
||||||
ms.addUserProfile(nm.User)
|
ms.addUserProfile(nm.User)
|
||||||
magicDNSSuffix := nm.MagicDNSSuffix()
|
magicDNSSuffix := nm.View().MagicDNSSuffix()
|
||||||
if nm.SelfNode != nil {
|
if nm.SelfNode != nil {
|
||||||
nm.SelfNode.InitDisplayNames(magicDNSSuffix)
|
nm.SelfNode.InitDisplayNames(magicDNSSuffix)
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ type Status struct {
|
|||||||
LogoutFinished *empty.Message // nonempty when logout finishes
|
LogoutFinished *empty.Message // nonempty when logout finishes
|
||||||
Err string
|
Err string
|
||||||
URL string // interactive URL to visit to finish logging in
|
URL string // interactive URL to visit to finish logging in
|
||||||
NetMap *netmap.NetworkMap // server-pushed configuration
|
NetMap netmap.NetworkMapView // server-pushed configuration
|
||||||
|
|
||||||
// The internal state should not be exposed outside this
|
// The internal state should not be exposed outside this
|
||||||
// package, but we have some automated tests elsewhere that need to
|
// package, but we have some automated tests elsewhere that need to
|
||||||
|
@ -115,8 +115,7 @@ type LocalBackend struct {
|
|||||||
capFileSharing bool // whether netMap contains the file sharing capability
|
capFileSharing bool // whether netMap contains the file sharing capability
|
||||||
// hostinfo is mutated in-place while mu is held.
|
// hostinfo is mutated in-place while mu is held.
|
||||||
hostinfo *tailcfg.Hostinfo
|
hostinfo *tailcfg.Hostinfo
|
||||||
// netMap is not mutated in-place once set.
|
netMap netmap.NetworkMapView
|
||||||
netMap *netmap.NetworkMap
|
|
||||||
nodeByAddr map[netaddr.IP]*tailcfg.Node
|
nodeByAddr map[netaddr.IP]*tailcfg.Node
|
||||||
activeLogin string // last logged LoginName from netMap
|
activeLogin string // last logged LoginName from netMap
|
||||||
engineStatus ipn.EngineStatus
|
engineStatus ipn.EngineStatus
|
||||||
@ -224,7 +223,7 @@ func (b *LocalBackend) maybePauseControlClientLocked() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
networkUp := b.prevIfState.AnyInterfaceUp()
|
networkUp := b.prevIfState.AnyInterfaceUp()
|
||||||
b.cc.SetPaused((b.state == ipn.Stopped && b.netMap != nil) || !networkUp)
|
b.cc.SetPaused((b.state == ipn.Stopped && b.netMap.Valid()) || !networkUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkChange is our link monitor callback, called whenever the network changes.
|
// linkChange is our link monitor callback, called whenever the network changes.
|
||||||
@ -253,8 +252,8 @@ func (b *LocalBackend) linkChange(major bool, ifst *interfaces.State) {
|
|||||||
// need updating to tweak default routes.
|
// need updating to tweak default routes.
|
||||||
b.updateFilter(b.netMap, b.prefs)
|
b.updateFilter(b.netMap, b.prefs)
|
||||||
|
|
||||||
if peerAPIListenAsync && b.netMap != nil && b.state == ipn.Running {
|
if peerAPIListenAsync && b.netMap.Valid() && b.state == ipn.Running {
|
||||||
want := len(b.netMap.Addresses)
|
want := len(b.netMap.Addresses())
|
||||||
if len(b.peerAPIListeners) < want {
|
if len(b.peerAPIListeners) < want {
|
||||||
b.logf("linkChange: peerAPIListeners too low; trying again")
|
b.logf("linkChange: peerAPIListeners too low; trying again")
|
||||||
go b.initPeerAPIListener()
|
go b.initPeerAPIListener()
|
||||||
@ -343,14 +342,14 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|||||||
s.Health = append(s.Health, err.Error())
|
s.Health = append(s.Health, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if b.netMap != nil {
|
if b.netMap.Valid() {
|
||||||
s.MagicDNSSuffix = b.netMap.MagicDNSSuffix()
|
s.MagicDNSSuffix = b.netMap.MagicDNSSuffix()
|
||||||
s.CertDomains = append([]string(nil), b.netMap.DNS.CertDomains...)
|
s.CertDomains = append([]string(nil), b.netMap.DNS().CertDomains()...)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
sb.MutateSelfStatus(func(ss *ipnstate.PeerStatus) {
|
sb.MutateSelfStatus(func(ss *ipnstate.PeerStatus) {
|
||||||
if b.netMap != nil && b.netMap.SelfNode != nil {
|
if b.netMap.Valid() && b.netMap.SelfNode != nil {
|
||||||
ss.ID = b.netMap.SelfNode.StableID
|
ss.ID = b.netMap.SelfNode().StableID()
|
||||||
}
|
}
|
||||||
for _, pln := range b.peerAPIListeners {
|
for _, pln := range b.peerAPIListeners {
|
||||||
ss.PeerAPIURL = append(ss.PeerAPIURL, pln.urlStr)
|
ss.PeerAPIURL = append(ss.PeerAPIURL, pln.urlStr)
|
||||||
@ -365,20 +364,21 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
||||||
if b.netMap == nil {
|
if !b.netMap.Valid() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for id, up := range b.netMap.UserProfiles {
|
for _, id := range b.netMap.UserIDs() {
|
||||||
|
up := b.netMap.UserProfile(id)
|
||||||
sb.AddUser(id, up)
|
sb.AddUser(id, up)
|
||||||
}
|
}
|
||||||
for _, p := range b.netMap.Peers {
|
for _, p := range b.netMap.Peers() {
|
||||||
var lastSeen time.Time
|
var lastSeen time.Time
|
||||||
if p.LastSeen != nil {
|
if p.LastSeen() != nil {
|
||||||
lastSeen = *p.LastSeen
|
lastSeen = *p.LastSeen()
|
||||||
}
|
}
|
||||||
var tailAddr4 string
|
var tailAddr4 string
|
||||||
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
|
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses()))
|
||||||
for _, addr := range p.Addresses {
|
for _, addr := range p.Addresses() {
|
||||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
|
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
|
||||||
if addr.IP().Is4() && tailAddr4 == "" {
|
if addr.IP().Is4() && tailAddr4 == "" {
|
||||||
// The peer struct previously only allowed a single
|
// The peer struct previously only allowed a single
|
||||||
@ -389,20 +389,20 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
|||||||
tailscaleIPs = append(tailscaleIPs, addr.IP())
|
tailscaleIPs = append(tailscaleIPs, addr.IP())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.AddPeer(key.Public(p.Key), &ipnstate.PeerStatus{
|
sb.AddPeer(key.Public(p.Key()), &ipnstate.PeerStatus{
|
||||||
InNetworkMap: true,
|
InNetworkMap: true,
|
||||||
ID: p.StableID,
|
ID: p.StableID(),
|
||||||
UserID: p.User,
|
UserID: p.User(),
|
||||||
TailAddrDeprecated: tailAddr4,
|
TailAddrDeprecated: tailAddr4,
|
||||||
TailscaleIPs: tailscaleIPs,
|
TailscaleIPs: tailscaleIPs,
|
||||||
HostName: p.Hostinfo.Hostname,
|
HostName: p.Hostinfo().Hostname(),
|
||||||
DNSName: p.Name,
|
DNSName: p.Name(),
|
||||||
OS: p.Hostinfo.OS,
|
OS: p.Hostinfo().OS(),
|
||||||
KeepAlive: p.KeepAlive,
|
KeepAlive: p.KeepAlive(),
|
||||||
Created: p.Created,
|
Created: p.Created(),
|
||||||
LastSeen: lastSeen,
|
LastSeen: lastSeen,
|
||||||
ShareeNode: p.Hostinfo.ShareeNode,
|
ShareeNode: p.Hostinfo().ShareeNode(),
|
||||||
ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID,
|
ExitNode: p.StableID() != "" && p.StableID() == b.prefs.ExitNodeID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|||||||
// Since we're logged out now, our netmap cache is invalid.
|
// Since we're logged out now, our netmap cache is invalid.
|
||||||
// Since st.NetMap==nil means "netmap is unchanged", there is
|
// Since st.NetMap==nil means "netmap is unchanged", there is
|
||||||
// no other way to represent this change.
|
// no other way to represent this change.
|
||||||
b.setNetMapLocked(nil)
|
b.setNetMapLocked(netmap.NetworkMapView{})
|
||||||
}
|
}
|
||||||
|
|
||||||
prefs := b.prefs
|
prefs := b.prefs
|
||||||
@ -501,7 +501,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|||||||
b.prefs.Persist = st.Persist.Clone()
|
b.prefs.Persist = st.Persist.Clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if st.NetMap != nil {
|
if st.NetMap.Valid() {
|
||||||
if b.findExitNodeIDLocked(st.NetMap) {
|
if b.findExitNodeIDLocked(st.NetMap) {
|
||||||
prefsChanged = true
|
prefsChanged = true
|
||||||
}
|
}
|
||||||
@ -537,8 +537,8 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|||||||
}
|
}
|
||||||
b.send(ipn.Notify{Prefs: prefs})
|
b.send(ipn.Notify{Prefs: prefs})
|
||||||
}
|
}
|
||||||
if st.NetMap != nil {
|
if st.NetMap.Valid() {
|
||||||
if netMap != nil {
|
if netMap.Valid() {
|
||||||
diff := st.NetMap.ConciseDiffFrom(netMap)
|
diff := st.NetMap.ConciseDiffFrom(netMap)
|
||||||
if strings.TrimSpace(diff) == "" {
|
if strings.TrimSpace(diff) == "" {
|
||||||
b.logf("[v1] netmap diff: (none)")
|
b.logf("[v1] netmap diff: (none)")
|
||||||
@ -567,7 +567,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
|||||||
|
|
||||||
// findExitNodeIDLocked updates b.prefs to reference an exit node by ID,
|
// findExitNodeIDLocked updates b.prefs to reference an exit node by ID,
|
||||||
// rather than by IP. It returns whether prefs was mutated.
|
// rather than by IP. It returns whether prefs was mutated.
|
||||||
func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged bool) {
|
func (b *LocalBackend) findExitNodeIDLocked(nm netmap.NetworkMapView) (prefsChanged bool) {
|
||||||
// If we have a desired IP on file, try to find the corresponding
|
// If we have a desired IP on file, try to find the corresponding
|
||||||
// node.
|
// node.
|
||||||
if b.prefs.ExitNodeIP.IsZero() {
|
if b.prefs.ExitNodeIP.IsZero() {
|
||||||
@ -580,14 +580,16 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
|
|||||||
prefsChanged = true
|
prefsChanged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, peer := range nm.Peers {
|
peers := nm.Peers()
|
||||||
for _, addr := range peer.Addresses {
|
for i := 0; i < peers.Len(); i++ {
|
||||||
|
peer := peers.At(i)
|
||||||
|
for _, addr := range peer.Addresses() {
|
||||||
if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
|
if !addr.IsSingleIP() || addr.IP() != b.prefs.ExitNodeIP {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Found the node being referenced, upgrade prefs to
|
// Found the node being referenced, upgrade prefs to
|
||||||
// reference it directly for next time.
|
// reference it directly for next time.
|
||||||
b.prefs.ExitNodeID = peer.StableID
|
b.prefs.ExitNodeID = peer.StableID()
|
||||||
b.prefs.ExitNodeIP = netaddr.IP{}
|
b.prefs.ExitNodeIP = netaddr.IP{}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -922,14 +924,14 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|||||||
|
|
||||||
// updateFilter updates the packet filter in wgengine based on the
|
// updateFilter updates the packet filter in wgengine based on the
|
||||||
// given netMap and user preferences.
|
// given netMap and user preferences.
|
||||||
func (b *LocalBackend) updateFilter(netMap *netmap.NetworkMap, prefs *ipn.Prefs) {
|
func (b *LocalBackend) updateFilter(netMap netmap.NetworkMapView, prefs *ipn.Prefs) {
|
||||||
// NOTE(danderson): keep change detection as the first thing in
|
// NOTE(danderson): keep change detection as the first thing in
|
||||||
// this function. Don't try to optimize by returning early, more
|
// this function. Don't try to optimize by returning early, more
|
||||||
// likely than not you'll just end up breaking the change
|
// likely than not you'll just end up breaking the change
|
||||||
// detection and end up with the wrong filter installed. This is
|
// detection and end up with the wrong filter installed. This is
|
||||||
// quite hard to debug, so save yourself the trouble.
|
// quite hard to debug, so save yourself the trouble.
|
||||||
var (
|
var (
|
||||||
haveNetmap = netMap != nil
|
haveNetmap = netMap.Valid()
|
||||||
addrs []netaddr.IPPrefix
|
addrs []netaddr.IPPrefix
|
||||||
packetFilter []filter.Match
|
packetFilter []filter.Match
|
||||||
localNetsB netaddr.IPSetBuilder
|
localNetsB netaddr.IPSetBuilder
|
||||||
@ -941,7 +943,7 @@ func (b *LocalBackend) updateFilter(netMap *netmap.NetworkMap, prefs *ipn.Prefs)
|
|||||||
logNetsB.AddPrefix(tsaddr.TailscaleULARange())
|
logNetsB.AddPrefix(tsaddr.TailscaleULARange())
|
||||||
logNetsB.RemovePrefix(tsaddr.ChromeOSVMRange())
|
logNetsB.RemovePrefix(tsaddr.ChromeOSVMRange())
|
||||||
if haveNetmap {
|
if haveNetmap {
|
||||||
addrs = netMap.Addresses
|
addrs = netMap.Addresses()
|
||||||
for _, p := range addrs {
|
for _, p := range addrs {
|
||||||
localNetsB.AddPrefix(p)
|
localNetsB.AddPrefix(p)
|
||||||
}
|
}
|
||||||
@ -2533,10 +2535,10 @@ func hasCapability(nm *netmap.NetworkMap, cap string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
func (b *LocalBackend) setNetMapLocked(nm netmap.NetworkMapView) {
|
||||||
var login string
|
var login string
|
||||||
if nm != nil {
|
if nm.Valid() {
|
||||||
login = nm.UserProfiles[nm.User].LoginName
|
login = nm.UserProfile(nm.User()).LoginName
|
||||||
if login == "" {
|
if login == "" {
|
||||||
login = "<missing-profile>"
|
login = "<missing-profile>"
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package tailcfg
|
package tailcfg
|
||||||
|
|
||||||
//go:generate go run tailscale.com/cmd/cloner --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPRegion,DERPMap,DERPNode --clonefunc=true --output=tailcfg_clone.go
|
//go:generate go run tailscale.com/cmd/cloner --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,DERPRegion,DERPMap,DERPNode --clonefunc=true --output=tailcfg_clone.go
|
||||||
|
//go:generate go run tailscale.com/cmd/viewer --type=Node,Hostinfo,DNSConfig,NetInfo,DERPMap --output=tailcfg_view.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
239
tailcfg/tailcfg_view.go
Normal file
239
tailcfg/tailcfg_view.go
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Code generated by the following command; DO NOT EDIT.
|
||||||
|
// tailscale.com/cmd/viewer -type Node,Hostinfo,DNSConfig,NetInfo,DERPMap
|
||||||
|
|
||||||
|
package tailcfg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/types/dnstype"
|
||||||
|
"tailscale.com/types/key"
|
||||||
|
"tailscale.com/types/opt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// View makes a readonly view of Node.
|
||||||
|
func (src *Node) View() NodeView {
|
||||||
|
return NodeView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeView is a readonly view of Node.
|
||||||
|
type NodeView struct{ ж *Node }
|
||||||
|
|
||||||
|
func (v NodeView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v NodeView) ID() NodeID { return v.ж.ID }
|
||||||
|
func (v NodeView) StableID() StableNodeID { return v.ж.StableID }
|
||||||
|
func (v NodeView) Name() string { return v.ж.Name }
|
||||||
|
func (v NodeView) User() UserID { return v.ж.User }
|
||||||
|
func (v NodeView) Sharer() UserID { return v.ж.Sharer }
|
||||||
|
func (v NodeView) Key() NodeKey { return v.ж.Key }
|
||||||
|
func (v NodeView) KeyExpiry() time.Time { return v.ж.KeyExpiry }
|
||||||
|
func (v NodeView) Machine() key.MachinePublic { return v.ж.Machine }
|
||||||
|
func (v NodeView) DiscoKey() DiscoKey { return v.ж.DiscoKey }
|
||||||
|
func (v NodeView) Addresses() []netaddr.IPPrefix { return v.ж.Addresses }
|
||||||
|
func (v NodeView) AllowedIPs() []netaddr.IPPrefix { return v.ж.AllowedIPs }
|
||||||
|
func (v NodeView) Endpoints() []string { return v.ж.Endpoints }
|
||||||
|
func (v NodeView) DERP() string { return v.ж.DERP }
|
||||||
|
func (v NodeView) Hostinfo() HostinfoView { return v.ж.Hostinfo.View() }
|
||||||
|
func (v NodeView) Created() time.Time { return v.ж.Created }
|
||||||
|
func (v NodeView) PrimaryRoutes() []netaddr.IPPrefix { return v.ж.PrimaryRoutes }
|
||||||
|
func (v NodeView) LastSeen() *time.Time {
|
||||||
|
ptr := v.ж.LastSeen
|
||||||
|
if ptr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cp := *ptr
|
||||||
|
return &cp
|
||||||
|
}
|
||||||
|
func (v NodeView) Online() *bool {
|
||||||
|
ptr := v.ж.Online
|
||||||
|
if ptr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cp := *ptr
|
||||||
|
return &cp
|
||||||
|
}
|
||||||
|
func (v NodeView) KeepAlive() bool { return v.ж.KeepAlive }
|
||||||
|
func (v NodeView) MachineAuthorized() bool { return v.ж.MachineAuthorized }
|
||||||
|
func (v NodeView) Capabilities() []string { return v.ж.Capabilities }
|
||||||
|
func (v NodeView) ComputedName() string { return v.ж.ComputedName }
|
||||||
|
func (v NodeView) computedHostIfDifferent() string { return v.ж.computedHostIfDifferent }
|
||||||
|
func (v NodeView) ComputedNameWithHost() string { return v.ж.ComputedNameWithHost }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _NodeViewNeedsRegeneration = Node(struct {
|
||||||
|
ID NodeID
|
||||||
|
StableID StableNodeID
|
||||||
|
Name string
|
||||||
|
User UserID
|
||||||
|
Sharer UserID
|
||||||
|
Key NodeKey
|
||||||
|
KeyExpiry time.Time
|
||||||
|
Machine key.MachinePublic
|
||||||
|
DiscoKey DiscoKey
|
||||||
|
Addresses []netaddr.IPPrefix
|
||||||
|
AllowedIPs []netaddr.IPPrefix
|
||||||
|
Endpoints []string
|
||||||
|
DERP string
|
||||||
|
Hostinfo Hostinfo
|
||||||
|
Created time.Time
|
||||||
|
PrimaryRoutes []netaddr.IPPrefix
|
||||||
|
LastSeen *time.Time
|
||||||
|
Online *bool
|
||||||
|
KeepAlive bool
|
||||||
|
MachineAuthorized bool
|
||||||
|
Capabilities []string
|
||||||
|
ComputedName string
|
||||||
|
computedHostIfDifferent string
|
||||||
|
ComputedNameWithHost string
|
||||||
|
}{})
|
||||||
|
|
||||||
|
// View makes a readonly view of Hostinfo.
|
||||||
|
func (src *Hostinfo) View() HostinfoView {
|
||||||
|
return HostinfoView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostinfoView is a readonly view of Hostinfo.
|
||||||
|
type HostinfoView struct{ ж *Hostinfo }
|
||||||
|
|
||||||
|
func (v HostinfoView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v HostinfoView) IPNVersion() string { return v.ж.IPNVersion }
|
||||||
|
func (v HostinfoView) FrontendLogID() string { return v.ж.FrontendLogID }
|
||||||
|
func (v HostinfoView) BackendLogID() string { return v.ж.BackendLogID }
|
||||||
|
func (v HostinfoView) OS() string { return v.ж.OS }
|
||||||
|
func (v HostinfoView) OSVersion() string { return v.ж.OSVersion }
|
||||||
|
func (v HostinfoView) Package() string { return v.ж.Package }
|
||||||
|
func (v HostinfoView) DeviceModel() string { return v.ж.DeviceModel }
|
||||||
|
func (v HostinfoView) Hostname() string { return v.ж.Hostname }
|
||||||
|
func (v HostinfoView) ShieldsUp() bool { return v.ж.ShieldsUp }
|
||||||
|
func (v HostinfoView) ShareeNode() bool { return v.ж.ShareeNode }
|
||||||
|
func (v HostinfoView) GoArch() string { return v.ж.GoArch }
|
||||||
|
func (v HostinfoView) RoutableIPs() []netaddr.IPPrefix { return v.ж.RoutableIPs }
|
||||||
|
func (v HostinfoView) RequestTags() []string { return v.ж.RequestTags }
|
||||||
|
func (v HostinfoView) Services() []Service { return v.ж.Services }
|
||||||
|
func (v HostinfoView) NetInfo() NetInfoView { return v.ж.NetInfo.View() }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
|
||||||
|
IPNVersion string
|
||||||
|
FrontendLogID string
|
||||||
|
BackendLogID string
|
||||||
|
OS string
|
||||||
|
OSVersion string
|
||||||
|
Package string
|
||||||
|
DeviceModel string
|
||||||
|
Hostname string
|
||||||
|
ShieldsUp bool
|
||||||
|
ShareeNode bool
|
||||||
|
GoArch string
|
||||||
|
RoutableIPs []netaddr.IPPrefix
|
||||||
|
RequestTags []string
|
||||||
|
Services []Service
|
||||||
|
NetInfo *NetInfo
|
||||||
|
}{})
|
||||||
|
|
||||||
|
// View makes a readonly view of DNSConfig.
|
||||||
|
func (src *DNSConfig) View() DNSConfigView {
|
||||||
|
return DNSConfigView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSConfigView is a readonly view of DNSConfig.
|
||||||
|
type DNSConfigView struct{ ж *DNSConfig }
|
||||||
|
|
||||||
|
func (v DNSConfigView) Valid() bool { return v.ж != nil }
|
||||||
|
|
||||||
|
type _DNSConfigView_Resolvers []dnstype.Resolver
|
||||||
|
|
||||||
|
func (s _DNSConfigView_Resolvers) Len() int { return len(s) }
|
||||||
|
func (s _DNSConfigView_Resolvers) At(i int) dnstype.ResolverView { return s[i].View() }
|
||||||
|
func (v DNSConfigView) Resolvers() interface {
|
||||||
|
Len() int
|
||||||
|
At(int) dnstype.ResolverView
|
||||||
|
} {
|
||||||
|
return _DNSConfigView_Resolvers(v.ж.Resolvers)
|
||||||
|
}
|
||||||
|
|
||||||
|
type _DNSConfigView_FallbackResolvers []dnstype.Resolver
|
||||||
|
|
||||||
|
func (s _DNSConfigView_FallbackResolvers) Len() int { return len(s) }
|
||||||
|
func (s _DNSConfigView_FallbackResolvers) At(i int) dnstype.ResolverView { return s[i].View() }
|
||||||
|
func (v DNSConfigView) FallbackResolvers() interface {
|
||||||
|
Len() int
|
||||||
|
At(int) dnstype.ResolverView
|
||||||
|
} {
|
||||||
|
return _DNSConfigView_FallbackResolvers(v.ж.FallbackResolvers)
|
||||||
|
}
|
||||||
|
func (v DNSConfigView) Domains() []string { return v.ж.Domains }
|
||||||
|
func (v DNSConfigView) Proxied() bool { return v.ж.Proxied }
|
||||||
|
func (v DNSConfigView) Nameservers() []netaddr.IP { return v.ж.Nameservers }
|
||||||
|
func (v DNSConfigView) PerDomain() bool { return v.ж.PerDomain }
|
||||||
|
func (v DNSConfigView) CertDomains() []string { return v.ж.CertDomains }
|
||||||
|
func (v DNSConfigView) ExtraRecords() []DNSRecord { return v.ж.ExtraRecords }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _DNSConfigViewNeedsRegeneration = DNSConfig(struct {
|
||||||
|
Resolvers []dnstype.Resolver
|
||||||
|
Routes map[string][]dnstype.Resolver
|
||||||
|
FallbackResolvers []dnstype.Resolver
|
||||||
|
Domains []string
|
||||||
|
Proxied bool
|
||||||
|
Nameservers []netaddr.IP
|
||||||
|
PerDomain bool
|
||||||
|
CertDomains []string
|
||||||
|
ExtraRecords []DNSRecord
|
||||||
|
}{})
|
||||||
|
|
||||||
|
// View makes a readonly view of NetInfo.
|
||||||
|
func (src *NetInfo) View() NetInfoView {
|
||||||
|
return NetInfoView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetInfoView is a readonly view of NetInfo.
|
||||||
|
type NetInfoView struct{ ж *NetInfo }
|
||||||
|
|
||||||
|
func (v NetInfoView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v NetInfoView) MappingVariesByDestIP() opt.Bool { return v.ж.MappingVariesByDestIP }
|
||||||
|
func (v NetInfoView) HairPinning() opt.Bool { return v.ж.HairPinning }
|
||||||
|
func (v NetInfoView) WorkingIPv6() opt.Bool { return v.ж.WorkingIPv6 }
|
||||||
|
func (v NetInfoView) WorkingUDP() opt.Bool { return v.ж.WorkingUDP }
|
||||||
|
func (v NetInfoView) HavePortMap() bool { return v.ж.HavePortMap }
|
||||||
|
func (v NetInfoView) UPnP() opt.Bool { return v.ж.UPnP }
|
||||||
|
func (v NetInfoView) PMP() opt.Bool { return v.ж.PMP }
|
||||||
|
func (v NetInfoView) PCP() opt.Bool { return v.ж.PCP }
|
||||||
|
func (v NetInfoView) PreferredDERP() int { return v.ж.PreferredDERP }
|
||||||
|
func (v NetInfoView) LinkType() string { return v.ж.LinkType }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _NetInfoViewNeedsRegeneration = NetInfo(struct {
|
||||||
|
MappingVariesByDestIP opt.Bool
|
||||||
|
HairPinning opt.Bool
|
||||||
|
WorkingIPv6 opt.Bool
|
||||||
|
WorkingUDP opt.Bool
|
||||||
|
HavePortMap bool
|
||||||
|
UPnP opt.Bool
|
||||||
|
PMP opt.Bool
|
||||||
|
PCP opt.Bool
|
||||||
|
PreferredDERP int
|
||||||
|
LinkType string
|
||||||
|
DERPLatency map[string]float64
|
||||||
|
}{})
|
||||||
|
|
||||||
|
// View makes a readonly view of DERPMap.
|
||||||
|
func (src *DERPMap) View() DERPMapView {
|
||||||
|
return DERPMapView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DERPMapView is a readonly view of DERPMap.
|
||||||
|
type DERPMapView struct{ ж *DERPMap }
|
||||||
|
|
||||||
|
func (v DERPMapView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v DERPMapView) OmitDefaultRegions() bool { return v.ж.OmitDefaultRegions }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _DERPMapViewNeedsRegeneration = DERPMap(struct {
|
||||||
|
Regions map[int]*DERPRegion
|
||||||
|
OmitDefaultRegions bool
|
||||||
|
}{})
|
@ -6,6 +6,7 @@
|
|||||||
package dnstype
|
package dnstype
|
||||||
|
|
||||||
//go:generate go run tailscale.com/cmd/cloner --type=Resolver --clonefunc=true --output=dnstype_clone.go
|
//go:generate go run tailscale.com/cmd/cloner --type=Resolver --clonefunc=true --output=dnstype_clone.go
|
||||||
|
//go:generate go run tailscale.com/cmd/viewer --type=Resolver --output=dnstype_view.go
|
||||||
|
|
||||||
import "inet.af/netaddr"
|
import "inet.af/netaddr"
|
||||||
|
|
||||||
|
30
types/dnstype/dnstype_view.go
Normal file
30
types/dnstype/dnstype_view.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Code generated by the following command; DO NOT EDIT.
|
||||||
|
// tailscale.com/cmd/viewer -type Resolver
|
||||||
|
|
||||||
|
package dnstype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"inet.af/netaddr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// View makes a readonly view of Resolver.
|
||||||
|
func (src *Resolver) View() ResolverView {
|
||||||
|
return ResolverView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolverView is a readonly view of Resolver.
|
||||||
|
type ResolverView struct{ ж *Resolver }
|
||||||
|
|
||||||
|
func (v ResolverView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v ResolverView) Addr() string { return v.ж.Addr }
|
||||||
|
func (v ResolverView) BootstrapResolution() []netaddr.IP { return v.ж.BootstrapResolution }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _ResolverViewNeedsRegeneration = Resolver(struct {
|
||||||
|
Addr string
|
||||||
|
BootstrapResolution []netaddr.IP
|
||||||
|
}{})
|
@ -5,6 +5,8 @@
|
|||||||
// Package netmap contains the netmap.NetworkMap type.
|
// Package netmap contains the netmap.NetworkMap type.
|
||||||
package netmap
|
package netmap
|
||||||
|
|
||||||
|
//go:generate go run tailscale.com/cmd/viewer --type=NetworkMap --output=netmap_view.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -66,8 +68,8 @@ type NetworkMap struct {
|
|||||||
// MagicDNS isn't necessarily in use).
|
// MagicDNS isn't necessarily in use).
|
||||||
//
|
//
|
||||||
// It will neither start nor end with a period.
|
// It will neither start nor end with a period.
|
||||||
func (nm *NetworkMap) MagicDNSSuffix() string {
|
func (nm NetworkMapView) MagicDNSSuffix() string {
|
||||||
name := strings.Trim(nm.Name, ".")
|
name := strings.Trim(nm.Name(), ".")
|
||||||
if i := strings.Index(name, "."); i != -1 {
|
if i := strings.Index(name, "."); i != -1 {
|
||||||
name = name[i+1:]
|
name = name[i+1:]
|
||||||
}
|
}
|
||||||
|
95
types/netmap/netmap_view.go
Normal file
95
types/netmap/netmap_view.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Code generated by the following command; DO NOT EDIT.
|
||||||
|
// tailscale.com/cmd/viewer -type NetworkMap
|
||||||
|
|
||||||
|
package netmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/key"
|
||||||
|
"tailscale.com/types/wgkey"
|
||||||
|
"tailscale.com/wgengine/filter"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// View makes a readonly view of NetworkMap.
|
||||||
|
func (src *NetworkMap) View() NetworkMapView {
|
||||||
|
return NetworkMapView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkMapView is a readonly view of NetworkMap.
|
||||||
|
type NetworkMapView struct{ ж *NetworkMap }
|
||||||
|
|
||||||
|
func (v NetworkMapView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v NetworkMapView) SelfNode() tailcfg.NodeView { return v.ж.SelfNode.View() }
|
||||||
|
func (v NetworkMapView) NodeKey() tailcfg.NodeKey { return v.ж.NodeKey }
|
||||||
|
func (v NetworkMapView) PrivateKey() wgkey.Private { return v.ж.PrivateKey }
|
||||||
|
func (v NetworkMapView) Expiry() time.Time { return v.ж.Expiry }
|
||||||
|
func (v NetworkMapView) Name() string { return v.ж.Name }
|
||||||
|
func (v NetworkMapView) Addresses() []netaddr.IPPrefix { return v.ж.Addresses }
|
||||||
|
func (v NetworkMapView) LocalPort() uint16 { return v.ж.LocalPort }
|
||||||
|
func (v NetworkMapView) MachineStatus() tailcfg.MachineStatus { return v.ж.MachineStatus }
|
||||||
|
func (v NetworkMapView) MachineKey() key.MachinePublic { return v.ж.MachineKey }
|
||||||
|
|
||||||
|
type _NetworkMapView_Peers []*tailcfg.Node
|
||||||
|
|
||||||
|
func (s _NetworkMapView_Peers) Len() int { return len(s) }
|
||||||
|
func (s _NetworkMapView_Peers) At(i int) tailcfg.NodeView { return s[i].View() }
|
||||||
|
func (v NetworkMapView) Peers() interface {
|
||||||
|
Len() int
|
||||||
|
At(int) tailcfg.NodeView
|
||||||
|
} {
|
||||||
|
return _NetworkMapView_Peers(v.ж.Peers)
|
||||||
|
}
|
||||||
|
func (v NetworkMapView) DNS() tailcfg.DNSConfigView { return v.ж.DNS.View() }
|
||||||
|
func (v NetworkMapView) Hostinfo() tailcfg.HostinfoView { return v.ж.Hostinfo.View() }
|
||||||
|
|
||||||
|
type _NetworkMapView_PacketFilter []filter.Match
|
||||||
|
|
||||||
|
func (s _NetworkMapView_PacketFilter) Len() int { return len(s) }
|
||||||
|
func (s _NetworkMapView_PacketFilter) At(i int) filter.MatchView { return s[i].View() }
|
||||||
|
func (v NetworkMapView) PacketFilter() interface {
|
||||||
|
Len() int
|
||||||
|
At(int) filter.MatchView
|
||||||
|
} {
|
||||||
|
return _NetworkMapView_PacketFilter(v.ж.PacketFilter)
|
||||||
|
}
|
||||||
|
func (v NetworkMapView) CollectServices() bool { return v.ж.CollectServices }
|
||||||
|
func (v NetworkMapView) DERPMap() tailcfg.DERPMapView { return v.ж.DERPMap.View() }
|
||||||
|
func (v NetworkMapView) Debug() *tailcfg.Debug {
|
||||||
|
ptr := v.ж.Debug
|
||||||
|
if ptr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cp := *ptr
|
||||||
|
return &cp
|
||||||
|
}
|
||||||
|
func (v NetworkMapView) User() tailcfg.UserID { return v.ж.User }
|
||||||
|
func (v NetworkMapView) Domain() string { return v.ж.Domain }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _NetworkMapViewNeedsRegeneration = NetworkMap(struct {
|
||||||
|
SelfNode *tailcfg.Node
|
||||||
|
NodeKey tailcfg.NodeKey
|
||||||
|
PrivateKey wgkey.Private
|
||||||
|
Expiry time.Time
|
||||||
|
Name string
|
||||||
|
Addresses []netaddr.IPPrefix
|
||||||
|
LocalPort uint16
|
||||||
|
MachineStatus tailcfg.MachineStatus
|
||||||
|
MachineKey key.MachinePublic
|
||||||
|
Peers []*tailcfg.Node
|
||||||
|
DNS tailcfg.DNSConfig
|
||||||
|
Hostinfo tailcfg.Hostinfo
|
||||||
|
PacketFilter []filter.Match
|
||||||
|
CollectServices bool
|
||||||
|
DERPMap *tailcfg.DERPMap
|
||||||
|
Debug *tailcfg.Debug
|
||||||
|
User tailcfg.UserID
|
||||||
|
Domain string
|
||||||
|
UserProfiles map[tailcfg.UserID]tailcfg.UserProfile
|
||||||
|
}{})
|
@ -14,6 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run tailscale.com/cmd/cloner --type=Match --output=match_clone.go
|
//go:generate go run tailscale.com/cmd/cloner --type=Match --output=match_clone.go
|
||||||
|
//go:generate go run tailscale.com/cmd/viewer --type=Match --output=match_view.go
|
||||||
|
|
||||||
// PortRange is a range of TCP and UDP ports.
|
// PortRange is a range of TCP and UDP ports.
|
||||||
type PortRange struct {
|
type PortRange struct {
|
||||||
|
33
wgengine/filter/match_view.go
Normal file
33
wgengine/filter/match_view.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2021 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.
|
||||||
|
|
||||||
|
// Code generated by the following command; DO NOT EDIT.
|
||||||
|
// tailscale.com/cmd/viewer -type Match
|
||||||
|
|
||||||
|
package filter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/types/ipproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// View makes a readonly view of Match.
|
||||||
|
func (src *Match) View() MatchView {
|
||||||
|
return MatchView{src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchView is a readonly view of Match.
|
||||||
|
type MatchView struct{ ж *Match }
|
||||||
|
|
||||||
|
func (v MatchView) Valid() bool { return v.ж != nil }
|
||||||
|
func (v MatchView) IPProto() []ipproto.Proto { return v.ж.IPProto }
|
||||||
|
func (v MatchView) Dsts() []NetPortRange { return v.ж.Dsts }
|
||||||
|
func (v MatchView) Srcs() []netaddr.IPPrefix { return v.ж.Srcs }
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _MatchViewNeedsRegeneration = Match(struct {
|
||||||
|
IPProto []ipproto.Proto
|
||||||
|
Dsts []NetPortRange
|
||||||
|
Srcs []netaddr.IPPrefix
|
||||||
|
}{})
|
@ -176,7 +176,7 @@ type DNSMap map[string]netaddr.IP
|
|||||||
|
|
||||||
func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
|
func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
|
||||||
ret := make(DNSMap)
|
ret := make(DNSMap)
|
||||||
suffix := nm.MagicDNSSuffix()
|
suffix := nm.View().MagicDNSSuffix()
|
||||||
have4 := false
|
have4 := false
|
||||||
if nm.Name != "" && len(nm.Addresses) > 0 {
|
if nm.Name != "" && len(nm.Addresses) > 0 {
|
||||||
ip := nm.Addresses[0].IP()
|
ip := nm.Addresses[0].IP()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user