| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- package ipn
- import (
- "net/netip"
- "tailscale.com/tailcfg"
- "tailscale.com/types/opt"
- "tailscale.com/types/preftype"
- )
- // ConfigVAlpha is the config file format for the "alpha0" version.
- type ConfigVAlpha struct {
- Version string // "alpha0" for now
- Locked opt.Bool `json:",omitempty"` // whether the config is locked from being changed by 'tailscale set'; it defaults to true
- ServerURL *string `json:",omitempty"` // defaults to https://controlplane.tailscale.com
- AuthKey *string `json:",omitempty"` // as needed if NeedsLogin. either key or path to a file (if prefixed with "file:")
- Enabled opt.Bool `json:",omitempty"` // wantRunning; empty string defaults to true
- OperatorUser *string `json:",omitempty"` // local user name who is allowed to operate tailscaled without being root or using sudo
- Hostname *string `json:",omitempty"`
- AcceptDNS opt.Bool `json:"acceptDNS,omitempty"` // --accept-dns
- AcceptRoutes opt.Bool `json:"acceptRoutes,omitempty"` // --accept-routes defaults to true
- ExitNode *string `json:"exitNode,omitempty"` // IP, StableID, or MagicDNS base name
- AllowLANWhileUsingExitNode opt.Bool `json:"allowLANWhileUsingExitNode,omitempty"`
- AdvertiseRoutes []netip.Prefix `json:",omitempty"`
- DisableSNAT opt.Bool `json:",omitempty"`
- AdvertiseServices []string `json:",omitempty"`
- AppConnector *AppConnectorPrefs `json:",omitempty"` // advertise app connector; defaults to false (if nil or explicitly set to false)
- NetfilterMode *string `json:",omitempty"` // "on", "off", "nodivert"
- NoStatefulFiltering opt.Bool `json:",omitempty"`
- PostureChecking opt.Bool `json:",omitempty"`
- RunSSHServer opt.Bool `json:",omitempty"` // Tailscale SSH
- RunWebClient opt.Bool `json:",omitempty"`
- ShieldsUp opt.Bool `json:",omitempty"`
- AutoUpdate *AutoUpdatePrefs `json:",omitempty"`
- ServeConfigTemp *ServeConfig `json:",omitempty"` // TODO(bradfitz,maisem): make separate stable type for this
- // StaticEndpoints are additional, user-defined endpoints that this node
- // should advertise amongst its wireguard endpoints.
- StaticEndpoints []netip.AddrPort `json:",omitempty"`
- // TODO(bradfitz,maisem): future something like:
- // Profile map[string]*Config // keyed by [email protected], corp.com (TailnetSID)
- }
- func (c *ConfigVAlpha) ToPrefs() (MaskedPrefs, error) {
- var mp MaskedPrefs
- if c == nil {
- return mp, nil
- }
- mp.WantRunning = !c.Enabled.EqualBool(false)
- mp.WantRunningSet = mp.WantRunning || c.Enabled != ""
- if c.ServerURL != nil {
- mp.ControlURL = *c.ServerURL
- mp.ControlURLSet = true
- }
- if c.AuthKey != nil && *c.AuthKey != "" {
- mp.LoggedOut = false
- mp.LoggedOutSet = true
- }
- if c.OperatorUser != nil {
- mp.OperatorUser = *c.OperatorUser
- mp.OperatorUserSet = true
- }
- if c.Hostname != nil {
- mp.Hostname = *c.Hostname
- mp.HostnameSet = true
- }
- if c.AcceptDNS != "" {
- mp.CorpDNS = c.AcceptDNS.EqualBool(true)
- mp.CorpDNSSet = true
- }
- if c.AcceptRoutes != "" {
- mp.RouteAll = c.AcceptRoutes.EqualBool(true)
- mp.RouteAllSet = true
- }
- if c.ExitNode != nil {
- ip, err := netip.ParseAddr(*c.ExitNode)
- if err == nil {
- mp.ExitNodeIP = ip
- mp.ExitNodeIPSet = true
- } else {
- mp.ExitNodeID = tailcfg.StableNodeID(*c.ExitNode)
- mp.ExitNodeIDSet = true
- }
- }
- if c.AllowLANWhileUsingExitNode != "" {
- mp.ExitNodeAllowLANAccess = c.AllowLANWhileUsingExitNode.EqualBool(true)
- mp.ExitNodeAllowLANAccessSet = true
- }
- if c.AdvertiseRoutes != nil {
- mp.AdvertiseRoutes = c.AdvertiseRoutes
- mp.AdvertiseRoutesSet = true
- }
- if c.DisableSNAT != "" {
- mp.NoSNAT = c.DisableSNAT.EqualBool(true)
- mp.NoSNAT = true
- }
- if c.NoStatefulFiltering != "" {
- mp.NoStatefulFiltering = c.NoStatefulFiltering
- mp.NoStatefulFilteringSet = true
- }
- if c.NetfilterMode != nil {
- m, err := preftype.ParseNetfilterMode(*c.NetfilterMode)
- if err != nil {
- return mp, err
- }
- mp.NetfilterMode = m
- mp.NetfilterModeSet = true
- }
- if c.PostureChecking != "" {
- mp.PostureChecking = c.PostureChecking.EqualBool(true)
- mp.PostureCheckingSet = true
- }
- if c.RunSSHServer != "" {
- mp.RunSSH = c.RunSSHServer.EqualBool(true)
- mp.RunSSHSet = true
- }
- if c.RunWebClient != "" {
- mp.RunWebClient = c.RunWebClient.EqualBool(true)
- mp.RunWebClientSet = true
- }
- if c.ShieldsUp != "" {
- mp.ShieldsUp = c.ShieldsUp.EqualBool(true)
- mp.ShieldsUpSet = true
- }
- if c.AutoUpdate != nil {
- mp.AutoUpdate = *c.AutoUpdate
- mp.AutoUpdateSet = AutoUpdatePrefsMask{ApplySet: true, CheckSet: true}
- }
- if c.AppConnector != nil {
- mp.AppConnector = *c.AppConnector
- mp.AppConnectorSet = true
- }
- // Configfile should be the source of truth for whether this node
- // advertises any services. We need to ensure that each reload updates
- // currently advertised services as else the transition from 'some
- // services are advertised' to 'advertised services are empty/unset in
- // conffile' would have no effect (especially given that an empty
- // service slice would be omitted from the JSON config).
- mp.AdvertiseServicesSet = true
- if c.AdvertiseServices != nil {
- mp.AdvertiseServices = c.AdvertiseServices
- }
- return mp, nil
- }
|