mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 13:05:46 +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,
|
||||
// since context cancelation is always on purpose.
|
||||
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.mu.Unlock()
|
||||
|
||||
c.sendStatus("authRoutine-wantout", nil, "", nil)
|
||||
c.sendStatus("authRoutine-wantout", nil, "", netmap.NetworkMapView{})
|
||||
bo.BackOff(ctx, nil)
|
||||
} else { // ie. goal.wantLoggedIn
|
||||
c.mu.Lock()
|
||||
@ -355,7 +355,7 @@ func (c *Auto) authRoutine() {
|
||||
c.synced = false
|
||||
c.mu.Unlock()
|
||||
|
||||
c.sendStatus("authRoutine-url", err, url, nil)
|
||||
c.sendStatus("authRoutine-url", err, url, netmap.NetworkMapView{})
|
||||
bo.BackOff(ctx, err)
|
||||
continue
|
||||
}
|
||||
@ -367,7 +367,7 @@ func (c *Auto) authRoutine() {
|
||||
c.state = StateAuthenticated
|
||||
c.mu.Unlock()
|
||||
|
||||
c.sendStatus("authRoutine-success", nil, "", nil)
|
||||
c.sendStatus("authRoutine-success", nil, "", netmap.NetworkMapView{})
|
||||
c.cancelMapSafely()
|
||||
bo.BackOff(ctx, nil)
|
||||
}
|
||||
@ -435,7 +435,7 @@ func (c *Auto) mapRoutine() {
|
||||
// don't send status updates for context errors,
|
||||
// since context cancelation is always on purpose.
|
||||
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()
|
||||
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)
|
||||
c.mu.Lock()
|
||||
|
||||
@ -482,7 +482,7 @@ func (c *Auto) mapRoutine() {
|
||||
if c.loggedIn {
|
||||
c.state = StateSynchronized
|
||||
}
|
||||
exp := nm.Expiry
|
||||
exp := nm.Expiry()
|
||||
c.expiry = &exp
|
||||
stillAuthed := c.loggedIn
|
||||
state := c.state
|
||||
@ -563,7 +563,7 @@ func (c *Auto) SetNetInfo(ni *tailcfg.NetInfo) {
|
||||
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()
|
||||
state := c.state
|
||||
loggedIn := c.loggedIn
|
||||
@ -583,13 +583,13 @@ func (c *Auto) sendStatus(who string, err error, url string, nm *netmap.NetworkM
|
||||
if state == StateNotAuthenticated {
|
||||
logoutFin = new(empty.Message)
|
||||
}
|
||||
if nm != nil && loggedIn && synced {
|
||||
if nm.Valid() && loggedIn && synced {
|
||||
pp := c.direct.GetPersist()
|
||||
p = &pp
|
||||
} else {
|
||||
// don't send netmap status, as it's misleading when we're
|
||||
// not logged in.
|
||||
nm = nil
|
||||
nm = netmap.NetworkMapView{}
|
||||
}
|
||||
new := Status{
|
||||
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
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -552,7 +552,7 @@ func (c *Direct) SendLiteMapUpdate(ctx context.Context) error {
|
||||
const pollTimeout = 120 * time.Second
|
||||
|
||||
// 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()
|
||||
persist := c.persist
|
||||
serverURL := c.serverURL
|
||||
@ -822,7 +822,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm
|
||||
c.expiry = &nm.Expiry
|
||||
c.mu.Unlock()
|
||||
|
||||
cb(nm)
|
||||
cb(nm.View())
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
|
@ -139,7 +139,7 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
|
||||
}
|
||||
|
||||
ms.addUserProfile(nm.User)
|
||||
magicDNSSuffix := nm.MagicDNSSuffix()
|
||||
magicDNSSuffix := nm.View().MagicDNSSuffix()
|
||||
if nm.SelfNode != nil {
|
||||
nm.SelfNode.InitDisplayNames(magicDNSSuffix)
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ type Status struct {
|
||||
LogoutFinished *empty.Message // nonempty when logout finishes
|
||||
Err string
|
||||
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
|
||||
// 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
|
||||
// hostinfo is mutated in-place while mu is held.
|
||||
hostinfo *tailcfg.Hostinfo
|
||||
// netMap is not mutated in-place once set.
|
||||
netMap *netmap.NetworkMap
|
||||
netMap netmap.NetworkMapView
|
||||
nodeByAddr map[netaddr.IP]*tailcfg.Node
|
||||
activeLogin string // last logged LoginName from netMap
|
||||
engineStatus ipn.EngineStatus
|
||||
@ -224,7 +223,7 @@ func (b *LocalBackend) maybePauseControlClientLocked() {
|
||||
return
|
||||
}
|
||||
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.
|
||||
@ -253,8 +252,8 @@ func (b *LocalBackend) linkChange(major bool, ifst *interfaces.State) {
|
||||
// need updating to tweak default routes.
|
||||
b.updateFilter(b.netMap, b.prefs)
|
||||
|
||||
if peerAPIListenAsync && b.netMap != nil && b.state == ipn.Running {
|
||||
want := len(b.netMap.Addresses)
|
||||
if peerAPIListenAsync && b.netMap.Valid() && b.state == ipn.Running {
|
||||
want := len(b.netMap.Addresses())
|
||||
if len(b.peerAPIListeners) < want {
|
||||
b.logf("linkChange: peerAPIListeners too low; trying again")
|
||||
go b.initPeerAPIListener()
|
||||
@ -343,14 +342,14 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
||||
s.Health = append(s.Health, err.Error())
|
||||
}
|
||||
}
|
||||
if b.netMap != nil {
|
||||
if b.netMap.Valid() {
|
||||
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) {
|
||||
if b.netMap != nil && b.netMap.SelfNode != nil {
|
||||
ss.ID = b.netMap.SelfNode.StableID
|
||||
if b.netMap.Valid() && b.netMap.SelfNode != nil {
|
||||
ss.ID = b.netMap.SelfNode().StableID()
|
||||
}
|
||||
for _, pln := range b.peerAPIListeners {
|
||||
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) {
|
||||
if b.netMap == nil {
|
||||
if !b.netMap.Valid() {
|
||||
return
|
||||
}
|
||||
for id, up := range b.netMap.UserProfiles {
|
||||
for _, id := range b.netMap.UserIDs() {
|
||||
up := b.netMap.UserProfile(id)
|
||||
sb.AddUser(id, up)
|
||||
}
|
||||
for _, p := range b.netMap.Peers {
|
||||
for _, p := range b.netMap.Peers() {
|
||||
var lastSeen time.Time
|
||||
if p.LastSeen != nil {
|
||||
lastSeen = *p.LastSeen
|
||||
if p.LastSeen() != nil {
|
||||
lastSeen = *p.LastSeen()
|
||||
}
|
||||
var tailAddr4 string
|
||||
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses))
|
||||
for _, addr := range p.Addresses {
|
||||
var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses()))
|
||||
for _, addr := range p.Addresses() {
|
||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP()) {
|
||||
if addr.IP().Is4() && tailAddr4 == "" {
|
||||
// The peer struct previously only allowed a single
|
||||
@ -389,20 +389,20 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
||||
tailscaleIPs = append(tailscaleIPs, addr.IP())
|
||||
}
|
||||
}
|
||||
sb.AddPeer(key.Public(p.Key), &ipnstate.PeerStatus{
|
||||
sb.AddPeer(key.Public(p.Key()), &ipnstate.PeerStatus{
|
||||
InNetworkMap: true,
|
||||
ID: p.StableID,
|
||||
UserID: p.User,
|
||||
ID: p.StableID(),
|
||||
UserID: p.User(),
|
||||
TailAddrDeprecated: tailAddr4,
|
||||
TailscaleIPs: tailscaleIPs,
|
||||
HostName: p.Hostinfo.Hostname,
|
||||
DNSName: p.Name,
|
||||
OS: p.Hostinfo.OS,
|
||||
KeepAlive: p.KeepAlive,
|
||||
Created: p.Created,
|
||||
HostName: p.Hostinfo().Hostname(),
|
||||
DNSName: p.Name(),
|
||||
OS: p.Hostinfo().OS(),
|
||||
KeepAlive: p.KeepAlive(),
|
||||
Created: p.Created(),
|
||||
LastSeen: lastSeen,
|
||||
ShareeNode: p.Hostinfo.ShareeNode,
|
||||
ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID,
|
||||
ShareeNode: p.Hostinfo().ShareeNode(),
|
||||
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 st.NetMap==nil means "netmap is unchanged", there is
|
||||
// no other way to represent this change.
|
||||
b.setNetMapLocked(nil)
|
||||
b.setNetMapLocked(netmap.NetworkMapView{})
|
||||
}
|
||||
|
||||
prefs := b.prefs
|
||||
@ -501,7 +501,7 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
||||
b.prefs.Persist = st.Persist.Clone()
|
||||
}
|
||||
}
|
||||
if st.NetMap != nil {
|
||||
if st.NetMap.Valid() {
|
||||
if b.findExitNodeIDLocked(st.NetMap) {
|
||||
prefsChanged = true
|
||||
}
|
||||
@ -537,8 +537,8 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
|
||||
}
|
||||
b.send(ipn.Notify{Prefs: prefs})
|
||||
}
|
||||
if st.NetMap != nil {
|
||||
if netMap != nil {
|
||||
if st.NetMap.Valid() {
|
||||
if netMap.Valid() {
|
||||
diff := st.NetMap.ConciseDiffFrom(netMap)
|
||||
if strings.TrimSpace(diff) == "" {
|
||||
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,
|
||||
// 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
|
||||
// node.
|
||||
if b.prefs.ExitNodeIP.IsZero() {
|
||||
@ -580,14 +580,16 @@ func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged
|
||||
prefsChanged = true
|
||||
}
|
||||
|
||||
for _, peer := range nm.Peers {
|
||||
for _, addr := range peer.Addresses {
|
||||
peers := nm.Peers()
|
||||
for i := 0; i < peers.Len(); i++ {
|
||||
peer := peers.At(i)
|
||||
for _, addr := range peer.Addresses() {
|
||||
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.ExitNodeID = peer.StableID()
|
||||
b.prefs.ExitNodeIP = netaddr.IP{}
|
||||
return true
|
||||
}
|
||||
@ -922,14 +924,14 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
||||
|
||||
// updateFilter updates the packet filter in wgengine based on the
|
||||
// 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
|
||||
// this function. Don't try to optimize by returning early, more
|
||||
// likely than not you'll just end up breaking the change
|
||||
// detection and end up with the wrong filter installed. This is
|
||||
// quite hard to debug, so save yourself the trouble.
|
||||
var (
|
||||
haveNetmap = netMap != nil
|
||||
haveNetmap = netMap.Valid()
|
||||
addrs []netaddr.IPPrefix
|
||||
packetFilter []filter.Match
|
||||
localNetsB netaddr.IPSetBuilder
|
||||
@ -941,7 +943,7 @@ func (b *LocalBackend) updateFilter(netMap *netmap.NetworkMap, prefs *ipn.Prefs)
|
||||
logNetsB.AddPrefix(tsaddr.TailscaleULARange())
|
||||
logNetsB.RemovePrefix(tsaddr.ChromeOSVMRange())
|
||||
if haveNetmap {
|
||||
addrs = netMap.Addresses
|
||||
addrs = netMap.Addresses()
|
||||
for _, p := range addrs {
|
||||
localNetsB.AddPrefix(p)
|
||||
}
|
||||
@ -2533,10 +2535,10 @@ func hasCapability(nm *netmap.NetworkMap, cap string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
||||
func (b *LocalBackend) setNetMapLocked(nm netmap.NetworkMapView) {
|
||||
var login string
|
||||
if nm != nil {
|
||||
login = nm.UserProfiles[nm.User].LoginName
|
||||
if nm.Valid() {
|
||||
login = nm.UserProfile(nm.User()).LoginName
|
||||
if login == "" {
|
||||
login = "<missing-profile>"
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
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/viewer --type=Node,Hostinfo,DNSConfig,NetInfo,DERPMap --output=tailcfg_view.go
|
||||
|
||||
import (
|
||||
"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
|
||||
|
||||
//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"
|
||||
|
||||
|
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
|
||||
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=NetworkMap --output=netmap_view.go
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@ -66,8 +68,8 @@ type NetworkMap struct {
|
||||
// MagicDNS isn't necessarily in use).
|
||||
//
|
||||
// It will neither start nor end with a period.
|
||||
func (nm *NetworkMap) MagicDNSSuffix() string {
|
||||
name := strings.Trim(nm.Name, ".")
|
||||
func (nm NetworkMapView) MagicDNSSuffix() string {
|
||||
name := strings.Trim(nm.Name(), ".")
|
||||
if i := strings.Index(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 @@
|
||||
)
|
||||
|
||||
//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.
|
||||
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 @@ func (ns *Impl) Start() error {
|
||||
|
||||
func DNSMapFromNetworkMap(nm *netmap.NetworkMap) DNSMap {
|
||||
ret := make(DNSMap)
|
||||
suffix := nm.MagicDNSSuffix()
|
||||
suffix := nm.View().MagicDNSSuffix()
|
||||
have4 := false
|
||||
if nm.Name != "" && len(nm.Addresses) > 0 {
|
||||
ip := nm.Addresses[0].IP()
|
||||
|
Loading…
Reference in New Issue
Block a user