tailcfg.go 106 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package tailcfg
  4. //go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile --clonefunc
  5. import (
  6. "bytes"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "maps"
  11. "net/netip"
  12. "reflect"
  13. "slices"
  14. "strings"
  15. "time"
  16. "tailscale.com/types/dnstype"
  17. "tailscale.com/types/key"
  18. "tailscale.com/types/opt"
  19. "tailscale.com/types/structs"
  20. "tailscale.com/types/tkatype"
  21. "tailscale.com/util/cmpx"
  22. "tailscale.com/util/dnsname"
  23. "tailscale.com/util/slicesx"
  24. )
  25. // CapabilityVersion represents the client's capability level. That
  26. // is, it can be thought of as the client's simple version number: a
  27. // single monotonically increasing integer, rather than the relatively
  28. // complex x.y.z-xxxxx semver+hash(es). Whenever the client gains a
  29. // capability or wants to negotiate a change in semantics with the
  30. // server (control plane), peers (over PeerAPI), or frontend (over
  31. // LocalAPI), bump this number and document what's new.
  32. //
  33. // Previously (prior to 2022-03-06), it was known as the "MapRequest
  34. // version" or "mapVer" or "map cap" and that name and usage persists
  35. // in places.
  36. type CapabilityVersion int
  37. // CurrentCapabilityVersion is the current capability version of the codebase.
  38. //
  39. // History of versions:
  40. //
  41. // - 3: implicit compression, keep-alives
  42. // - 4: opt-in keep-alives via KeepAlive field, opt-in compression via Compress
  43. // - 5: 2020-10-19, implies IncludeIPv6, delta Peers/UserProfiles, supports MagicDNS
  44. // - 6: 2020-12-07: means MapResponse.PacketFilter nil means unchanged
  45. // - 7: 2020-12-15: FilterRule.SrcIPs accepts CIDRs+ranges, doesn't warn about 0.0.0.0/::
  46. // - 8: 2020-12-19: client can buggily receive IPv6 addresses and routes if beta enabled server-side
  47. // - 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains
  48. // - 10: 2021-01-17: client understands MapResponse.PeerSeenChange
  49. // - 11: 2021-03-03: client understands IPv6, multiple default routes, and goroutine dumping
  50. // - 12: 2021-03-04: client understands PingRequest
  51. // - 13: 2021-03-19: client understands FilterRule.IPProto
  52. // - 14: 2021-04-07: client understands DNSConfig.Routes and DNSConfig.Resolvers
  53. // - 15: 2021-04-12: client treats nil MapResponse.DNSConfig as meaning unchanged
  54. // - 16: 2021-04-15: client understands Node.Online, MapResponse.OnlineChange
  55. // - 17: 2021-04-18: MapResponse.Domain empty means unchanged
  56. // - 18: 2021-04-19: MapResponse.Node nil means unchanged (all fields now omitempty)
  57. // - 19: 2021-04-21: MapResponse.Debug.SleepSeconds
  58. // - 20: 2021-06-11: MapResponse.LastSeen used even less (https://github.com/tailscale/tailscale/issues/2107)
  59. // - 21: 2021-06-15: added MapResponse.DNSConfig.CertDomains
  60. // - 22: 2021-06-16: added MapResponse.DNSConfig.ExtraRecords
  61. // - 23: 2021-08-25: DNSConfig.Routes values may be empty (for ExtraRecords support in 1.14.1+)
  62. // - 24: 2021-09-18: MapResponse.Health from control to node; node shows in "tailscale status"
  63. // - 25: 2021-11-01: MapResponse.Debug.Exit
  64. // - 26: 2022-01-12: (nothing, just bumping for 1.20.0)
  65. // - 27: 2022-02-18: start of SSHPolicy being respected
  66. // - 28: 2022-03-09: client can communicate over Noise.
  67. // - 29: 2022-03-21: MapResponse.PopBrowserURL
  68. // - 30: 2022-03-22: client can request id tokens.
  69. // - 31: 2022-04-15: PingRequest & PingResponse TSMP & disco support
  70. // - 32: 2022-04-17: client knows FilterRule.CapMatch
  71. // - 33: 2022-07-20: added MapResponse.PeersChangedPatch (DERPRegion + Endpoints)
  72. // - 34: 2022-08-02: client understands CapabilityFileSharingTarget
  73. // - 36: 2022-08-02: added PeersChangedPatch.{Key,DiscoKey,Online,LastSeen,KeyExpiry,Capabilities}
  74. // - 37: 2022-08-09: added Debug.{SetForceBackgroundSTUN,SetRandomizeClientPort}; Debug are sticky
  75. // - 38: 2022-08-11: added PingRequest.URLIsNoise
  76. // - 39: 2022-08-15: clients can talk Noise over arbitrary HTTPS port
  77. // - 40: 2022-08-22: added Node.KeySignature, PeersChangedPatch.KeySignature
  78. // - 41: 2022-08-30: uses 100.100.100.100 for route-less ExtraRecords if global nameservers is set
  79. // - 42: 2022-09-06: NextDNS DoH support; see https://github.com/tailscale/tailscale/pull/5556
  80. // - 43: 2022-09-21: clients can return usernames for SSH
  81. // - 44: 2022-09-22: MapResponse.ControlDialPlan
  82. // - 45: 2022-09-26: c2n /debug/{goroutines,prefs,metrics}
  83. // - 46: 2022-10-04: c2n /debug/component-logging
  84. // - 47: 2022-10-11: Register{Request,Response}.NodeKeySignature
  85. // - 48: 2022-11-02: Node.UnsignedPeerAPIOnly
  86. // - 49: 2022-11-03: Client understands EarlyNoise
  87. // - 50: 2022-11-14: Client understands CapabilityIngress
  88. // - 51: 2022-11-30: Client understands CapabilityTailnetLockAlpha
  89. // - 52: 2023-01-05: client can handle c2n POST /logtail/flush
  90. // - 53: 2023-01-18: client respects explicit Node.Expired + auto-sets based on Node.KeyExpiry
  91. // - 54: 2023-01-19: Node.Cap added, PeersChangedPatch.Cap, uses Node.Cap for ExitDNS before Hostinfo.Services fallback
  92. // - 55: 2023-01-23: start of c2n GET+POST /update handler
  93. // - 56: 2023-01-24: Client understands CapabilityDebugTSDNSResolution
  94. // - 57: 2023-01-25: Client understands CapabilityBindToInterfaceByRoute
  95. // - 58: 2023-03-10: Client retries lite map updates before restarting map poll.
  96. // - 59: 2023-03-16: Client understands Peers[].SelfNodeV4MasqAddrForThisPeer
  97. // - 60: 2023-04-06: Client understands IsWireGuardOnly
  98. // - 61: 2023-04-18: Client understand SSHAction.SSHRecorderFailureAction
  99. // - 62: 2023-05-05: Client can notify control over noise for SSHEventNotificationRequest recording failure events
  100. // - 63: 2023-06-08: Client understands SSHAction.AllowRemotePortForwarding.
  101. // - 64: 2023-07-11: Client understands s/CapabilityTailnetLockAlpha/CapabilityTailnetLock
  102. // - 65: 2023-07-12: Client understands DERPMap.HomeParams + incremental DERPMap updates with params
  103. // - 66: 2023-07-23: UserProfile.Groups added (available via WhoIs)
  104. // - 67: 2023-07-25: Client understands PeerCapMap
  105. // - 68: 2023-08-09: Client has dedicated updateRoutine; MapRequest.Stream true means ignore Hostinfo+Endpoints
  106. // - 69: 2023-08-16: removed Debug.LogHeap* + GoroutineDumpURL; added c2n /debug/logheap
  107. // - 70: 2023-08-16: removed most Debug fields; added NodeAttrDisable*, NodeAttrDebug* instead
  108. // - 71: 2023-08-17: added NodeAttrOneCGNATEnable, NodeAttrOneCGNATDisable
  109. // - 72: 2023-08-23: TS-2023-006 UPnP issue fixed; UPnP can now be used again
  110. // - 73: 2023-09-01: Non-Windows clients expect to receive ClientVersion
  111. // - 74: 2023-09-18: Client understands NodeCapMap
  112. // - 75: 2023-09-12: Client understands NodeAttrDNSForwarderDisableTCPRetries
  113. // - 76: 2023-09-20: Client understands ExitNodeDNSResolvers for IsWireGuardOnly nodes
  114. // - 77: 2023-10-03: Client understands Peers[].SelfNodeV6MasqAddrForThisPeer
  115. // - 78: 2023-10-05: can handle c2n Wake-on-LAN sending
  116. // - 79: 2023-10-05: Client understands UrgentSecurityUpdate in ClientVersion
  117. // - 80: 2023-11-16: can handle c2n GET /tls-cert-status
  118. // - 81: 2023-11-17: MapResponse.PacketFilters (incremental packet filter updates)
  119. // - 82: 2023-12-01: Client understands NodeAttrLinuxMustUseIPTables, NodeAttrLinuxMustUseNfTables, c2n /netfilter-kind
  120. // - 83: 2023-12-18: Client understands DefaultAutoUpdate
  121. // - 84: 2024-01-04: Client understands SeamlessKeyRenewal
  122. // - 85: 2024-01-05: Client understands MaxKeyDuration
  123. const CurrentCapabilityVersion CapabilityVersion = 85
  124. type StableID string
  125. type ID int64
  126. type UserID ID
  127. func (u UserID) IsZero() bool {
  128. return u == 0
  129. }
  130. type LoginID ID
  131. func (u LoginID) IsZero() bool {
  132. return u == 0
  133. }
  134. type NodeID ID
  135. func (u NodeID) IsZero() bool {
  136. return u == 0
  137. }
  138. type StableNodeID StableID
  139. func (u StableNodeID) IsZero() bool {
  140. return u == ""
  141. }
  142. // User is an IPN user.
  143. //
  144. // A user can have multiple logins associated with it (e.g. gmail and github oauth).
  145. // (Note: none of our UIs support this yet.)
  146. //
  147. // Some properties are inherited from the logins and can be overridden, such as
  148. // display name and profile picture.
  149. //
  150. // Other properties must be the same for all logins associated with a user.
  151. // In particular: domain. If a user has a "tailscale.io" domain login, they cannot
  152. // have a general gmail address login associated with the user.
  153. type User struct {
  154. ID UserID
  155. LoginName string `json:"-"` // not stored, filled from Login // TODO REMOVE
  156. DisplayName string // if non-empty overrides Login field
  157. ProfilePicURL string // if non-empty overrides Login field
  158. Logins []LoginID
  159. Created time.Time
  160. }
  161. type Login struct {
  162. _ structs.Incomparable
  163. ID LoginID
  164. Provider string
  165. LoginName string
  166. DisplayName string
  167. ProfilePicURL string
  168. }
  169. // A UserProfile is display-friendly data for a user.
  170. // It includes the LoginName for display purposes but *not* the Provider.
  171. // It also includes derived data from one of the user's logins.
  172. type UserProfile struct {
  173. ID UserID
  174. LoginName string // "[email protected]"; for display purposes only (provider is not listed)
  175. DisplayName string // "Alice Smith"
  176. ProfilePicURL string
  177. // Roles exists for legacy reasons, to keep old macOS clients
  178. // happy. It JSON marshals as [].
  179. Roles emptyStructJSONSlice
  180. // Groups contains group identifiers for any group that this user is
  181. // a part of and that the coordination server is configured to tell
  182. // your node about. (Thus, it may be empty or incomplete.)
  183. // There's no semantic difference between a nil and an empty list.
  184. // The list is always sorted.
  185. Groups []string `json:",omitempty"`
  186. }
  187. func (p *UserProfile) Equal(p2 *UserProfile) bool {
  188. if p == nil && p2 == nil {
  189. return true
  190. }
  191. if p == nil || p2 == nil {
  192. return false
  193. }
  194. return p.ID == p2.ID &&
  195. p.LoginName == p2.LoginName &&
  196. p.DisplayName == p2.DisplayName &&
  197. p.ProfilePicURL == p2.ProfilePicURL &&
  198. (len(p.Groups) == 0 && len(p2.Groups) == 0 || reflect.DeepEqual(p.Groups, p2.Groups))
  199. }
  200. type emptyStructJSONSlice struct{}
  201. var emptyJSONSliceBytes = []byte("[]")
  202. func (emptyStructJSONSlice) MarshalJSON() ([]byte, error) {
  203. return emptyJSONSliceBytes, nil
  204. }
  205. func (emptyStructJSONSlice) UnmarshalJSON([]byte) error { return nil }
  206. // RawMessage is a raw encoded JSON value. It implements Marshaler and
  207. // Unmarshaler and can be used to delay JSON decoding or precompute a JSON
  208. // encoding.
  209. //
  210. // It is like json.RawMessage but is a string instead of a []byte to better
  211. // portray immutable data.
  212. type RawMessage string
  213. // MarshalJSON returns m as the JSON encoding of m.
  214. func (m RawMessage) MarshalJSON() ([]byte, error) {
  215. if m == "" {
  216. return []byte("null"), nil
  217. }
  218. return []byte(m), nil
  219. }
  220. // UnmarshalJSON sets *m to a copy of data.
  221. func (m *RawMessage) UnmarshalJSON(data []byte) error {
  222. if m == nil {
  223. return errors.New("RawMessage: UnmarshalJSON on nil pointer")
  224. }
  225. *m = RawMessage(data)
  226. return nil
  227. }
  228. type Node struct {
  229. ID NodeID
  230. StableID StableNodeID
  231. // Name is the FQDN of the node.
  232. // It is also the MagicDNS name for the node.
  233. // It has a trailing dot.
  234. // e.g. "host.tail-scale.ts.net."
  235. Name string
  236. // User is the user who created the node. If ACL tags are in use for the
  237. // node then it doesn't reflect the ACL identity that the node is running
  238. // as.
  239. User UserID
  240. // Sharer, if non-zero, is the user who shared this node, if different than User.
  241. Sharer UserID `json:",omitempty"`
  242. Key key.NodePublic
  243. KeyExpiry time.Time // the zero value if this node does not expire
  244. KeySignature tkatype.MarshaledSignature `json:",omitempty"`
  245. Machine key.MachinePublic
  246. DiscoKey key.DiscoPublic
  247. Addresses []netip.Prefix // IP addresses of this Node directly
  248. AllowedIPs []netip.Prefix // range of IP addresses to route to this node
  249. Endpoints []netip.AddrPort `json:",omitempty"` // IP+port (public via STUN, and local LANs)
  250. // DERP is this node's home DERP region ID integer, but shoved into an
  251. // IP:port string for legacy reasons. The IP address is always "127.3.3.40"
  252. // (a loopback address (127) followed by the digits over the letters DERP on
  253. // a QWERTY keyboard (3.3.40)). The "port number" is the home DERP region ID
  254. // integer.
  255. //
  256. // TODO(bradfitz): simplify this legacy mess; add a new HomeDERPRegionID int
  257. // field behind a new capver bump.
  258. DERP string `json:",omitempty"` // DERP-in-IP:port ("127.3.3.40:N") endpoint
  259. Hostinfo HostinfoView
  260. Created time.Time
  261. Cap CapabilityVersion `json:",omitempty"` // if non-zero, the node's capability version; old servers might not send
  262. // Tags are the list of ACL tags applied to this node.
  263. // Tags take the form of `tag:<value>` where value starts
  264. // with a letter and only contains alphanumerics and dashes `-`.
  265. // Some valid tag examples:
  266. // `tag:prod`
  267. // `tag:database`
  268. // `tag:lab-1`
  269. Tags []string `json:",omitempty"`
  270. // PrimaryRoutes are the routes from AllowedIPs that this node
  271. // is currently the primary subnet router for, as determined
  272. // by the control plane. It does not include the self address
  273. // values from Addresses that are in AllowedIPs.
  274. PrimaryRoutes []netip.Prefix `json:",omitempty"`
  275. // LastSeen is when the node was last online. It is not
  276. // updated when Online is true. It is nil if the current
  277. // node doesn't have permission to know, or the node
  278. // has never been online.
  279. LastSeen *time.Time `json:",omitempty"`
  280. // Online is whether the node is currently connected to the
  281. // coordination server. A value of nil means unknown, or the
  282. // current node doesn't have permission to know.
  283. Online *bool `json:",omitempty"`
  284. MachineAuthorized bool `json:",omitempty"` // TODO(crawshaw): replace with MachineStatus
  285. // Capabilities are capabilities that the node has.
  286. // They're free-form strings, but should be in the form of URLs/URIs
  287. // such as:
  288. // "https://tailscale.com/cap/is-admin"
  289. // "https://tailscale.com/cap/file-sharing"
  290. //
  291. // Deprecated: use CapMap instead.
  292. Capabilities []NodeCapability `json:",omitempty"`
  293. // CapMap is a map of capabilities to their optional argument/data values.
  294. //
  295. // It is valid for a capability to not have any argument/data values; such
  296. // capabilities can be tested for using the HasCap method. These type of
  297. // capabilities are used to indicate that a node has a capability, but there
  298. // is no additional data associated with it. These were previously
  299. // represented by the Capabilities field, but can now be represented by
  300. // CapMap with an empty value.
  301. //
  302. // See NodeCapability for more information on keys.
  303. CapMap NodeCapMap `json:",omitempty"`
  304. // UnsignedPeerAPIOnly means that this node is not signed nor subject to TKA
  305. // restrictions. However, in exchange for that privilege, it does not get
  306. // network access. It can only access this node's peerapi, which may not let
  307. // it do anything. It is the tailscaled client's job to double-check the
  308. // MapResponse's PacketFilter to verify that its AllowedIPs will not be
  309. // accepted by the packet filter.
  310. UnsignedPeerAPIOnly bool `json:",omitempty"`
  311. // The following three computed fields hold the various names that can
  312. // be used for this node in UIs. They are populated from controlclient
  313. // (not from control) by calling node.InitDisplayNames. These can be
  314. // used directly or accessed via node.DisplayName or node.DisplayNames.
  315. ComputedName string `json:",omitempty"` // MagicDNS base name (for normal non-shared-in nodes), FQDN (without trailing dot, for shared-in nodes), or Hostname (if no MagicDNS)
  316. computedHostIfDifferent string // hostname, if different than ComputedName, otherwise empty
  317. ComputedNameWithHost string `json:",omitempty"` // either "ComputedName" or "ComputedName (computedHostIfDifferent)", if computedHostIfDifferent is set
  318. // DataPlaneAuditLogID is the per-node logtail ID used for data plane audit logging.
  319. DataPlaneAuditLogID string `json:",omitempty"`
  320. // Expired is whether this node's key has expired. Control may send
  321. // this; clients are only allowed to set this from false to true. On
  322. // the client, this is calculated client-side based on a timestamp sent
  323. // from control, to avoid clock skew issues.
  324. Expired bool `json:",omitempty"`
  325. // SelfNodeV4MasqAddrForThisPeer is the IPv4 that this peer knows the current node as.
  326. // It may be empty if the peer knows the current node by its native
  327. // IPv4 address.
  328. // This field is only populated in a MapResponse for peers and not
  329. // for the current node.
  330. //
  331. // If set, it should be used to masquerade traffic originating from the
  332. // current node to this peer. The masquerade address is only relevant
  333. // for this peer and not for other peers.
  334. //
  335. // This only applies to traffic originating from the current node to the
  336. // peer or any of its subnets. Traffic originating from subnet routes will
  337. // not be masqueraded (e.g. in case of --snat-subnet-routes).
  338. SelfNodeV4MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
  339. // SelfNodeV6MasqAddrForThisPeer is the IPv6 that this peer knows the current node as.
  340. // It may be empty if the peer knows the current node by its native
  341. // IPv6 address.
  342. // This field is only populated in a MapResponse for peers and not
  343. // for the current node.
  344. //
  345. // If set, it should be used to masquerade traffic originating from the
  346. // current node to this peer. The masquerade address is only relevant
  347. // for this peer and not for other peers.
  348. //
  349. // This only applies to traffic originating from the current node to the
  350. // peer or any of its subnets. Traffic originating from subnet routes will
  351. // not be masqueraded (e.g. in case of --snat-subnet-routes).
  352. SelfNodeV6MasqAddrForThisPeer *netip.Addr `json:",omitempty"`
  353. // IsWireGuardOnly indicates that this is a non-Tailscale WireGuard peer, it
  354. // is not expected to speak Disco or DERP, and it must have Endpoints in
  355. // order to be reachable.
  356. IsWireGuardOnly bool `json:",omitempty"`
  357. // ExitNodeDNSResolvers is the list of DNS servers that should be used when this
  358. // node is marked IsWireGuardOnly and being used as an exit node.
  359. ExitNodeDNSResolvers []*dnstype.Resolver `json:",omitempty"`
  360. }
  361. // HasCap reports whether the node has the given capability.
  362. // It is safe to call on an invalid NodeView.
  363. func (v NodeView) HasCap(cap NodeCapability) bool {
  364. return v.ж.HasCap(cap)
  365. }
  366. // HasCap reports whether the node has the given capability.
  367. // It is safe to call on a nil Node.
  368. func (v *Node) HasCap(cap NodeCapability) bool {
  369. return v != nil && (v.CapMap.Contains(cap) || slices.Contains(v.Capabilities, cap))
  370. }
  371. // DisplayName returns the user-facing name for a node which should
  372. // be shown in client UIs.
  373. //
  374. // Parameter forOwner specifies whether the name is requested by
  375. // the owner of the node. When forOwner is false, the hostname is
  376. // never included in the return value.
  377. //
  378. // Return value is either "Name" or "Name (Hostname)", where
  379. // Name is the node's MagicDNS base name (for normal non-shared-in
  380. // nodes), FQDN (without trailing dot, for shared-in nodes), or
  381. // Hostname (if no MagicDNS). Hostname is only included in the
  382. // return value if it varies from Name and forOwner is provided true.
  383. //
  384. // DisplayName is only valid if InitDisplayNames has been called.
  385. func (n *Node) DisplayName(forOwner bool) string {
  386. if forOwner {
  387. return n.ComputedNameWithHost
  388. }
  389. return n.ComputedName
  390. }
  391. // DisplayName returns the decomposed user-facing name for a node.
  392. //
  393. // Parameter forOwner specifies whether the name is requested by
  394. // the owner of the node. When forOwner is false, hostIfDifferent
  395. // is always returned empty.
  396. //
  397. // Return value name is the node's primary name, populated with the
  398. // node's MagicDNS base name (for normal non-shared-in nodes), FQDN
  399. // (without trailing dot, for shared-in nodes), or Hostname (if no
  400. // MagicDNS).
  401. //
  402. // Return value hostIfDifferent, when non-empty, is the node's
  403. // hostname. hostIfDifferent is only populated when the hostname
  404. // varies from name and forOwner is provided as true.
  405. //
  406. // DisplayNames is only valid if InitDisplayNames has been called.
  407. func (n *Node) DisplayNames(forOwner bool) (name, hostIfDifferent string) {
  408. if forOwner {
  409. return n.ComputedName, n.computedHostIfDifferent
  410. }
  411. return n.ComputedName, ""
  412. }
  413. // IsTagged reports whether the node has any tags.
  414. func (n *Node) IsTagged() bool {
  415. return len(n.Tags) > 0
  416. }
  417. // SharerOrUser Sharer if set, else User.
  418. func (n *Node) SharerOrUser() UserID {
  419. return cmpx.Or(n.Sharer, n.User)
  420. }
  421. // IsTagged reports whether the node has any tags.
  422. func (n NodeView) IsTagged() bool { return n.ж.IsTagged() }
  423. // DisplayName wraps Node.DisplayName.
  424. func (n NodeView) DisplayName(forOwner bool) string { return n.ж.DisplayName(forOwner) }
  425. // SharerOrUser wraps Node.SharerOrUser.
  426. func (n NodeView) SharerOrUser() UserID { return n.ж.SharerOrUser() }
  427. // InitDisplayNames computes and populates n's display name
  428. // fields: n.ComputedName, n.computedHostIfDifferent, and
  429. // n.ComputedNameWithHost.
  430. func (n *Node) InitDisplayNames(networkMagicDNSSuffix string) {
  431. name := dnsname.TrimSuffix(n.Name, networkMagicDNSSuffix)
  432. var hostIfDifferent string
  433. if n.Hostinfo.Valid() {
  434. hostIfDifferent = dnsname.SanitizeHostname(n.Hostinfo.Hostname())
  435. }
  436. if strings.EqualFold(name, hostIfDifferent) {
  437. hostIfDifferent = ""
  438. }
  439. if name == "" {
  440. if hostIfDifferent != "" {
  441. name = hostIfDifferent
  442. hostIfDifferent = ""
  443. } else {
  444. name = n.Key.String()
  445. }
  446. }
  447. var nameWithHost string
  448. if hostIfDifferent != "" {
  449. nameWithHost = fmt.Sprintf("%s (%s)", name, hostIfDifferent)
  450. } else {
  451. nameWithHost = name
  452. }
  453. n.ComputedName = name
  454. n.computedHostIfDifferent = hostIfDifferent
  455. n.ComputedNameWithHost = nameWithHost
  456. }
  457. type MachineStatus int
  458. const (
  459. MachineUnknown = MachineStatus(iota)
  460. MachineUnauthorized // server has yet to approve
  461. MachineAuthorized // server has approved
  462. MachineInvalid // server has explicitly rejected this machine key
  463. )
  464. func (m MachineStatus) AppendText(b []byte) ([]byte, error) {
  465. return append(b, m.String()...), nil
  466. }
  467. func (m MachineStatus) MarshalText() ([]byte, error) {
  468. return []byte(m.String()), nil
  469. }
  470. func (m *MachineStatus) UnmarshalText(b []byte) error {
  471. switch string(b) {
  472. case "machine-unknown":
  473. *m = MachineUnknown
  474. case "machine-unauthorized":
  475. *m = MachineUnauthorized
  476. case "machine-authorized":
  477. *m = MachineAuthorized
  478. case "machine-invalid":
  479. *m = MachineInvalid
  480. default:
  481. var val int
  482. if _, err := fmt.Sscanf(string(b), "machine-unknown(%d)", &val); err != nil {
  483. *m = MachineStatus(val)
  484. } else {
  485. *m = MachineUnknown
  486. }
  487. }
  488. return nil
  489. }
  490. func (m MachineStatus) String() string {
  491. switch m {
  492. case MachineUnknown:
  493. return "machine-unknown"
  494. case MachineUnauthorized:
  495. return "machine-unauthorized"
  496. case MachineAuthorized:
  497. return "machine-authorized"
  498. case MachineInvalid:
  499. return "machine-invalid"
  500. default:
  501. return fmt.Sprintf("machine-unknown(%d)", int(m))
  502. }
  503. }
  504. func isNum(b byte) bool {
  505. return b >= '0' && b <= '9'
  506. }
  507. func isAlpha(b byte) bool {
  508. return (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z')
  509. }
  510. // CheckTag validates tag for use as an ACL tag.
  511. // For now we allow only ascii alphanumeric tags, and they need to start
  512. // with a letter. No unicode shenanigans allowed, and we reserve punctuation
  513. // marks other than '-' for a possible future URI scheme.
  514. //
  515. // Because we're ignoring unicode entirely, we can treat utf-8 as a series of
  516. // bytes. Anything >= 128 is disqualified anyway.
  517. //
  518. // We might relax these rules later.
  519. func CheckTag(tag string) error {
  520. if !strings.HasPrefix(tag, "tag:") {
  521. return errors.New("tags must start with 'tag:'")
  522. }
  523. tag = tag[4:]
  524. if tag == "" {
  525. return errors.New("tag names must not be empty")
  526. }
  527. if !isAlpha(tag[0]) {
  528. return errors.New("tag names must start with a letter, after 'tag:'")
  529. }
  530. for _, b := range []byte(tag) {
  531. if !isNum(b) && !isAlpha(b) && b != '-' {
  532. return errors.New("tag names can only contain numbers, letters, or dashes")
  533. }
  534. }
  535. return nil
  536. }
  537. // CheckRequestTags checks that all of h.RequestTags are valid.
  538. func (h *Hostinfo) CheckRequestTags() error {
  539. if h == nil {
  540. return nil
  541. }
  542. for _, tag := range h.RequestTags {
  543. if err := CheckTag(tag); err != nil {
  544. return fmt.Errorf("tag(%#v): %w", tag, err)
  545. }
  546. }
  547. return nil
  548. }
  549. // ServiceProto is a service type. It's usually
  550. // TCP ("tcp") or UDP ("udp"), but it can also have
  551. // meta service values as defined in Service.Proto.
  552. type ServiceProto string
  553. const (
  554. TCP = ServiceProto("tcp")
  555. UDP = ServiceProto("udp")
  556. PeerAPI4 = ServiceProto("peerapi4")
  557. PeerAPI6 = ServiceProto("peerapi6")
  558. PeerAPIDNS = ServiceProto("peerapi-dns-proxy")
  559. )
  560. // Service represents a service running on a node.
  561. type Service struct {
  562. _ structs.Incomparable
  563. // Proto is the type of service. It's usually the constant TCP
  564. // or UDP ("tcp" or "udp"), but it can also be one of the
  565. // following meta service values:
  566. //
  567. // * "peerapi4": peerapi is available on IPv4; Port is the
  568. // port number that the peerapi is running on the
  569. // node's Tailscale IPv4 address.
  570. // * "peerapi6": peerapi is available on IPv6; Port is the
  571. // port number that the peerapi is running on the
  572. // node's Tailscale IPv6 address.
  573. // * "peerapi-dns-proxy": the local peerapi service supports
  574. // being a DNS proxy (when the node is an exit
  575. // node). For this service, the Port number is really
  576. // the version number of the service.
  577. Proto ServiceProto
  578. // Port is the port number.
  579. //
  580. // For Proto "peerapi-dns", it's the version number of the DNS proxy,
  581. // currently 1.
  582. Port uint16
  583. // Description is the textual description of the service,
  584. // usually the process name that's running.
  585. Description string `json:",omitempty"`
  586. // TODO(apenwarr): allow advertising services on subnet IPs?
  587. // TODO(apenwarr): add "tags" here for each service?
  588. }
  589. // Location represents geographical location data about a
  590. // Tailscale host. Location is optional and only set if
  591. // explicitly declared by a node.
  592. type Location struct {
  593. Country string `json:",omitempty"` // User friendly country name, with proper capitalization ("Canada")
  594. CountryCode string `json:",omitempty"` // ISO 3166-1 alpha-2 in upper case ("CA")
  595. City string `json:",omitempty"` // User friendly city name, with proper capitalization ("Squamish")
  596. // CityCode is a short code representing the city in upper case.
  597. // CityCode is used to disambiguate a city from another location
  598. // with the same city name. It uniquely identifies a particular
  599. // geographical location, within the tailnet.
  600. // IATA, ICAO or ISO 3166-2 codes are recommended ("YSE")
  601. CityCode string `json:",omitempty"`
  602. // Priority determines the order of use of an exit node when a
  603. // location based preference matches more than one exit node,
  604. // the node with the highest priority wins. Nodes of equal
  605. // probability may be selected arbitrarily.
  606. //
  607. // A value of 0 means the exit node does not have a priority
  608. // preference. A negative int is not allowed.
  609. Priority int `json:",omitempty"`
  610. }
  611. // Hostinfo contains a summary of a Tailscale host.
  612. //
  613. // Because it contains pointers (slices), this type should not be used
  614. // as a value type.
  615. type Hostinfo struct {
  616. IPNVersion string `json:",omitempty"` // version of this code (in version.Long format)
  617. FrontendLogID string `json:",omitempty"` // logtail ID of frontend instance
  618. BackendLogID string `json:",omitempty"` // logtail ID of backend instance
  619. OS string `json:",omitempty"` // operating system the client runs on (a version.OS value)
  620. // OSVersion is the version of the OS, if available.
  621. //
  622. // For Android, it's like "10", "11", "12", etc. For iOS and macOS it's like
  623. // "15.6.1" or "12.4.0". For Windows it's like "10.0.19044.1889". For
  624. // FreeBSD it's like "12.3-STABLE".
  625. //
  626. // For Linux, prior to Tailscale 1.32, we jammed a bunch of fields into this
  627. // string on Linux, like "Debian 10.4; kernel=xxx; container; env=kn" and so
  628. // on. As of Tailscale 1.32, this is simply the kernel version on Linux, like
  629. // "5.10.0-17-amd64".
  630. OSVersion string `json:",omitempty"`
  631. Container opt.Bool `json:",omitempty"` // whether the client is running in a container
  632. Env string `json:",omitempty"` // a hostinfo.EnvType in string form
  633. Distro string `json:",omitempty"` // "debian", "ubuntu", "nixos", ...
  634. DistroVersion string `json:",omitempty"` // "20.04", ...
  635. DistroCodeName string `json:",omitempty"` // "jammy", "bullseye", ...
  636. // App is used to disambiguate Tailscale clients that run using tsnet.
  637. App string `json:",omitempty"` // "k8s-operator", "golinks", ...
  638. Desktop opt.Bool `json:",omitempty"` // if a desktop was detected on Linux
  639. Package string `json:",omitempty"` // Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown)
  640. DeviceModel string `json:",omitempty"` // mobile phone model ("Pixel 3a", "iPhone12,3")
  641. PushDeviceToken string `json:",omitempty"` // macOS/iOS APNs device token for notifications (and Android in the future)
  642. Hostname string `json:",omitempty"` // name of the host the client runs on
  643. ShieldsUp bool `json:",omitempty"` // indicates whether the host is blocking incoming connections
  644. ShareeNode bool `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user
  645. NoLogsNoSupport bool `json:",omitempty"` // indicates that the user has opted out of sending logs and support
  646. WireIngress bool `json:",omitempty"` // indicates that the node wants the option to receive ingress connections
  647. AllowsUpdate bool `json:",omitempty"` // indicates that the node has opted-in to admin-console-drive remote updates
  648. Machine string `json:",omitempty"` // the current host's machine type (uname -m)
  649. GoArch string `json:",omitempty"` // GOARCH value (of the built binary)
  650. GoArchVar string `json:",omitempty"` // GOARM, GOAMD64, etc (of the built binary)
  651. GoVersion string `json:",omitempty"` // Go version binary was built with
  652. RoutableIPs []netip.Prefix `json:",omitempty"` // set of IP ranges this client can route
  653. RequestTags []string `json:",omitempty"` // set of ACL tags this node wants to claim
  654. WoLMACs []string `json:",omitempty"` // MAC address(es) to send Wake-on-LAN packets to wake this node (lowercase hex w/ colons)
  655. Services []Service `json:",omitempty"` // services advertised by this machine
  656. NetInfo *NetInfo `json:",omitempty"`
  657. SSH_HostKeys []string `json:"sshHostKeys,omitempty"` // if advertised
  658. Cloud string `json:",omitempty"`
  659. Userspace opt.Bool `json:",omitempty"` // if the client is running in userspace (netstack) mode
  660. UserspaceRouter opt.Bool `json:",omitempty"` // if the client's subnet router is running in userspace (netstack) mode
  661. AppConnector opt.Bool `json:",omitempty"` // if the client is running the app-connector service
  662. // Location represents geographical location data about a
  663. // Tailscale host. Location is optional and only set if
  664. // explicitly declared by a node.
  665. Location *Location `json:",omitempty"`
  666. // NOTE: any new fields containing pointers in this type
  667. // require changes to Hostinfo.Equal.
  668. }
  669. // TailscaleSSHEnabled reports whether or not this node is acting as a
  670. // Tailscale SSH server.
  671. func (hi *Hostinfo) TailscaleSSHEnabled() bool {
  672. // Currently, we use `SSH_HostKeys` as a proxy for this. However, we may later
  673. // include non-Tailscale host keys, and will add a separate flag to rely on.
  674. return hi != nil && len(hi.SSH_HostKeys) > 0
  675. }
  676. func (v HostinfoView) TailscaleSSHEnabled() bool { return v.ж.TailscaleSSHEnabled() }
  677. // TailscaleFunnelEnabled reports whether or not this node has explicitly
  678. // enabled Funnel.
  679. func (hi *Hostinfo) TailscaleFunnelEnabled() bool {
  680. return hi != nil && hi.WireIngress
  681. }
  682. func (v HostinfoView) TailscaleFunnelEnabled() bool { return v.ж.TailscaleFunnelEnabled() }
  683. // NetInfo contains information about the host's network state.
  684. type NetInfo struct {
  685. // MappingVariesByDestIP says whether the host's NAT mappings
  686. // vary based on the destination IP.
  687. MappingVariesByDestIP opt.Bool
  688. // HairPinning is their router does hairpinning.
  689. // It reports true even if there's no NAT involved.
  690. HairPinning opt.Bool
  691. // WorkingIPv6 is whether the host has IPv6 internet connectivity.
  692. WorkingIPv6 opt.Bool
  693. // OSHasIPv6 is whether the OS supports IPv6 at all, regardless of
  694. // whether IPv6 internet connectivity is available.
  695. OSHasIPv6 opt.Bool
  696. // WorkingUDP is whether the host has UDP internet connectivity.
  697. WorkingUDP opt.Bool
  698. // WorkingICMPv4 is whether ICMPv4 works.
  699. // Empty means not checked.
  700. WorkingICMPv4 opt.Bool
  701. // HavePortMap is whether we have an existing portmap open
  702. // (UPnP, PMP, or PCP).
  703. HavePortMap bool `json:",omitempty"`
  704. // UPnP is whether UPnP appears present on the LAN.
  705. // Empty means not checked.
  706. UPnP opt.Bool
  707. // PMP is whether NAT-PMP appears present on the LAN.
  708. // Empty means not checked.
  709. PMP opt.Bool
  710. // PCP is whether PCP appears present on the LAN.
  711. // Empty means not checked.
  712. PCP opt.Bool
  713. // PreferredDERP is this node's preferred (home) DERP region ID.
  714. // This is where the node expects to be contacted to begin a
  715. // peer-to-peer connection. The node might be be temporarily
  716. // connected to multiple DERP servers (to speak to other nodes
  717. // that are located elsewhere) but PreferredDERP is the region ID
  718. // that the node subscribes to traffic at.
  719. // Zero means disconnected or unknown.
  720. PreferredDERP int
  721. // LinkType is the current link type, if known.
  722. LinkType string `json:",omitempty"` // "wired", "wifi", "mobile" (LTE, 4G, 3G, etc)
  723. // DERPLatency is the fastest recent time to reach various
  724. // DERP STUN servers, in seconds. The map key is the
  725. // "regionID-v4" or "-v6"; it was previously the DERP server's
  726. // STUN host:port.
  727. //
  728. // This should only be updated rarely, or when there's a
  729. // material change, as any change here also gets uploaded to
  730. // the control plane.
  731. DERPLatency map[string]float64 `json:",omitempty"`
  732. // FirewallMode encodes both which firewall mode was selected and why.
  733. // It is Linux-specific (at least as of 2023-08-19) and is meant to help
  734. // debug iptables-vs-nftables issues. The string is of the form
  735. // "{nft,ift}-REASON", like "nft-forced" or "ipt-default". Empty means
  736. // either not Linux or a configuration in which the host firewall rules
  737. // are not managed by tailscaled.
  738. FirewallMode string `json:",omitempty"`
  739. // Update BasicallyEqual when adding fields.
  740. }
  741. func (ni *NetInfo) String() string {
  742. if ni == nil {
  743. return "NetInfo(nil)"
  744. }
  745. return fmt.Sprintf("NetInfo{varies=%v hairpin=%v ipv6=%v ipv6os=%v udp=%v icmpv4=%v derp=#%v portmap=%v link=%q firewallmode=%q}",
  746. ni.MappingVariesByDestIP, ni.HairPinning, ni.WorkingIPv6,
  747. ni.OSHasIPv6, ni.WorkingUDP, ni.WorkingICMPv4,
  748. ni.PreferredDERP, ni.portMapSummary(), ni.LinkType, ni.FirewallMode)
  749. }
  750. func (ni *NetInfo) portMapSummary() string {
  751. if !ni.HavePortMap && ni.UPnP == "" && ni.PMP == "" && ni.PCP == "" {
  752. return "?"
  753. }
  754. var prefix string
  755. if ni.HavePortMap {
  756. prefix = "active-"
  757. }
  758. return prefix + conciseOptBool(ni.UPnP, "U") + conciseOptBool(ni.PMP, "M") + conciseOptBool(ni.PCP, "C")
  759. }
  760. func conciseOptBool(b opt.Bool, trueVal string) string {
  761. if b == "" {
  762. return "_"
  763. }
  764. v, ok := b.Get()
  765. if !ok {
  766. return "x"
  767. }
  768. if v {
  769. return trueVal
  770. }
  771. return ""
  772. }
  773. // BasicallyEqual reports whether ni and ni2 are basically equal, ignoring
  774. // changes in DERP ServerLatency & RegionLatency.
  775. func (ni *NetInfo) BasicallyEqual(ni2 *NetInfo) bool {
  776. if (ni == nil) != (ni2 == nil) {
  777. return false
  778. }
  779. if ni == nil {
  780. return true
  781. }
  782. return ni.MappingVariesByDestIP == ni2.MappingVariesByDestIP &&
  783. ni.HairPinning == ni2.HairPinning &&
  784. ni.WorkingIPv6 == ni2.WorkingIPv6 &&
  785. ni.OSHasIPv6 == ni2.OSHasIPv6 &&
  786. ni.WorkingUDP == ni2.WorkingUDP &&
  787. ni.WorkingICMPv4 == ni2.WorkingICMPv4 &&
  788. ni.HavePortMap == ni2.HavePortMap &&
  789. ni.UPnP == ni2.UPnP &&
  790. ni.PMP == ni2.PMP &&
  791. ni.PCP == ni2.PCP &&
  792. ni.PreferredDERP == ni2.PreferredDERP &&
  793. ni.LinkType == ni2.LinkType &&
  794. ni.FirewallMode == ni2.FirewallMode
  795. }
  796. // Equal reports whether h and h2 are equal.
  797. func (h *Hostinfo) Equal(h2 *Hostinfo) bool {
  798. if h == nil && h2 == nil {
  799. return true
  800. }
  801. if (h == nil) != (h2 == nil) {
  802. return false
  803. }
  804. return reflect.DeepEqual(h, h2)
  805. }
  806. // HowUnequal returns a list of paths through Hostinfo where h and h2 differ.
  807. // If they differ in nil-ness, the path is "nil", otherwise the path is like
  808. // "ShieldsUp" or "NetInfo.nil" or "NetInfo.PCP".
  809. func (h *Hostinfo) HowUnequal(h2 *Hostinfo) (path []string) {
  810. return appendStructPtrDiff(nil, "", reflect.ValueOf(h), reflect.ValueOf(h2))
  811. }
  812. func appendStructPtrDiff(base []string, pfx string, p1, p2 reflect.Value) (ret []string) {
  813. ret = base
  814. if p1.IsNil() && p2.IsNil() {
  815. return base
  816. }
  817. mkPath := func(b string) string {
  818. if pfx == "" {
  819. return b
  820. }
  821. return pfx + "." + b
  822. }
  823. if p1.IsNil() || p2.IsNil() {
  824. return append(base, mkPath("nil"))
  825. }
  826. v1, v2 := p1.Elem(), p2.Elem()
  827. t := v1.Type()
  828. for i, n := 0, t.NumField(); i < n; i++ {
  829. sf := t.Field(i)
  830. switch sf.Type.Kind() {
  831. case reflect.String:
  832. if v1.Field(i).String() != v2.Field(i).String() {
  833. ret = append(ret, mkPath(sf.Name))
  834. }
  835. continue
  836. case reflect.Bool:
  837. if v1.Field(i).Bool() != v2.Field(i).Bool() {
  838. ret = append(ret, mkPath(sf.Name))
  839. }
  840. continue
  841. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  842. if v1.Field(i).Int() != v2.Field(i).Int() {
  843. ret = append(ret, mkPath(sf.Name))
  844. }
  845. continue
  846. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  847. if v1.Field(i).Uint() != v2.Field(i).Uint() {
  848. ret = append(ret, mkPath(sf.Name))
  849. }
  850. continue
  851. case reflect.Slice, reflect.Map:
  852. if !reflect.DeepEqual(v1.Field(i).Interface(), v2.Field(i).Interface()) {
  853. ret = append(ret, mkPath(sf.Name))
  854. }
  855. continue
  856. case reflect.Ptr:
  857. if sf.Type.Elem().Kind() == reflect.Struct {
  858. ret = appendStructPtrDiff(ret, sf.Name, v1.Field(i), v2.Field(i))
  859. continue
  860. }
  861. }
  862. panic(fmt.Sprintf("unsupported type at %s: %s", mkPath(sf.Name), sf.Type.String()))
  863. }
  864. return ret
  865. }
  866. // SignatureType specifies a scheme for signing RegisterRequest messages. It
  867. // specifies the crypto algorithms to use, the contents of what is signed, and
  868. // any other relevant details. Historically, requests were unsigned so the zero
  869. // value is SignatureNone.
  870. type SignatureType int
  871. const (
  872. // SignatureNone indicates that there is no signature, no Timestamp is
  873. // required (but may be specified if desired), and both DeviceCert and
  874. // Signature should be empty.
  875. SignatureNone = SignatureType(iota)
  876. // SignatureUnknown represents an unknown signature scheme, which should
  877. // be considered an error if seen.
  878. SignatureUnknown
  879. // SignatureV1 is computed as RSA-PSS-Sign(privateKeyForDeviceCert,
  880. // SHA256(Timestamp || ServerIdentity || DeviceCert || ServerShortPubKey ||
  881. // MachineShortPubKey)). The PSS salt length is equal to hash length
  882. // (rsa.PSSSaltLengthEqualsHash). Device cert is required.
  883. // Deprecated: uses old key serialization format.
  884. SignatureV1
  885. // SignatureV2 is computed as RSA-PSS-Sign(privateKeyForDeviceCert,
  886. // SHA256(Timestamp || ServerIdentity || DeviceCert || ServerPubKey ||
  887. // MachinePubKey)). The PSS salt length is equal to hash length
  888. // (rsa.PSSSaltLengthEqualsHash). Device cert is required.
  889. SignatureV2
  890. )
  891. func (st SignatureType) AppendText(b []byte) ([]byte, error) {
  892. return append(b, st.String()...), nil
  893. }
  894. func (st SignatureType) MarshalText() ([]byte, error) {
  895. return []byte(st.String()), nil
  896. }
  897. func (st *SignatureType) UnmarshalText(b []byte) error {
  898. switch string(b) {
  899. case "signature-none":
  900. *st = SignatureNone
  901. case "signature-v1":
  902. *st = SignatureV1
  903. case "signature-v2":
  904. *st = SignatureV2
  905. default:
  906. var val int
  907. if _, err := fmt.Sscanf(string(b), "signature-unknown(%d)", &val); err != nil {
  908. *st = SignatureType(val)
  909. } else {
  910. *st = SignatureUnknown
  911. }
  912. }
  913. return nil
  914. }
  915. func (st SignatureType) String() string {
  916. switch st {
  917. case SignatureNone:
  918. return "signature-none"
  919. case SignatureUnknown:
  920. return "signature-unknown"
  921. case SignatureV1:
  922. return "signature-v1"
  923. case SignatureV2:
  924. return "signature-v2"
  925. default:
  926. return fmt.Sprintf("signature-unknown(%d)", int(st))
  927. }
  928. }
  929. // RegisterResponseAuth is the authentication information returned by the server
  930. // in response to a RegisterRequest.
  931. type RegisterResponseAuth struct {
  932. _ structs.Incomparable
  933. // One of Provider/LoginName, Oauth2Token, or AuthKey is set.
  934. Provider, LoginName string
  935. Oauth2Token *Oauth2Token
  936. AuthKey string
  937. }
  938. // RegisterRequest is sent by a client to register the key for a node.
  939. // It is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box,
  940. // using the local machine key, and sent to:
  941. //
  942. // https://login.tailscale.com/machine/<mkey hex>
  943. type RegisterRequest struct {
  944. _ structs.Incomparable
  945. // Version is the client's capabilities when using the Noise
  946. // transport.
  947. //
  948. // When using the original nacl crypto_box transport, the
  949. // value must be 1.
  950. Version CapabilityVersion
  951. NodeKey key.NodePublic
  952. OldNodeKey key.NodePublic
  953. NLKey key.NLPublic
  954. Auth RegisterResponseAuth
  955. // Expiry optionally specifies the requested key expiry.
  956. // The server policy may override.
  957. // As a special case, if Expiry is in the past and NodeKey is
  958. // the node's current key, the key is expired.
  959. Expiry time.Time
  960. Followup string // response waits until AuthURL is visited
  961. Hostinfo *Hostinfo
  962. // Ephemeral is whether the client is requesting that this
  963. // node be considered ephemeral and be automatically deleted
  964. // when it stops being active.
  965. Ephemeral bool `json:",omitempty"`
  966. // NodeKeySignature is the node's own node-key signature, re-signed
  967. // for its new node key using its network-lock key.
  968. //
  969. // This field is set when the client retries registration after learning
  970. // its NodeKeySignature (which is in need of rotation).
  971. NodeKeySignature tkatype.MarshaledSignature
  972. // The following fields are not used for SignatureNone and are required for
  973. // SignatureV1:
  974. SignatureType SignatureType `json:",omitempty"`
  975. Timestamp *time.Time `json:",omitempty"` // creation time of request to prevent replay
  976. DeviceCert []byte `json:",omitempty"` // X.509 certificate for client device
  977. Signature []byte `json:",omitempty"` // as described by SignatureType
  978. // Tailnet is an optional identifier specifying the name of the recommended or required
  979. // network that the node should join. Its exact form should not be depended on; new
  980. // forms are coming later. The identifier is generally a domain name (for an organization)
  981. // or e-mail address (for a personal account on a shared e-mail provider). It is the same name
  982. // used by the API, as described in /api.md#tailnet.
  983. // If Tailnet begins with the prefix "required:" then the server should prevent logging in to a different
  984. // network than the one specified. Otherwise, the server should recommend the specified network
  985. // but still permit logging in to other networks.
  986. // If empty, no recommendation is offered to the server and the login page should show all options.
  987. Tailnet string `json:",omitempty"`
  988. }
  989. // RegisterResponse is returned by the server in response to a RegisterRequest.
  990. type RegisterResponse struct {
  991. User User
  992. Login Login
  993. NodeKeyExpired bool // if true, the NodeKey needs to be replaced
  994. MachineAuthorized bool // TODO(crawshaw): move to using MachineStatus
  995. AuthURL string // if set, authorization pending
  996. // If set, this is the current node-key signature that needs to be
  997. // re-signed for the node's new node-key.
  998. NodeKeySignature tkatype.MarshaledSignature
  999. // Error indicates that authorization failed. If this is non-empty,
  1000. // other status fields should be ignored.
  1001. Error string
  1002. }
  1003. // EndpointType distinguishes different sources of MapRequest.Endpoint values.
  1004. type EndpointType int
  1005. const (
  1006. EndpointUnknownType = EndpointType(0)
  1007. EndpointLocal = EndpointType(1)
  1008. EndpointSTUN = EndpointType(2)
  1009. EndpointPortmapped = EndpointType(3)
  1010. EndpointSTUN4LocalPort = EndpointType(4) // hard NAT: STUN'ed IPv4 address + local fixed port
  1011. )
  1012. func (et EndpointType) String() string {
  1013. switch et {
  1014. case EndpointUnknownType:
  1015. return "?"
  1016. case EndpointLocal:
  1017. return "local"
  1018. case EndpointSTUN:
  1019. return "stun"
  1020. case EndpointPortmapped:
  1021. return "portmap"
  1022. case EndpointSTUN4LocalPort:
  1023. return "stun4localport"
  1024. }
  1025. return "other"
  1026. }
  1027. // Endpoint is an endpoint IPPort and an associated type.
  1028. // It doesn't currently go over the wire as is but is instead
  1029. // broken up into two parallel slices in MapRequest, for compatibility
  1030. // reasons. But this type is used in the codebase.
  1031. type Endpoint struct {
  1032. Addr netip.AddrPort
  1033. Type EndpointType
  1034. }
  1035. // MapRequest is sent by a client to either update the control plane
  1036. // about its current state, or to start a long-poll of network map updates.
  1037. //
  1038. // The request includes a copy of the client's current set of WireGuard
  1039. // endpoints and general host information.
  1040. //
  1041. // The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box,
  1042. // using the local machine key, and sent to:
  1043. //
  1044. // https://login.tailscale.com/machine/<mkey hex>/map
  1045. type MapRequest struct {
  1046. // Version is incremented whenever the client code changes enough that
  1047. // we want to signal to the control server that we're capable of something
  1048. // different.
  1049. //
  1050. // For current values and history, see the CapabilityVersion type's docs.
  1051. Version CapabilityVersion
  1052. Compress string // "zstd" or "" (no compression)
  1053. KeepAlive bool // whether server should send keep-alives back to us
  1054. NodeKey key.NodePublic
  1055. DiscoKey key.DiscoPublic
  1056. // Stream is whether the client wants to receive multiple MapResponses over
  1057. // the same HTTP connection.
  1058. //
  1059. // If false, the server will send a single MapResponse and then close the
  1060. // connection.
  1061. //
  1062. // If true and Version >= 68, the server should treat this as a read-only
  1063. // request and ignore any Hostinfo or other fields that might be set.
  1064. Stream bool
  1065. // Hostinfo is the client's current Hostinfo. Although it is always included
  1066. // in the request, the server may choose to ignore it when Stream is true
  1067. // and Version >= 68.
  1068. Hostinfo *Hostinfo
  1069. // MapSessionHandle, if non-empty, is a request to reattach to a previous
  1070. // map session after a previous map session was interrupted for whatever
  1071. // reason. Its value is an opaque string as returned by
  1072. // MapResponse.MapSessionHandle.
  1073. //
  1074. // When set, the client must also send MapSessionSeq to specify the last
  1075. // processed message in that prior session.
  1076. //
  1077. // The server may choose to ignore the request for any reason and start a
  1078. // new map session. This is only applicable when Stream is true.
  1079. MapSessionHandle string `json:",omitempty"`
  1080. // MapSessionSeq is the sequence number in the map session identified by
  1081. // MapSesssionHandle that was most recently processed by the client.
  1082. // It is only applicable when MapSessionHandle is specified.
  1083. // If the server chooses to honor the MapSessionHandle request, only sequence
  1084. // numbers greater than this value will be returned.
  1085. MapSessionSeq int64 `json:",omitempty"`
  1086. // Endpoints are the client's magicsock UDP ip:port endpoints (IPv4 or IPv6).
  1087. // These can be ignored if Stream is true and Version >= 68.
  1088. Endpoints []netip.AddrPort `json:",omitempty"`
  1089. // EndpointTypes are the types of the corresponding endpoints in Endpoints.
  1090. EndpointTypes []EndpointType `json:",omitempty"`
  1091. // TKAHead describes the hash of the latest AUM applied to the local
  1092. // tailnet key authority, if one is operating.
  1093. // It is encoded as tka.AUMHash.MarshalText.
  1094. TKAHead string `json:",omitempty"`
  1095. // ReadOnly was set when client just wanted to fetch the MapResponse,
  1096. // without updating their Endpoints. The intended use was for clients to
  1097. // discover the DERP map at start-up before their first real endpoint
  1098. // update.
  1099. //
  1100. // Deprecated: always false as of Version 68.
  1101. ReadOnly bool `json:",omitempty"`
  1102. // OmitPeers is whether the client is okay with the Peers list being omitted
  1103. // in the response.
  1104. //
  1105. // The behavior of OmitPeers being true varies based on Stream and ReadOnly:
  1106. //
  1107. // If OmitPeers is true, Stream is false, and ReadOnly is false,
  1108. // then the server will let clients update their endpoints without
  1109. // breaking existing long-polling (Stream == true) connections.
  1110. // In this case, the server can omit the entire response; the client
  1111. // only checks the HTTP response status code.
  1112. //
  1113. // If OmitPeers is true, Stream is false, but ReadOnly is true,
  1114. // then all the response fields are included. (This is what the client does
  1115. // when initially fetching the DERP map.)
  1116. OmitPeers bool `json:",omitempty"`
  1117. // DebugFlags is a list of strings specifying debugging and
  1118. // development features to enable in handling this map
  1119. // request. The values are deliberately unspecified, as they get
  1120. // added and removed all the time during development, and offer no
  1121. // compatibility promise. To roll out semantic changes, bump
  1122. // Version instead.
  1123. //
  1124. // Current DebugFlags values are:
  1125. // * "warn-ip-forwarding-off": client is trying to be a subnet
  1126. // router but their IP forwarding is broken.
  1127. // * "warn-router-unhealthy": client's Router implementation is
  1128. // having problems.
  1129. DebugFlags []string `json:",omitempty"`
  1130. }
  1131. // PortRange represents a range of UDP or TCP port numbers.
  1132. type PortRange struct {
  1133. First uint16
  1134. Last uint16
  1135. }
  1136. // Contains reports whether port is in pr.
  1137. func (pr PortRange) Contains(port uint16) bool {
  1138. return port >= pr.First && port <= pr.Last
  1139. }
  1140. var PortRangeAny = PortRange{0, 65535}
  1141. // NetPortRange represents a range of ports that's allowed for one or more IPs.
  1142. type NetPortRange struct {
  1143. _ structs.Incomparable
  1144. IP string // IP, CIDR, Range, or "*" (same formats as FilterRule.SrcIPs)
  1145. Bits *int // deprecated; the old way to turn IP into a CIDR
  1146. Ports PortRange
  1147. }
  1148. // CapGrant grants capabilities in a FilterRule.
  1149. type CapGrant struct {
  1150. // Dsts are the destination IP ranges that this capability
  1151. // grant matches.
  1152. Dsts []netip.Prefix
  1153. // Caps are the capabilities the source IP matched by
  1154. // FilterRule.SrcIPs are granted to the destination IP,
  1155. // matched by Dsts.
  1156. // Deprecated: use CapMap instead.
  1157. Caps []PeerCapability `json:",omitempty"`
  1158. // CapMap is a map of capabilities to their values.
  1159. // The key is the capability name, and the value is a list of
  1160. // values for that capability.
  1161. CapMap PeerCapMap `json:",omitempty"`
  1162. }
  1163. // PeerCapability represents a capability granted to a peer by a FilterRule when
  1164. // the peer communicates with the node that has this rule. Its meaning is
  1165. // application-defined.
  1166. //
  1167. // It must be a URL like "https://tailscale.com/cap/file-send".
  1168. type PeerCapability string
  1169. const (
  1170. // PeerCapabilityFileSharingTarget grants the current node the ability to send
  1171. // files to the peer which has this capability.
  1172. PeerCapabilityFileSharingTarget PeerCapability = "https://tailscale.com/cap/file-sharing-target"
  1173. // PeerCapabilityFileSharingSend grants the ability to receive files from a
  1174. // node that's owned by a different user.
  1175. PeerCapabilityFileSharingSend PeerCapability = "https://tailscale.com/cap/file-send"
  1176. // PeerCapabilityDebugPeer grants the ability for a peer to read this node's
  1177. // goroutines, metrics, magicsock internal state, etc.
  1178. PeerCapabilityDebugPeer PeerCapability = "https://tailscale.com/cap/debug-peer"
  1179. // PeerCapabilityWakeOnLAN grants the ability to send a Wake-On-LAN packet.
  1180. PeerCapabilityWakeOnLAN PeerCapability = "https://tailscale.com/cap/wake-on-lan"
  1181. // PeerCapabilityIngress grants the ability for a peer to send ingress traffic.
  1182. PeerCapabilityIngress PeerCapability = "https://tailscale.com/cap/ingress"
  1183. // PeerCapabilityWebUI grants the ability for a peer to edit features from the
  1184. // device Web UI.
  1185. PeerCapabilityWebUI PeerCapability = "tailscale.com/cap/webui"
  1186. )
  1187. // NodeCapMap is a map of capabilities to their optional values. It is valid for
  1188. // a capability to have no values (nil slice); such capabilities can be tested
  1189. // for by using the Contains method.
  1190. //
  1191. // See [NodeCapability] for more information on keys.
  1192. type NodeCapMap map[NodeCapability][]RawMessage
  1193. // Equal reports whether c and c2 are equal.
  1194. func (c NodeCapMap) Equal(c2 NodeCapMap) bool {
  1195. return maps.EqualFunc(c, c2, slices.Equal)
  1196. }
  1197. // UnmarshalNodeCapJSON unmarshals each JSON value in cm[cap] as T.
  1198. // If cap does not exist in cm, it returns (nil, nil).
  1199. // It returns an error if the values cannot be unmarshaled into the provided type.
  1200. func UnmarshalNodeCapJSON[T any](cm NodeCapMap, cap NodeCapability) ([]T, error) {
  1201. vals, ok := cm[cap]
  1202. if !ok {
  1203. return nil, nil
  1204. }
  1205. out := make([]T, 0, len(vals))
  1206. for _, v := range vals {
  1207. var t T
  1208. if err := json.Unmarshal([]byte(v), &t); err != nil {
  1209. return nil, err
  1210. }
  1211. out = append(out, t)
  1212. }
  1213. return out, nil
  1214. }
  1215. // Contains reports whether c has the capability cap. This is used to test for
  1216. // the existence of a capability, especially when the capability has no
  1217. // associated argument/data values.
  1218. func (c NodeCapMap) Contains(cap NodeCapability) bool {
  1219. _, ok := c[cap]
  1220. return ok
  1221. }
  1222. // PeerCapMap is a map of capabilities to their optional values. It is valid for
  1223. // a capability to have no values (nil slice); such capabilities can be tested
  1224. // for by using the HasCapability method.
  1225. //
  1226. // The values are opaque to Tailscale, but are passed through from the ACLs to
  1227. // the application via the WhoIs API.
  1228. type PeerCapMap map[PeerCapability][]RawMessage
  1229. // UnmarshalCapJSON unmarshals each JSON value in cm[cap] as T.
  1230. // If cap does not exist in cm, it returns (nil, nil).
  1231. // It returns an error if the values cannot be unmarshaled into the provided type.
  1232. func UnmarshalCapJSON[T any](cm PeerCapMap, cap PeerCapability) ([]T, error) {
  1233. vals, ok := cm[cap]
  1234. if !ok {
  1235. return nil, nil
  1236. }
  1237. out := make([]T, 0, len(vals))
  1238. for _, v := range vals {
  1239. var t T
  1240. if err := json.Unmarshal([]byte(v), &t); err != nil {
  1241. return nil, err
  1242. }
  1243. out = append(out, t)
  1244. }
  1245. return out, nil
  1246. }
  1247. // HasCapability reports whether c has the capability cap. This is used to test
  1248. // for the existence of a capability, especially when the capability has no
  1249. // associated argument/data values.
  1250. func (c PeerCapMap) HasCapability(cap PeerCapability) bool {
  1251. _, ok := c[cap]
  1252. return ok
  1253. }
  1254. // FilterRule represents one rule in a packet filter.
  1255. //
  1256. // A rule is logically a set of source CIDRs to match (described by
  1257. // SrcIPs and SrcBits), and a set of destination targets that are then
  1258. // allowed if a source IP is matches of those CIDRs.
  1259. type FilterRule struct {
  1260. // SrcIPs are the source IPs/networks to match.
  1261. //
  1262. // It may take the following forms:
  1263. // * an IP address (IPv4 or IPv6)
  1264. // * the string "*" to match everything (both IPv4 & IPv6)
  1265. // * a CIDR (e.g. "192.168.0.0/16")
  1266. // * a range of two IPs, inclusive, separated by hyphen ("2eff::1-2eff::0800")
  1267. SrcIPs []string
  1268. // SrcBits is deprecated; it's the old way to specify a CIDR
  1269. // prior to CapabilityVersion 7. Its values correspond to the
  1270. // SrcIPs above.
  1271. //
  1272. // If an entry of SrcBits is present for the same index as a
  1273. // SrcIPs entry, it changes the SrcIP above to be a network
  1274. // with /n CIDR bits. If the slice is nil or insufficiently
  1275. // long, the default value (for an IPv4 address) for a
  1276. // position is 32, as if the SrcIPs above were a /32 mask. For
  1277. // a "*" SrcIPs value, the corresponding SrcBits value is
  1278. // ignored.
  1279. SrcBits []int `json:",omitempty"`
  1280. // DstPorts are the port ranges to allow once a source IP
  1281. // matches (is in the CIDR described by SrcIPs & SrcBits).
  1282. //
  1283. // CapGrant and DstPorts are mutually exclusive: at most one can be non-nil.
  1284. DstPorts []NetPortRange `json:",omitempty"`
  1285. // IPProto are the IP protocol numbers to match.
  1286. //
  1287. // As a special case, nil or empty means TCP, UDP, and ICMP.
  1288. //
  1289. // Numbers outside the uint8 range (below 0 or above 255) are
  1290. // reserved for Tailscale's use. Unknown ones are ignored.
  1291. //
  1292. // Depending on the IPProto values, DstPorts may or may not be
  1293. // used.
  1294. IPProto []int `json:",omitempty"`
  1295. // CapGrant, if non-empty, are the capabilities to
  1296. // conditionally grant to the source IP in SrcIPs.
  1297. //
  1298. // Think of DstPorts as "capabilities for networking" and
  1299. // CapGrant as arbitrary application-defined capabilities
  1300. // defined between the admin's ACLs and the application
  1301. // doing WhoIs lookups, looking up the remote IP address's
  1302. // application-level capabilities.
  1303. //
  1304. // CapGrant and DstPorts are mutually exclusive: at most one can be non-nil.
  1305. CapGrant []CapGrant `json:",omitempty"`
  1306. }
  1307. var FilterAllowAll = []FilterRule{
  1308. {
  1309. SrcIPs: []string{"*"},
  1310. SrcBits: nil,
  1311. DstPorts: []NetPortRange{{
  1312. IP: "*",
  1313. Bits: nil,
  1314. Ports: PortRange{0, 65535},
  1315. }},
  1316. },
  1317. }
  1318. // DNSConfig is the DNS configuration.
  1319. type DNSConfig struct {
  1320. // Resolvers are the DNS resolvers to use, in order of preference.
  1321. Resolvers []*dnstype.Resolver `json:",omitempty"`
  1322. // Routes maps DNS name suffixes to a set of DNS resolvers to
  1323. // use. It is used to implement "split DNS" and other advanced DNS
  1324. // routing overlays.
  1325. //
  1326. // Map keys are fully-qualified DNS name suffixes; they may
  1327. // optionally contain a trailing dot but no leading dot.
  1328. //
  1329. // If the value is an empty slice, that means the suffix should still
  1330. // be handled by Tailscale's built-in resolver (100.100.100.100), such
  1331. // as for the purpose of handling ExtraRecords.
  1332. Routes map[string][]*dnstype.Resolver `json:",omitempty"`
  1333. // FallbackResolvers is like Resolvers, but is only used if a
  1334. // split DNS configuration is requested in a configuration that
  1335. // doesn't work yet without explicit default resolvers.
  1336. // https://github.com/tailscale/tailscale/issues/1743
  1337. FallbackResolvers []*dnstype.Resolver `json:",omitempty"`
  1338. // Domains are the search domains to use.
  1339. // Search domains must be FQDNs, but *without* the trailing dot.
  1340. Domains []string `json:",omitempty"`
  1341. // Proxied turns on automatic resolution of hostnames for devices
  1342. // in the network map, aka MagicDNS.
  1343. // Despite the (legacy) name, does not necessarily cause request
  1344. // proxying to be enabled.
  1345. Proxied bool `json:",omitempty"`
  1346. // The following fields are only set and used by
  1347. // MapRequest.Version >=9 and <14.
  1348. // Nameservers are the IP addresses of the nameservers to use.
  1349. Nameservers []netip.Addr `json:",omitempty"`
  1350. // CertDomains are the set of DNS names for which the control
  1351. // plane server will assist with provisioning TLS
  1352. // certificates. See SetDNSRequest, which can be used to
  1353. // answer dns-01 ACME challenges for e.g. LetsEncrypt.
  1354. // These names are FQDNs without trailing periods, and without
  1355. // any "_acme-challenge." prefix.
  1356. CertDomains []string `json:",omitempty"`
  1357. // ExtraRecords contains extra DNS records to add to the
  1358. // MagicDNS config.
  1359. ExtraRecords []DNSRecord `json:",omitempty"`
  1360. // ExitNodeFilteredSuffixes are the DNS suffixes that the
  1361. // node, when being an exit node DNS proxy, should not answer.
  1362. //
  1363. // The entries do not contain trailing periods and are always
  1364. // all lowercase.
  1365. //
  1366. // If an entry starts with a period, it's a suffix match (but
  1367. // suffix ".a.b" doesn't match "a.b"; a prefix is required).
  1368. //
  1369. // If an entry does not start with a period, it's an exact
  1370. // match.
  1371. //
  1372. // Matches are case insensitive.
  1373. ExitNodeFilteredSet []string `json:",omitempty"`
  1374. // TempCorpIssue13969 is a temporary (2023-08-16) field for an internal hack day prototype.
  1375. // It contains a user inputed URL that should have a list of domains to be blocked.
  1376. // See https://github.com/tailscale/corp/issues/13969.
  1377. TempCorpIssue13969 string `json:",omitempty"`
  1378. }
  1379. // DNSRecord is an extra DNS record to add to MagicDNS.
  1380. type DNSRecord struct {
  1381. // Name is the fully qualified domain name of
  1382. // the record to add. The trailing dot is optional.
  1383. Name string
  1384. // Type is the DNS record type.
  1385. // Empty means A or AAAA, depending on value.
  1386. // Other values are currently ignored.
  1387. Type string `json:",omitempty"`
  1388. // Value is the IP address in string form.
  1389. // TODO(bradfitz): if we ever add support for record types
  1390. // with non-UTF8 binary data, add ValueBytes []byte that
  1391. // would take precedence.
  1392. Value string
  1393. }
  1394. // PingType is a string representing the kind of ping to perform.
  1395. type PingType string
  1396. const (
  1397. // PingDisco performs a ping, without involving IP at either end.
  1398. PingDisco PingType = "disco"
  1399. // PingTSMP performs a ping, using the IP layer, but avoiding the OS IP stack.
  1400. PingTSMP PingType = "TSMP"
  1401. // PingICMP performs a ping between two tailscale nodes using ICMP that is
  1402. // received by the target systems IP stack.
  1403. PingICMP PingType = "ICMP"
  1404. // PingPeerAPI performs a ping between two tailscale nodes using ICMP that is
  1405. // received by the target systems IP stack.
  1406. PingPeerAPI PingType = "peerapi"
  1407. )
  1408. // PingRequest with no IP and Types is a request to send an HTTP request to prove the
  1409. // long-polling client is still connected.
  1410. // PingRequest with Types and IP, will send a ping to the IP and send a POST
  1411. // request containing a PingResponse to the URL containing results.
  1412. type PingRequest struct {
  1413. // URL is the URL to reply to the PingRequest to.
  1414. // It will be a unique URL each time. No auth headers are necessary.
  1415. // If the client sees multiple PingRequests with the same URL,
  1416. // subsequent ones should be ignored.
  1417. //
  1418. // The HTTP method that the node should make back to URL depends on the other
  1419. // fields of the PingRequest. If Types is defined, then URL is the URL to
  1420. // send a POST request to. Otherwise, the node should just make a HEAD
  1421. // request to URL.
  1422. URL string
  1423. // URLIsNoise, if true, means that the client should hit URL over the Noise
  1424. // transport instead of TLS.
  1425. URLIsNoise bool `json:",omitempty"`
  1426. // Log is whether to log about this ping in the success case.
  1427. // For failure cases, the client will log regardless.
  1428. Log bool `json:",omitempty"`
  1429. // Types is the types of ping that are initiated. Can be any PingType, comma
  1430. // separated, e.g. "disco,TSMP"
  1431. //
  1432. // As a special case, if Types is "c2n", then this PingRequest is a
  1433. // client-to-node HTTP request. The HTTP request should be handled by this
  1434. // node's c2n handler and the HTTP response sent in a POST to URL. For c2n,
  1435. // the value of URLIsNoise is ignored and only the Noise transport (back to
  1436. // the control plane) will be used, as if URLIsNoise were true.
  1437. Types string `json:",omitempty"`
  1438. // IP is the ping target, when needed by the PingType(s) given in Types.
  1439. IP netip.Addr
  1440. // Payload is the ping payload.
  1441. //
  1442. // It is only used for c2n requests, in which case it's an HTTP/1.0 or
  1443. // HTTP/1.1-formatted HTTP request as parsable with http.ReadRequest.
  1444. Payload []byte `json:",omitempty"`
  1445. }
  1446. // PingResponse provides result information for a TSMP or Disco PingRequest.
  1447. // Typically populated from an ipnstate.PingResult used in `tailscale ping`.
  1448. type PingResponse struct {
  1449. Type PingType // ping type, such as TSMP or disco.
  1450. IP string `json:",omitempty"` // ping destination
  1451. NodeIP string `json:",omitempty"` // Tailscale IP of node handling IP (different for subnet routers)
  1452. NodeName string `json:",omitempty"` // DNS name base or (possibly not unique) hostname
  1453. // Err contains a short description of error conditions if the PingRequest
  1454. // could not be fulfilled for some reason.
  1455. // e.g. "100.1.2.3 is local Tailscale IP"
  1456. Err string `json:",omitempty"`
  1457. // LatencySeconds reports measurement of the round-trip time of a message to
  1458. // the requested target, if it could be determined. If LatencySeconds is
  1459. // omitted, Err should contain information as to the cause.
  1460. LatencySeconds float64 `json:",omitempty"`
  1461. // Endpoint is the ip:port if direct UDP was used.
  1462. // It is not currently set for TSMP pings.
  1463. Endpoint string `json:",omitempty"`
  1464. // DERPRegionID is non-zero DERP region ID if DERP was used.
  1465. // It is not currently set for TSMP pings.
  1466. DERPRegionID int `json:",omitempty"`
  1467. // DERPRegionCode is the three-letter region code
  1468. // corresponding to DERPRegionID.
  1469. // It is not currently set for TSMP pings.
  1470. DERPRegionCode string `json:",omitempty"`
  1471. // PeerAPIPort is set by TSMP ping responses for peers that
  1472. // are running a peerapi server. This is the port they're
  1473. // running the server on.
  1474. PeerAPIPort uint16 `json:",omitempty"`
  1475. // IsLocalIP is whether the ping request error is due to it being
  1476. // a ping to the local node.
  1477. IsLocalIP bool `json:",omitempty"`
  1478. }
  1479. // MapResponse is the response to a MapRequest. It describes the state of the
  1480. // local node, the peer nodes, the DNS configuration, the packet filter, and
  1481. // more. A MapRequest, depending on its parameters, may result in the control
  1482. // plane coordination server sending 0, 1 or a stream of multiple MapResponse
  1483. // values.
  1484. //
  1485. // When the client sets MapRequest.Stream, the server sends a stream of
  1486. // MapResponses. That long-lived HTTP transaction is called a "map poll". In a
  1487. // map poll, the first MapResponse will be complete and subsequent MapResponses
  1488. // will be incremental updates with only changed information.
  1489. //
  1490. // The zero value for all fields means "unchanged". Unfortunately, several
  1491. // fields were defined before that convention was established, so they use a
  1492. // slice with omitempty, meaning this type can't be used to marshal JSON
  1493. // containing non-nil zero-length slices (meaning explicitly now empty). The
  1494. // control plane uses a separate type to marshal these fields. This type is
  1495. // primarily used for unmarshaling responses so the omitempty annotations are
  1496. // mostly useless, except that this type is also used for the integration test's
  1497. // fake control server. (It's not necessary to marshal a non-nil zero-length
  1498. // slice for the things we've needed to test in the integration tests as of
  1499. // 2023-09-09).
  1500. type MapResponse struct {
  1501. // MapSessionHandle optionally specifies a unique opaque handle for this
  1502. // stateful MapResponse session. Servers may choose not to send it, and it's
  1503. // only sent on the first MapResponse in a stream. The client can determine
  1504. // whether it's reattaching to a prior stream by seeing whether this value
  1505. // matches the requested MapRequest.MapSessionHandle.
  1506. MapSessionHandle string `json:",omitempty"`
  1507. // Seq is a sequence number within a named map session (a response where the
  1508. // first message contains a MapSessionHandle). The Seq number may be omitted
  1509. // on responses that don't change the state of the stream, such as KeepAlive
  1510. // or certain types of PingRequests. This is the value to be sent in
  1511. // MapRequest.MapSessionSeq to resume after this message.
  1512. Seq int64 `json:",omitempty"`
  1513. // KeepAlive, if set, represents an empty message just to keep
  1514. // the connection alive. When true, all other fields except
  1515. // PingRequest, ControlTime, and PopBrowserURL are ignored.
  1516. KeepAlive bool `json:",omitempty"`
  1517. // PingRequest, if non-empty, is a request to the client to
  1518. // prove it's still there by sending an HTTP request to the
  1519. // provided URL. No auth headers are necessary.
  1520. // PingRequest may be sent on any MapResponse (ones with
  1521. // KeepAlive true or false).
  1522. PingRequest *PingRequest `json:",omitempty"`
  1523. // PopBrowserURL, if non-empty, is a URL for the client to
  1524. // open to complete an action. The client should dup suppress
  1525. // identical URLs and only open it once for the same URL.
  1526. PopBrowserURL string `json:",omitempty"`
  1527. // Networking
  1528. // Node describes the node making the map request.
  1529. // Starting with MapRequest.Version 18, nil means unchanged.
  1530. Node *Node `json:",omitempty"`
  1531. // DERPMap describe the set of DERP servers available.
  1532. // A nil value means unchanged.
  1533. DERPMap *DERPMap `json:",omitempty"`
  1534. // Peers, if non-empty, is the complete list of peers.
  1535. // It will be set in the first MapResponse for a long-polled request/response.
  1536. // Subsequent responses will be delta-encoded if MapRequest.Version >= 5 and server
  1537. // chooses, in which case Peers will be nil or zero length.
  1538. // If Peers is non-empty, PeersChanged and PeersRemoved should
  1539. // be ignored (and should be empty).
  1540. // Peers is always returned sorted by Node.ID.
  1541. Peers []*Node `json:",omitempty"`
  1542. // PeersChanged are the Nodes (identified by their ID) that
  1543. // have changed or been added since the past update on the
  1544. // HTTP response. It's not used by the server if MapRequest.Version < 5.
  1545. // PeersChanged is always returned sorted by Node.ID.
  1546. PeersChanged []*Node `json:",omitempty"`
  1547. // PeersRemoved are the NodeIDs that are no longer in the peer list.
  1548. PeersRemoved []NodeID `json:",omitempty"`
  1549. // PeersChangedPatch, if non-nil, means that node(s) have changed.
  1550. // This is a lighter version of the older PeersChanged support that
  1551. // only supports certain types of updates
  1552. //
  1553. // These are applied after Peers* above, but in practice the
  1554. // control server should only send these on their own, without
  1555. // the Peers* fields also set.
  1556. PeersChangedPatch []*PeerChange `json:",omitempty"`
  1557. // PeerSeenChange contains information on how to update peers' LastSeen
  1558. // times. If the value is false, the peer is gone. If the value is true,
  1559. // the LastSeen time is now. Absent means unchanged.
  1560. PeerSeenChange map[NodeID]bool `json:",omitempty"`
  1561. // OnlineChange changes the value of a Peer Node.Online value.
  1562. OnlineChange map[NodeID]bool `json:",omitempty"`
  1563. // DNSConfig contains the DNS settings for the client to use.
  1564. // A nil value means no change from an earlier non-nil value.
  1565. DNSConfig *DNSConfig `json:",omitempty"`
  1566. // Domain is the name of the network that this node is
  1567. // in. It's either of the form "example.com" (for user
  1568. // [email protected], for multi-user networks) or
  1569. // "[email protected]" (for siloed users on shared email
  1570. // providers). Its exact form should not be depended on; new
  1571. // forms are coming later.
  1572. // If empty, the value is unchanged.
  1573. Domain string `json:",omitempty"`
  1574. // CollectServices reports whether this node's Tailnet has
  1575. // requested that info about services be included in HostInfo.
  1576. // If unset, the most recent non-empty MapResponse value in
  1577. // the HTTP response stream is used.
  1578. CollectServices opt.Bool `json:",omitempty"`
  1579. // PacketFilter are the firewall rules.
  1580. //
  1581. // For MapRequest.Version >= 6, a nil value means the most
  1582. // previously streamed non-nil MapResponse.PacketFilter within
  1583. // the same HTTP response. A non-nil but empty list always means
  1584. // no PacketFilter (that is, to block everything).
  1585. //
  1586. // Note that this package's type, due its use of a slice and omitempty, is
  1587. // unable to marshal a zero-length non-nil slice. The control server needs
  1588. // to marshal this type using a separate type. See MapResponse docs.
  1589. //
  1590. // See PacketFilters for the newer way to send PacketFilter updates.
  1591. PacketFilter []FilterRule `json:",omitempty"`
  1592. // PacketFilters encodes incremental packet filter updates to the client
  1593. // without having to send the entire packet filter on any changes as
  1594. // required by the older PacketFilter (singular) field above. The map keys
  1595. // are server-assigned arbitrary strings. The map values are the new rules
  1596. // for that key, or nil to delete it. The client then concatenates all the
  1597. // rules together to generate the final packet filter. Because the
  1598. // FilterRules can only match or not match, the ordering of filter rules
  1599. // doesn't matter. (That said, the client generates the file merged packet
  1600. // filter rules by concananting all the packet filter rules sorted by the
  1601. // map key name. But it does so for stability and testability, not
  1602. // correctness. If something needs to rely on that property, something has
  1603. // gone wrong.)
  1604. //
  1605. // If the server sends a non-nil PacketFilter (above), that is equivalent to
  1606. // a named packet filter with the key "base". It is valid for the server to
  1607. // send both PacketFilter and PacketFilters in the same MapResponse or
  1608. // alternate between them within a session. The PacketFilter is applied
  1609. // first (if set) and then the PacketFilters.
  1610. //
  1611. // As a special case, the map key "*" with a value of nil means to clear all
  1612. // prior named packet filters (including any implicit "base") before
  1613. // processing the other map entries.
  1614. PacketFilters map[string][]FilterRule `json:",omitempty"`
  1615. // UserProfiles are the user profiles of nodes in the network.
  1616. // As as of 1.1.541 (mapver 5), this contains new or updated
  1617. // user profiles only.
  1618. UserProfiles []UserProfile `json:",omitempty"`
  1619. // Health, if non-nil, sets the health state of the node from the control
  1620. // plane's perspective. A nil value means no change from the previous
  1621. // MapResponse. A non-nil 0-length slice restores the health to good (no
  1622. // known problems). A non-zero length slice are the list of problems that
  1623. // the control place sees.
  1624. //
  1625. // Note that this package's type, due its use of a slice and omitempty, is
  1626. // unable to marshal a zero-length non-nil slice. The control server needs
  1627. // to marshal this type using a separate type. See MapResponse docs.
  1628. Health []string `json:",omitempty"`
  1629. // SSHPolicy, if non-nil, updates the SSH policy for how incoming
  1630. // SSH connections should be handled.
  1631. SSHPolicy *SSHPolicy `json:",omitempty"`
  1632. // ControlTime, if non-zero, is the current timestamp according to the control server.
  1633. ControlTime *time.Time `json:",omitempty"`
  1634. // TKAInfo describes the control plane's view of tailnet
  1635. // key authority (TKA) state.
  1636. //
  1637. // An initial nil TKAInfo indicates that the control plane
  1638. // believes TKA should not be enabled. An initial non-nil TKAInfo
  1639. // indicates the control plane believes TKA should be enabled.
  1640. // A nil TKAInfo in a mapresponse stream (i.e. a 'delta' mapresponse)
  1641. // indicates no change from the value sent earlier.
  1642. TKAInfo *TKAInfo `json:",omitempty"`
  1643. // DomainDataPlaneAuditLogID, if non-empty, is the per-tailnet log ID to be
  1644. // used when writing data plane audit logs.
  1645. DomainDataPlaneAuditLogID string `json:",omitempty"`
  1646. // Debug is normally nil, except for when the control server
  1647. // is setting debug settings on a node.
  1648. Debug *Debug `json:",omitempty"`
  1649. // ControlDialPlan tells the client how to connect to the control
  1650. // server. An initial nil is equivalent to new(ControlDialPlan).
  1651. // A subsequent streamed nil means no change.
  1652. ControlDialPlan *ControlDialPlan `json:",omitempty"`
  1653. // ClientVersion describes the latest client version that's available for
  1654. // download and whether the client is using it. A nil value means no change
  1655. // or nothing to report.
  1656. ClientVersion *ClientVersion `json:",omitempty"`
  1657. // DefaultAutoUpdate is the default node auto-update setting for this
  1658. // tailnet. The node is free to opt-in or out locally regardless of this
  1659. // value. This value is only used on first MapResponse from control, the
  1660. // auto-update setting doesn't change if the tailnet admin flips the
  1661. // default after the node registered.
  1662. DefaultAutoUpdate opt.Bool `json:",omitempty"`
  1663. // MaxKeyDuration describes the MaxKeyDuration setting for the tailnet.
  1664. // If zero, the value is unchanged.
  1665. MaxKeyDuration time.Duration `json:",omitempty"`
  1666. }
  1667. // ClientVersion is information about the latest client version that's available
  1668. // for the client (and whether they're already running it).
  1669. //
  1670. // It does not include a URL to download the client, as that varies by platform.
  1671. type ClientVersion struct {
  1672. // RunningLatest is true if the client is running the latest build.
  1673. RunningLatest bool `json:",omitempty"`
  1674. // LatestVersion is the latest version.Short ("1.34.2") version available
  1675. // for download for the client's platform and packaging type.
  1676. // It won't be populated if RunningLatest is true.
  1677. LatestVersion string `json:",omitempty"`
  1678. // UrgentSecurityUpdate is set when the client is missing an important
  1679. // security update. That update may be in LatestVersion or earlier.
  1680. // UrgentSecurityUpdate should not be set if RunningLatest is false.
  1681. UrgentSecurityUpdate bool `json:",omitempty"`
  1682. // Notify is whether the client should do an OS-specific notification about
  1683. // a new version being available. This should not be populated if
  1684. // RunningLatest is true. The client should not notify multiple times for
  1685. // the same LatestVersion value.
  1686. Notify bool `json:",omitempty"`
  1687. // NotifyURL is a URL to open in the browser when the user clicks on the
  1688. // notification, when Notify is true.
  1689. NotifyURL string `json:",omitempty"`
  1690. // NotifyText is the text to show in the notification, when Notify is true.
  1691. NotifyText string `json:",omitempty"`
  1692. }
  1693. // ControlDialPlan is instructions from the control server to the client on how
  1694. // to connect to the control server; this is useful for maintaining connection
  1695. // if the client's network state changes after the initial connection, or due
  1696. // to the configuration that the control server pushes.
  1697. type ControlDialPlan struct {
  1698. // An empty list means the default: use DNS (unspecified which DNS).
  1699. Candidates []ControlIPCandidate
  1700. }
  1701. // ControlIPCandidate represents a single candidate address to use when
  1702. // connecting to the control server.
  1703. type ControlIPCandidate struct {
  1704. // IP is the address to attempt connecting to.
  1705. IP netip.Addr
  1706. // DialStartSec is the number of seconds after the beginning of the
  1707. // connection process to wait before trying this candidate.
  1708. DialStartDelaySec float64 `json:",omitempty"`
  1709. // DialTimeoutSec is the timeout for a connection to this candidate,
  1710. // starting after DialStartDelaySec.
  1711. DialTimeoutSec float64 `json:",omitempty"`
  1712. // Priority is the relative priority of this candidate; candidates with
  1713. // a higher priority are preferred over candidates with a lower
  1714. // priority.
  1715. Priority int `json:",omitempty"`
  1716. }
  1717. // Debug used to be a miscellaneous set of declarative debug config changes and
  1718. // imperative debug commands. They've since been mostly migrated to node
  1719. // attributes (MapResponse.Node.Capabilities) for the declarative things and c2n
  1720. // requests for the imperative things. Not much remains here. Don't add more.
  1721. type Debug struct {
  1722. // SleepSeconds requests that the client sleep for the
  1723. // provided number of seconds.
  1724. // The client can (and should) limit the value (such as 5
  1725. // minutes). This exists as a safety measure to slow down
  1726. // spinning clients, in case we introduce a bug in the
  1727. // state machine.
  1728. SleepSeconds float64 `json:",omitempty"`
  1729. // DisableLogTail disables the logtail package. Once disabled it can't be
  1730. // re-enabled for the lifetime of the process.
  1731. //
  1732. // This is primarily used by Headscale.
  1733. DisableLogTail bool `json:",omitempty"`
  1734. // Exit optionally specifies that the client should os.Exit
  1735. // with this code. This is a safety measure in case a client is crash
  1736. // looping or in an unsafe state and we need to remotely shut it down.
  1737. Exit *int `json:",omitempty"`
  1738. }
  1739. func (id ID) String() string { return fmt.Sprintf("id:%x", int64(id)) }
  1740. func (id UserID) String() string { return fmt.Sprintf("userid:%x", int64(id)) }
  1741. func (id LoginID) String() string { return fmt.Sprintf("loginid:%x", int64(id)) }
  1742. func (id NodeID) String() string { return fmt.Sprintf("nodeid:%x", int64(id)) }
  1743. // Equal reports whether n and n2 are equal.
  1744. func (n *Node) Equal(n2 *Node) bool {
  1745. if n == nil && n2 == nil {
  1746. return true
  1747. }
  1748. return n != nil && n2 != nil &&
  1749. n.ID == n2.ID &&
  1750. n.StableID == n2.StableID &&
  1751. n.Name == n2.Name &&
  1752. n.User == n2.User &&
  1753. n.Sharer == n2.Sharer &&
  1754. n.UnsignedPeerAPIOnly == n2.UnsignedPeerAPIOnly &&
  1755. n.Key == n2.Key &&
  1756. n.KeyExpiry.Equal(n2.KeyExpiry) &&
  1757. bytes.Equal(n.KeySignature, n2.KeySignature) &&
  1758. n.Machine == n2.Machine &&
  1759. n.DiscoKey == n2.DiscoKey &&
  1760. eqPtr(n.Online, n2.Online) &&
  1761. slicesx.EqualSameNil(n.Addresses, n2.Addresses) &&
  1762. slicesx.EqualSameNil(n.AllowedIPs, n2.AllowedIPs) &&
  1763. slicesx.EqualSameNil(n.PrimaryRoutes, n2.PrimaryRoutes) &&
  1764. slicesx.EqualSameNil(n.Endpoints, n2.Endpoints) &&
  1765. n.DERP == n2.DERP &&
  1766. n.Cap == n2.Cap &&
  1767. n.Hostinfo.Equal(n2.Hostinfo) &&
  1768. n.Created.Equal(n2.Created) &&
  1769. eqTimePtr(n.LastSeen, n2.LastSeen) &&
  1770. n.MachineAuthorized == n2.MachineAuthorized &&
  1771. slices.Equal(n.Capabilities, n2.Capabilities) &&
  1772. n.CapMap.Equal(n2.CapMap) &&
  1773. n.ComputedName == n2.ComputedName &&
  1774. n.computedHostIfDifferent == n2.computedHostIfDifferent &&
  1775. n.ComputedNameWithHost == n2.ComputedNameWithHost &&
  1776. slicesx.EqualSameNil(n.Tags, n2.Tags) &&
  1777. n.Expired == n2.Expired &&
  1778. eqPtr(n.SelfNodeV4MasqAddrForThisPeer, n2.SelfNodeV4MasqAddrForThisPeer) &&
  1779. eqPtr(n.SelfNodeV6MasqAddrForThisPeer, n2.SelfNodeV6MasqAddrForThisPeer) &&
  1780. n.IsWireGuardOnly == n2.IsWireGuardOnly
  1781. }
  1782. func eqPtr[T comparable](a, b *T) bool {
  1783. if a == b { // covers nil
  1784. return true
  1785. }
  1786. if a == nil || b == nil {
  1787. return false
  1788. }
  1789. return *a == *b
  1790. }
  1791. func eqTimePtr(a, b *time.Time) bool {
  1792. return ((a == nil) == (b == nil)) && (a == nil || a.Equal(*b))
  1793. }
  1794. // Oauth2Token is a copy of golang.org/x/oauth2.Token, to avoid the
  1795. // go.mod dependency on App Engine and grpc, which was causing problems.
  1796. // All we actually needed was this struct on the client side.
  1797. type Oauth2Token struct {
  1798. // AccessToken is the token that authorizes and authenticates
  1799. // the requests.
  1800. AccessToken string `json:"access_token"`
  1801. // TokenType is the type of token.
  1802. // The Type method returns either this or "Bearer", the default.
  1803. TokenType string `json:"token_type,omitempty"`
  1804. // RefreshToken is a token that's used by the application
  1805. // (as opposed to the user) to refresh the access token
  1806. // if it expires.
  1807. RefreshToken string `json:"refresh_token,omitempty"`
  1808. // Expiry is the optional expiration time of the access token.
  1809. //
  1810. // If zero, TokenSource implementations will reuse the same
  1811. // token forever and RefreshToken or equivalent
  1812. // mechanisms for that TokenSource will not be used.
  1813. Expiry time.Time `json:"expiry,omitempty"`
  1814. }
  1815. // NodeCapability represents a capability granted to the self node as listed in
  1816. // MapResponse.Node.Capabilities.
  1817. //
  1818. // It must be a URL like "https://tailscale.com/cap/file-sharing", or a
  1819. // well-known capability name like "funnel". The latter is only allowed for
  1820. // Tailscale-defined capabilities.
  1821. //
  1822. // Unlike PeerCapability, NodeCapability is not in context of a peer and is
  1823. // granted to the node itself.
  1824. //
  1825. // These are also referred to as "Node Attributes" in the ACL policy file.
  1826. type NodeCapability string
  1827. const (
  1828. CapabilityFileSharing NodeCapability = "https://tailscale.com/cap/file-sharing"
  1829. CapabilityAdmin NodeCapability = "https://tailscale.com/cap/is-admin"
  1830. CapabilitySSH NodeCapability = "https://tailscale.com/cap/ssh" // feature enabled/available
  1831. CapabilitySSHRuleIn NodeCapability = "https://tailscale.com/cap/ssh-rule-in" // some SSH rule reach this node
  1832. CapabilityDataPlaneAuditLogs NodeCapability = "https://tailscale.com/cap/data-plane-audit-logs" // feature enabled
  1833. CapabilityDebug NodeCapability = "https://tailscale.com/cap/debug" // exposes debug endpoints over the PeerAPI
  1834. CapabilityHTTPS NodeCapability = "https" // https cert provisioning enabled on tailnet
  1835. // CapabilityBindToInterfaceByRoute changes how Darwin nodes create
  1836. // sockets (in the net/netns package). See that package for more
  1837. // details on the behaviour of this capability.
  1838. CapabilityBindToInterfaceByRoute NodeCapability = "https://tailscale.com/cap/bind-to-interface-by-route"
  1839. // CapabilityDebugDisableAlternateDefaultRouteInterface changes how Darwin
  1840. // nodes get the default interface. There is an optional hook (used by the
  1841. // macOS and iOS clients) to override the default interface, this capability
  1842. // disables that and uses the default behavior (of parsing the routing
  1843. // table).
  1844. CapabilityDebugDisableAlternateDefaultRouteInterface NodeCapability = "https://tailscale.com/cap/debug-disable-alternate-default-route-interface"
  1845. // CapabilityDebugDisableBindConnToInterface disables the automatic binding
  1846. // of connections to the default network interface on Darwin nodes.
  1847. CapabilityDebugDisableBindConnToInterface NodeCapability = "https://tailscale.com/cap/debug-disable-bind-conn-to-interface"
  1848. // CapabilityTailnetLock indicates the node may initialize tailnet lock.
  1849. CapabilityTailnetLock NodeCapability = "https://tailscale.com/cap/tailnet-lock"
  1850. // Funnel warning capabilities used for reporting errors to the user.
  1851. // CapabilityWarnFunnelNoInvite indicates whether Funnel is enabled for the tailnet.
  1852. // This cap is no longer used 2023-08-09 onwards.
  1853. CapabilityWarnFunnelNoInvite NodeCapability = "https://tailscale.com/cap/warn-funnel-no-invite"
  1854. // CapabilityWarnFunnelNoHTTPS indicates HTTPS has not been enabled for the tailnet.
  1855. // This cap is no longer used 2023-08-09 onwards.
  1856. CapabilityWarnFunnelNoHTTPS NodeCapability = "https://tailscale.com/cap/warn-funnel-no-https"
  1857. // Debug logging capabilities
  1858. // CapabilityDebugTSDNSResolution enables verbose debug logging for DNS
  1859. // resolution for Tailscale-controlled domains (the control server, log
  1860. // server, DERP servers, etc.)
  1861. CapabilityDebugTSDNSResolution NodeCapability = "https://tailscale.com/cap/debug-ts-dns-resolution"
  1862. // CapabilityFunnelPorts specifies the ports that the Funnel is available on.
  1863. // The ports are specified as a comma-separated list of port numbers or port
  1864. // ranges (e.g. "80,443,8080-8090") in the ports query parameter.
  1865. // e.g. https://tailscale.com/cap/funnel-ports?ports=80,443,8080-8090
  1866. CapabilityFunnelPorts NodeCapability = "https://tailscale.com/cap/funnel-ports"
  1867. // NodeAttrFunnel grants the ability for a node to host ingress traffic.
  1868. NodeAttrFunnel NodeCapability = "funnel"
  1869. // NodeAttrSSHAggregator grants the ability for a node to collect SSH sessions.
  1870. NodeAttrSSHAggregator NodeCapability = "ssh-aggregator"
  1871. // NodeAttrDebugForceBackgroundSTUN forces a node to always do background
  1872. // STUN queries regardless of inactivity.
  1873. NodeAttrDebugForceBackgroundSTUN NodeCapability = "debug-always-stun"
  1874. // NodeAttrDebugDisableWGTrim disables the lazy WireGuard configuration,
  1875. // always giving WireGuard the full netmap, even for idle peers.
  1876. NodeAttrDebugDisableWGTrim NodeCapability = "debug-no-wg-trim"
  1877. // NodeAttrDebugDisableDRPO disables the DERP Return Path Optimization.
  1878. // See Issue 150.
  1879. NodeAttrDebugDisableDRPO NodeCapability = "debug-disable-drpo"
  1880. // NodeAttrDisableSubnetsIfPAC controls whether subnet routers should be
  1881. // disabled if WPAD is present on the network.
  1882. NodeAttrDisableSubnetsIfPAC NodeCapability = "debug-disable-subnets-if-pac"
  1883. // NodeAttrDisableUPnP makes the client not perform a UPnP portmapping.
  1884. // By default, we want to enable it to see if it works on more clients.
  1885. //
  1886. // If UPnP catastrophically fails for people, this should be set kill
  1887. // new attempts at UPnP connections.
  1888. NodeAttrDisableUPnP NodeCapability = "debug-disable-upnp"
  1889. // NodeAttrDisableDeltaUpdates makes the client not process updates via the
  1890. // delta update mechanism and should instead treat all netmap changes as
  1891. // "full" ones as tailscaled did in 1.48.x and earlier.
  1892. NodeAttrDisableDeltaUpdates NodeCapability = "disable-delta-updates"
  1893. // NodeAttrRandomizeClientPort makes magicsock UDP bind to
  1894. // :0 to get a random local port, ignoring any configured
  1895. // fixed port.
  1896. NodeAttrRandomizeClientPort NodeCapability = "randomize-client-port"
  1897. // NodeAttrSilentDisco makes the client suppress disco heartbeats to its
  1898. // peers.
  1899. NodeAttrSilentDisco NodeCapability = "silent-disco"
  1900. // NodeAttrOneCGNATEnable makes the client prefer one big CGNAT /10 route
  1901. // rather than a /32 per peer. At most one of this or
  1902. // NodeAttrOneCGNATDisable may be set; if neither are, it's automatic.
  1903. NodeAttrOneCGNATEnable NodeCapability = "one-cgnat?v=true"
  1904. // NodeAttrOneCGNATDisable makes the client prefer a /32 route per peer
  1905. // rather than one big /10 CGNAT route. At most one of this or
  1906. // NodeAttrOneCGNATEnable may be set; if neither are, it's automatic.
  1907. NodeAttrOneCGNATDisable NodeCapability = "one-cgnat?v=false"
  1908. // NodeAttrPeerMTUEnable makes the client do path MTU discovery to its
  1909. // peers. If it isn't set, it defaults to the client default.
  1910. NodeAttrPeerMTUEnable NodeCapability = "peer-mtu-enable"
  1911. // NodeAttrDNSForwarderDisableTCPRetries disables retrying truncated
  1912. // DNS queries over TCP if the response is truncated.
  1913. NodeAttrDNSForwarderDisableTCPRetries NodeCapability = "dns-forwarder-disable-tcp-retries"
  1914. // NodeAttrLinuxMustUseIPTables forces Linux clients to use iptables for
  1915. // netfilter management.
  1916. // This cannot be set simultaneously with NodeAttrLinuxMustUseNfTables.
  1917. NodeAttrLinuxMustUseIPTables NodeCapability = "linux-netfilter?v=iptables"
  1918. // NodeAttrLinuxMustUseNfTables forces Linux clients to use nftables for
  1919. // netfilter management.
  1920. // This cannot be set simultaneously with NodeAttrLinuxMustUseIPTables.
  1921. NodeAttrLinuxMustUseNfTables NodeCapability = "linux-netfilter?v=nftables"
  1922. // NodeAttrSeamlessKeyRenewal makes clients enable beta functionality
  1923. // of renewing node keys without breaking connections.
  1924. NodeAttrSeamlessKeyRenewal NodeCapability = "seamless-key-renewal"
  1925. )
  1926. // SetDNSRequest is a request to add a DNS record.
  1927. //
  1928. // This is used for ACME DNS-01 challenges (so people can use
  1929. // LetsEncrypt, etc).
  1930. //
  1931. // The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box,
  1932. // using the local machine key, and sent to:
  1933. //
  1934. // https://login.tailscale.com/machine/<mkey hex>/set-dns
  1935. type SetDNSRequest struct {
  1936. // Version is the client's capabilities
  1937. // (CurrentCapabilityVersion) when using the Noise transport.
  1938. //
  1939. // When using the original nacl crypto_box transport, the
  1940. // value must be 1.
  1941. Version CapabilityVersion
  1942. // NodeKey is the client's current node key.
  1943. NodeKey key.NodePublic
  1944. // Name is the domain name for which to create a record.
  1945. // For ACME DNS-01 challenges, it should be one of the domains
  1946. // in MapResponse.DNSConfig.CertDomains with the prefix
  1947. // "_acme-challenge.".
  1948. Name string
  1949. // Type is the DNS record type. For ACME DNS-01 challenges, it
  1950. // should be "TXT".
  1951. Type string
  1952. // Value is the value to add.
  1953. Value string
  1954. }
  1955. // SetDNSResponse is the response to a SetDNSRequest.
  1956. type SetDNSResponse struct{}
  1957. // HealthChangeRequest is the JSON request body type used to report
  1958. // node health changes to https://<control>/machine/<mkey hex>/update-health.
  1959. type HealthChangeRequest struct {
  1960. Subsys string // a health.Subsystem value in string form
  1961. Error string // or empty if cleared
  1962. }
  1963. // SSHPolicy is the policy for how to handle incoming SSH connections
  1964. // over Tailscale.
  1965. type SSHPolicy struct {
  1966. // Rules are the rules to process for an incoming SSH connection. The first
  1967. // matching rule takes its action and stops processing further rules.
  1968. //
  1969. // When an incoming connection first starts, all rules are evaluated in
  1970. // "none" auth mode, where the client hasn't even been asked to send a
  1971. // public key. All SSHRule.Principals requiring a public key won't match. If
  1972. // a rule matches on the first pass and its Action is reject, the
  1973. // authentication fails with that action's rejection message, if any.
  1974. //
  1975. // If the first pass rule evaluation matches nothing without matching an
  1976. // Action with Reject set, the rules are considered to see whether public
  1977. // keys might still result in a match. If not, "none" auth is terminated
  1978. // before proceeding to public key mode. If so, the client is asked to try
  1979. // public key authentication and the rules are evaluated again for each of
  1980. // the client's present keys.
  1981. Rules []*SSHRule `json:"rules"`
  1982. }
  1983. // An SSH rule is a match predicate and associated action for an incoming SSH connection.
  1984. type SSHRule struct {
  1985. // RuleExpires, if non-nil, is when this rule expires.
  1986. //
  1987. // For example, a (principal,sshuser) tuple might be granted
  1988. // prompt-free SSH access for N minutes, so this rule would be
  1989. // before a expiration-free rule for the same principal that
  1990. // required an auth prompt. This permits the control plane to
  1991. // be out of the path for already-authorized SSH pairs.
  1992. //
  1993. // Once a rule matches, the lifetime of any accepting connection
  1994. // is subject to the SSHAction.SessionExpires time, if any.
  1995. RuleExpires *time.Time `json:"ruleExpires,omitempty"`
  1996. // Principals matches an incoming connection. If the connection
  1997. // matches anything in this list and also matches SSHUsers,
  1998. // then Action is applied.
  1999. Principals []*SSHPrincipal `json:"principals"`
  2000. // SSHUsers are the SSH users that this rule matches. It is a
  2001. // map from either ssh-user|"*" => local-user. The map must
  2002. // contain a key for either ssh-user or, as a fallback, "*" to
  2003. // match anything. If it does, the map entry's value is the
  2004. // actual user that's logged in.
  2005. // If the map value is the empty string (for either the
  2006. // requested SSH user or "*"), the rule doesn't match.
  2007. // If the map value is "=", it means the ssh-user should map
  2008. // directly to the local-user.
  2009. // It may be nil if the Action is reject.
  2010. SSHUsers map[string]string `json:"sshUsers"`
  2011. // Action is the outcome to task.
  2012. // A nil or invalid action means to deny.
  2013. Action *SSHAction `json:"action"`
  2014. }
  2015. // SSHPrincipal is either a particular node or a user on any node.
  2016. type SSHPrincipal struct {
  2017. // Matching any one of the following four field causes a match.
  2018. // It must also match Certs, if non-empty.
  2019. Node StableNodeID `json:"node,omitempty"`
  2020. NodeIP string `json:"nodeIP,omitempty"`
  2021. UserLogin string `json:"userLogin,omitempty"` // email-ish: [email protected], bar@github
  2022. Any bool `json:"any,omitempty"` // if true, match any connection
  2023. // TODO(bradfitz): add StableUserID, once that exists
  2024. // PubKeys, if non-empty, means that this SSHPrincipal only
  2025. // matches if one of these public keys is presented by the user.
  2026. //
  2027. // As a special case, if len(PubKeys) == 1 and PubKeys[0] starts
  2028. // with "https://", then it's fetched (like https://github.com/username.keys).
  2029. // In that case, the following variable expansions are also supported
  2030. // in the URL:
  2031. // * $LOGINNAME_EMAIL ("[email protected]" or "foo@github")
  2032. // * $LOGINNAME_LOCALPART (the "foo" from either of the above)
  2033. PubKeys []string `json:"pubKeys,omitempty"`
  2034. }
  2035. // SSHAction is how to handle an incoming connection.
  2036. // At most one field should be non-zero.
  2037. type SSHAction struct {
  2038. // Message, if non-empty, is shown to the user before the
  2039. // action occurs.
  2040. Message string `json:"message,omitempty"`
  2041. // Reject, if true, terminates the connection. This action
  2042. // has higher priority that Accept, if given.
  2043. // The reason this is exists is primarily so a response
  2044. // from HoldAndDelegate has a way to stop the poll.
  2045. Reject bool `json:"reject,omitempty"`
  2046. // Accept, if true, accepts the connection immediately
  2047. // without further prompts.
  2048. Accept bool `json:"accept,omitempty"`
  2049. // SessionDuration, if non-zero, is how long the session can stay open
  2050. // before being forcefully terminated.
  2051. SessionDuration time.Duration `json:"sessionDuration,omitempty"`
  2052. // AllowAgentForwarding, if true, allows accepted connections to forward
  2053. // the ssh agent if requested.
  2054. AllowAgentForwarding bool `json:"allowAgentForwarding,omitempty"`
  2055. // HoldAndDelegate, if non-empty, is a URL that serves an
  2056. // outcome verdict. The connection will be accepted and will
  2057. // block until the provided long-polling URL serves a new
  2058. // SSHAction JSON value. The URL must be fetched using the
  2059. // Noise transport (in package control/control{base,http}).
  2060. // If the long poll breaks before returning a complete HTTP
  2061. // response, it should be re-fetched as long as the SSH
  2062. // session is open.
  2063. //
  2064. // The following variables in the URL are expanded by tailscaled:
  2065. //
  2066. // * $SRC_NODE_IP (URL escaped)
  2067. // * $SRC_NODE_ID (Node.ID as int64 string)
  2068. // * $DST_NODE_IP (URL escaped)
  2069. // * $DST_NODE_ID (Node.ID as int64 string)
  2070. // * $SSH_USER (URL escaped, ssh user requested)
  2071. // * $LOCAL_USER (URL escaped, local user mapped)
  2072. HoldAndDelegate string `json:"holdAndDelegate,omitempty"`
  2073. // AllowLocalPortForwarding, if true, allows accepted connections
  2074. // to use local port forwarding if requested.
  2075. AllowLocalPortForwarding bool `json:"allowLocalPortForwarding,omitempty"`
  2076. // AllowRemotePortForwarding, if true, allows accepted connections
  2077. // to use remote port forwarding if requested.
  2078. AllowRemotePortForwarding bool `json:"allowRemotePortForwarding,omitempty"`
  2079. // Recorders defines the destinations of the SSH session recorders.
  2080. // The recording will be uploaded to http://addr:port/record.
  2081. Recorders []netip.AddrPort `json:"recorders,omitempty"`
  2082. // OnRecorderFailure is the action to take if recording fails.
  2083. // If nil, the default action is to fail open.
  2084. OnRecordingFailure *SSHRecorderFailureAction `json:"onRecordingFailure,omitempty"`
  2085. }
  2086. // SSHRecorderFailureAction is the action to take if recording fails.
  2087. type SSHRecorderFailureAction struct {
  2088. // RejectSessionWithMessage, if not empty, specifies that the session should
  2089. // be rejected if the recording fails to start.
  2090. // The message will be shown to the user before the session is rejected.
  2091. RejectSessionWithMessage string `json:",omitempty"`
  2092. // TerminateSessionWithMessage, if not empty, specifies that the session
  2093. // should be terminated if the recording fails after it has started. The
  2094. // message will be shown to the user before the session is terminated.
  2095. TerminateSessionWithMessage string `json:",omitempty"`
  2096. // NotifyURL, if non-empty, specifies a HTTP POST URL to notify when the
  2097. // recording fails. The payload is the JSON encoded
  2098. // SSHRecordingFailureNotifyRequest struct. The host field in the URL is
  2099. // ignored, and it will be sent to control over the Noise transport.
  2100. NotifyURL string `json:",omitempty"`
  2101. }
  2102. // SSHEventNotifyRequest is the JSON payload sent to the NotifyURL
  2103. // for an SSH event.
  2104. type SSHEventNotifyRequest struct {
  2105. // EventType is the type of notify request being sent.
  2106. EventType SSHEventType
  2107. // ConnectionID uniquely identifies a connection made to the SSH server.
  2108. // It may be shared across multiple sessions over the same connection in
  2109. // case a single connection creates multiple sessions.
  2110. ConnectionID string
  2111. // CapVersion is the client's current CapabilityVersion.
  2112. CapVersion CapabilityVersion
  2113. // NodeKey is the client's current node key.
  2114. NodeKey key.NodePublic
  2115. // SrcNode is the ID of the node that initiated the SSH session.
  2116. SrcNode NodeID
  2117. // SSHUser is the user that was presented to the SSH server.
  2118. SSHUser string
  2119. // LocalUser is the user that was resolved from the SSHUser for the local machine.
  2120. LocalUser string
  2121. // RecordingAttempts is the list of recorders that were attempted, in order.
  2122. RecordingAttempts []*SSHRecordingAttempt
  2123. }
  2124. // SSHEventType defines the event type linked to a SSH action or state.
  2125. type SSHEventType int
  2126. const (
  2127. UnspecifiedSSHEventType SSHEventType = 0
  2128. // SSHSessionRecordingRejected is the event that
  2129. // defines when a SSH session cannot be started
  2130. // because no recorder is available for session
  2131. // recording, and the SSHRecorderFailureAction
  2132. // RejectSessionWithMessage is not empty.
  2133. SSHSessionRecordingRejected SSHEventType = 1
  2134. // SSHSessionRecordingTerminated is the event that
  2135. // defines when session recording has failed
  2136. // during the session and the SSHRecorderFailureAction
  2137. // TerminateSessionWithMessage is not empty.
  2138. SSHSessionRecordingTerminated SSHEventType = 2
  2139. // SSHSessionRecordingFailed is the event that
  2140. // defines when session recording is unavailable and
  2141. // the SSHRecorderFailureAction RejectSessionWithMessage
  2142. // or TerminateSessionWithMessage is empty.
  2143. SSHSessionRecordingFailed SSHEventType = 3
  2144. )
  2145. // SSHRecordingAttempt is a single attempt to start a recording.
  2146. type SSHRecordingAttempt struct {
  2147. // Recorder is the address of the recorder that was attempted.
  2148. Recorder netip.AddrPort
  2149. // FailureMessage is the error message of the failed attempt.
  2150. FailureMessage string
  2151. }
  2152. // QueryFeatureRequest is a request sent to "/machine/feature/query"
  2153. // to get instructions on how to enable a feature, such as Funnel,
  2154. // for the node's tailnet.
  2155. //
  2156. // See QueryFeatureResponse for response structure.
  2157. type QueryFeatureRequest struct {
  2158. // Feature is the string identifier for a feature.
  2159. Feature string `json:",omitempty"`
  2160. // NodeKey is the client's current node key.
  2161. NodeKey key.NodePublic `json:",omitempty"`
  2162. }
  2163. // QueryFeatureResponse is the response to an QueryFeatureRequest.
  2164. // See cli.enableFeatureInteractive for usage.
  2165. type QueryFeatureResponse struct {
  2166. // Complete is true when the feature is already enabled.
  2167. Complete bool `json:",omitempty"`
  2168. // Text holds lines to display in the CLI with information
  2169. // about the feature and how to enable it.
  2170. //
  2171. // Lines are separated by newline characters. The final
  2172. // newline may be omitted.
  2173. Text string `json:",omitempty"`
  2174. // URL is the link for the user to visit to take action on
  2175. // enabling the feature.
  2176. //
  2177. // When empty, there is no action for this user to take.
  2178. URL string `json:",omitempty"`
  2179. // ShouldWait specifies whether the CLI should block and
  2180. // wait for the user to enable the feature.
  2181. //
  2182. // If this is true, the enablement from the control server
  2183. // is expected to be a quick and uninterrupted process for
  2184. // the user, and blocking allows them to immediately start
  2185. // using the feature once enabled without rerunning the
  2186. // command (e.g. no need to re-run "funnel on").
  2187. //
  2188. // The CLI can watch the IPN notification bus for changes in
  2189. // required node capabilities to know when to continue.
  2190. ShouldWait bool `json:",omitempty"`
  2191. }
  2192. // WebClientAuthResponse is the response to a web client authentication request
  2193. // sent to "/machine/webclient/action" or "/machine/webclient/wait".
  2194. // See client/web for usage.
  2195. type WebClientAuthResponse struct {
  2196. // ID is a unique identifier for the session auth request.
  2197. // It can be supplied to "/machine/webclient/wait" to pause until
  2198. // the session authentication has been completed.
  2199. ID string `json:",omitempty"`
  2200. // URL is the link for the user to visit to authenticate the session.
  2201. //
  2202. // When empty, there is no action for the user to take.
  2203. URL string `json:",omitempty"`
  2204. // Complete is true when the session authentication has been completed.
  2205. Complete bool `json:",omitempty"`
  2206. }
  2207. // OverTLSPublicKeyResponse is the JSON response to /key?v=<n>
  2208. // over HTTPS (regular TLS) to the Tailscale control plane server,
  2209. // where the 'v' argument is the client's current capability version
  2210. // (previously known as the "MapRequest version").
  2211. //
  2212. // The "OverTLS" prefix is to loudly declare that this exchange
  2213. // doesn't happen over Noise and can be intercepted/MITM'ed by
  2214. // enterprise/corp proxies where the organization can put TLS roots
  2215. // on devices.
  2216. type OverTLSPublicKeyResponse struct {
  2217. // LegacyPublic specifies the control plane server's original
  2218. // NaCl crypto_box machine key.
  2219. // It will be zero for sufficiently new clients, based on their
  2220. // advertised "v" parameter (the CurrentMapRequestVersion).
  2221. // In that case, only the newer Noise-based transport may be used
  2222. // using the PublicKey field.
  2223. LegacyPublicKey key.MachinePublic `json:"legacyPublicKey"`
  2224. // PublicKey specifies the server's public key for the
  2225. // Noise-based control plane protocol. (see packages
  2226. // control/controlbase and control/controlhttp)
  2227. PublicKey key.MachinePublic `json:"publicKey"`
  2228. }
  2229. // TokenRequest is a request to get an OIDC ID token for an audience.
  2230. // The token can be presented to any resource provider which offers OIDC
  2231. // Federation.
  2232. //
  2233. // It is JSON-encoded and sent over Noise to "/machine/id-token".
  2234. type TokenRequest struct {
  2235. // CapVersion is the client's current CapabilityVersion.
  2236. CapVersion CapabilityVersion
  2237. // NodeKey is the client's current node key.
  2238. NodeKey key.NodePublic
  2239. // Audience the token is being requested for.
  2240. Audience string
  2241. }
  2242. // TokenResponse is the response to a TokenRequest.
  2243. type TokenResponse struct {
  2244. // IDToken is a JWT encoding the following standard claims:
  2245. //
  2246. // `sub` | the MagicDNS name of the node
  2247. // `aud` | Audience from the request
  2248. // `exp` | Token expiry
  2249. // `iat` | Token issuance time
  2250. // `iss` | Issuer
  2251. // `jti` | Random token identifier
  2252. // `nbf` | Not before time
  2253. //
  2254. // It also encodes the following Tailscale specific claims:
  2255. //
  2256. // `key` | the node public key
  2257. // `addresses` | the Tailscale IPs of the node
  2258. // `nid` | the node ID
  2259. // `node` | the name of the node
  2260. // `domain` | the domain of the node, it has the same format as MapResponse.Domain.
  2261. // `tags` | an array of <domain:tag> on the node (like alice.github:tag:foo or example.com:tag:foo)
  2262. // `user` | user emailish (like alice.github:alice@github or example.com:[email protected]), if not tagged
  2263. // `uid` | user ID, if not tagged
  2264. IDToken string `json:"id_token"`
  2265. }
  2266. // PeerChange is an update to a node.
  2267. type PeerChange struct {
  2268. // NodeID is the node ID being mutated. If the NodeID is not
  2269. // known in the current netmap, this update should be
  2270. // ignored. (But the server will try not to send such useless
  2271. // updates.)
  2272. NodeID NodeID
  2273. // DERPRegion, if non-zero, means that NodeID's home DERP
  2274. // region ID is now this number.
  2275. DERPRegion int `json:",omitempty"`
  2276. // Cap, if non-zero, means that NodeID's capability version has changed.
  2277. Cap CapabilityVersion `json:",omitempty"`
  2278. // CapMap, if non-nil, means that NodeID's capability map has changed.
  2279. CapMap NodeCapMap `json:",omitempty"`
  2280. // Endpoints, if non-empty, means that NodeID's UDP Endpoints
  2281. // have changed to these.
  2282. Endpoints []netip.AddrPort `json:",omitempty"`
  2283. // Key, if non-nil, means that the NodeID's wireguard public key changed.
  2284. Key *key.NodePublic `json:",omitempty"`
  2285. // KeySignature, if non-nil, means that the signature of the wireguard
  2286. // public key has changed.
  2287. KeySignature tkatype.MarshaledSignature `json:",omitempty"`
  2288. // DiscoKey, if non-nil, means that the NodeID's discokey changed.
  2289. DiscoKey *key.DiscoPublic `json:",omitempty"`
  2290. // Online, if non-nil, means that the NodeID's online status changed.
  2291. Online *bool `json:",omitempty"`
  2292. // LastSeen, if non-nil, means that the NodeID's online status changed.
  2293. LastSeen *time.Time `json:",omitempty"`
  2294. // KeyExpiry, if non-nil, changes the NodeID's key expiry.
  2295. KeyExpiry *time.Time `json:",omitempty"`
  2296. // Capabilities, if non-nil, means that the NodeID's capabilities changed.
  2297. // It's a pointer to a slice for "omitempty", to allow differentiating
  2298. // a change to empty from no change.
  2299. Capabilities *[]NodeCapability `json:",omitempty"`
  2300. }
  2301. // DerpMagicIP is a fake WireGuard endpoint IP address that means to
  2302. // use DERP. When used (in the Node.DERP field), the port number of
  2303. // the WireGuard endpoint is the DERP region ID number to use.
  2304. //
  2305. // Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
  2306. const DerpMagicIP = "127.3.3.40"
  2307. var DerpMagicIPAddr = netip.MustParseAddr(DerpMagicIP)
  2308. // EarlyNoise is the early payload that's sent over Noise but before the HTTP/2
  2309. // handshake when connecting to the coordination server.
  2310. //
  2311. // This exists to let the server push some early info to client for that
  2312. // stateful HTTP/2+Noise connection without incurring an extra round trip. (This
  2313. // would've used HTTP/2 server push, had Go's client-side APIs been available)
  2314. type EarlyNoise struct {
  2315. // NodeKeyChallenge is a random per-connection public key to be used by
  2316. // the client to prove possession of a wireguard private key.
  2317. NodeKeyChallenge key.ChallengePublic `json:"nodeKeyChallenge"`
  2318. }