netmap.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package controlclient
  5. import (
  6. "bytes"
  7. "encoding/base64"
  8. "encoding/json"
  9. "fmt"
  10. "log"
  11. "reflect"
  12. "strings"
  13. "time"
  14. "github.com/tailscale/wireguard-go/wgcfg"
  15. "tailscale.com/tailcfg"
  16. "tailscale.com/types/logger"
  17. "tailscale.com/wgengine/filter"
  18. )
  19. type NetworkMap struct {
  20. // Core networking
  21. NodeKey tailcfg.NodeKey
  22. PrivateKey wgcfg.PrivateKey
  23. Expiry time.Time
  24. Addresses []wgcfg.CIDR
  25. LocalPort uint16 // used for debugging
  26. MachineStatus tailcfg.MachineStatus
  27. Peers []*tailcfg.Node
  28. DNS []wgcfg.IP
  29. DNSDomains []string
  30. Hostinfo tailcfg.Hostinfo
  31. PacketFilter filter.Matches
  32. // DERPMap is the last DERP server map received. It's reused
  33. // between updates and should not be modified.
  34. DERPMap *tailcfg.DERPMap
  35. // Debug knobs from control server for debug or feature gating.
  36. Debug *tailcfg.Debug
  37. // ACLs
  38. User tailcfg.UserID
  39. Domain string
  40. // TODO(crawshaw): reduce UserProfiles to []tailcfg.UserProfile?
  41. // There are lots of ways to slice this data, leave it up to users.
  42. UserProfiles map[tailcfg.UserID]tailcfg.UserProfile
  43. Roles []tailcfg.Role
  44. // TODO(crawshaw): Groups []tailcfg.Group
  45. // TODO(crawshaw): Capabilities []tailcfg.Capability
  46. }
  47. func (n *NetworkMap) Equal(n2 *NetworkMap) bool {
  48. // TODO(crawshaw): this is crude, but is an easy way to avoid bugs.
  49. b, err := json.Marshal(n)
  50. if err != nil {
  51. panic(err)
  52. }
  53. b2, err := json.Marshal(n2)
  54. if err != nil {
  55. panic(err)
  56. }
  57. return bytes.Equal(b, b2)
  58. }
  59. func (nm NetworkMap) String() string {
  60. return nm.Concise()
  61. }
  62. func (nm *NetworkMap) Concise() string {
  63. buf := new(strings.Builder)
  64. fmt.Fprintf(buf, "netmap: self: %v auth=%v",
  65. nm.NodeKey.ShortString(), nm.MachineStatus)
  66. if nm.LocalPort != 0 {
  67. fmt.Fprintf(buf, " port=%v", nm.LocalPort)
  68. }
  69. if nm.Debug != nil {
  70. j, _ := json.Marshal(nm.Debug)
  71. fmt.Fprintf(buf, " debug=%s", j)
  72. }
  73. fmt.Fprintf(buf, " %v", nm.Addresses)
  74. buf.WriteByte('\n')
  75. for _, p := range nm.Peers {
  76. aip := make([]string, len(p.AllowedIPs))
  77. for i, a := range p.AllowedIPs {
  78. s := strings.TrimSuffix(fmt.Sprint(a), "/32")
  79. aip[i] = s
  80. }
  81. ep := make([]string, len(p.Endpoints))
  82. for i, e := range p.Endpoints {
  83. // Align vertically on the ':' between IP and port
  84. colon := strings.IndexByte(e, ':')
  85. spaces := 0
  86. for colon > 0 && len(e)+spaces-colon < 6 {
  87. spaces++
  88. colon--
  89. }
  90. ep[i] = fmt.Sprintf("%21v", e+strings.Repeat(" ", spaces))
  91. }
  92. derp := p.DERP
  93. const derpPrefix = "127.3.3.40:"
  94. if strings.HasPrefix(derp, derpPrefix) {
  95. derp = "D" + derp[len(derpPrefix):]
  96. }
  97. // Most of the time, aip is just one element, so format the
  98. // table to look good in that case. This will also make multi-
  99. // subnet nodes stand out visually.
  100. fmt.Fprintf(buf, " %v %-2v %-15v : %v\n",
  101. p.Key.ShortString(), derp,
  102. strings.Join(aip, " "),
  103. strings.Join(ep, " "))
  104. }
  105. return buf.String()
  106. }
  107. func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
  108. if reflect.DeepEqual(a, b) {
  109. // Fast path that only does one allocation.
  110. return ""
  111. }
  112. out := []string{}
  113. ra := strings.Split(a.Concise(), "\n")
  114. rb := strings.Split(b.Concise(), "\n")
  115. ma := map[string]struct{}{}
  116. for _, s := range ra {
  117. ma[s] = struct{}{}
  118. }
  119. mb := map[string]struct{}{}
  120. for _, s := range rb {
  121. mb[s] = struct{}{}
  122. }
  123. for _, s := range ra {
  124. if _, ok := mb[s]; !ok {
  125. out = append(out, "-"+s)
  126. }
  127. }
  128. for _, s := range rb {
  129. if _, ok := ma[s]; !ok {
  130. out = append(out, "+"+s)
  131. }
  132. }
  133. return strings.Join(out, "\n")
  134. }
  135. func (nm *NetworkMap) JSON() string {
  136. b, err := json.MarshalIndent(*nm, "", " ")
  137. if err != nil {
  138. return fmt.Sprintf("[json error: %v]", err)
  139. }
  140. return string(b)
  141. }
  142. const (
  143. UAllowSingleHosts = 1 << iota
  144. UAllowSubnetRoutes
  145. UAllowDefaultRoute
  146. UHackDefaultRoute
  147. UDefault = 0
  148. )
  149. // Several programs need to parse these arguments into uflags, so let's
  150. // centralize it here.
  151. func UFlagsHelper(uroutes, rroutes, droutes bool) int {
  152. uflags := 0
  153. if uroutes {
  154. uflags |= UAllowSingleHosts
  155. }
  156. if rroutes {
  157. uflags |= UAllowSubnetRoutes
  158. }
  159. if droutes {
  160. uflags |= UAllowDefaultRoute
  161. }
  162. return uflags
  163. }
  164. // TODO(bradfitz): UAPI seems to only be used by the old confnode and
  165. // pingnode; delete this when those are deleted/rewritten?
  166. func (nm *NetworkMap) UAPI(uflags int, dnsOverride []wgcfg.IP) string {
  167. wgcfg, err := nm.WGCfg(log.Printf, uflags, dnsOverride)
  168. if err != nil {
  169. log.Fatalf("WGCfg() failed unexpectedly: %v\n", err)
  170. }
  171. s, err := wgcfg.ToUAPI()
  172. if err != nil {
  173. log.Fatalf("ToUAPI() failed unexpectedly: %v\n", err)
  174. }
  175. return s
  176. }
  177. func (nm *NetworkMap) WGCfg(logf logger.Logf, uflags int, dnsOverride []wgcfg.IP) (*wgcfg.Config, error) {
  178. s := nm._WireGuardConfig(logf, uflags, dnsOverride, true)
  179. return wgcfg.FromWgQuick(s, "tailscale")
  180. }
  181. // EndpointDiscoSuffix is appended to the hex representation of a peer's discovery key
  182. // and is then the sole wireguard endpoint for peers with a non-zero discovery key.
  183. // This form is then recognize by magicsock's CreateEndpoint.
  184. const EndpointDiscoSuffix = ".disco.tailscale:12345"
  185. func (nm *NetworkMap) _WireGuardConfig(logf logger.Logf, uflags int, dnsOverride []wgcfg.IP, allEndpoints bool) string {
  186. buf := new(strings.Builder)
  187. fmt.Fprintf(buf, "[Interface]\n")
  188. fmt.Fprintf(buf, "PrivateKey = %s\n", base64.StdEncoding.EncodeToString(nm.PrivateKey[:]))
  189. if len(nm.Addresses) > 0 {
  190. fmt.Fprintf(buf, "Address = ")
  191. for i, cidr := range nm.Addresses {
  192. if i > 0 {
  193. fmt.Fprintf(buf, ", ")
  194. }
  195. fmt.Fprintf(buf, "%s", cidr)
  196. }
  197. fmt.Fprintf(buf, "\n")
  198. }
  199. fmt.Fprintf(buf, "ListenPort = %d\n", nm.LocalPort)
  200. if len(dnsOverride) > 0 {
  201. dnss := []string{}
  202. for _, ip := range dnsOverride {
  203. dnss = append(dnss, ip.String())
  204. }
  205. fmt.Fprintf(buf, "DNS = %s\n", strings.Join(dnss, ","))
  206. }
  207. fmt.Fprintf(buf, "\n")
  208. for i, peer := range nm.Peers {
  209. if Debug.OnlyDisco && peer.DiscoKey.IsZero() {
  210. continue
  211. }
  212. if (uflags&UAllowSingleHosts) == 0 && len(peer.AllowedIPs) < 2 {
  213. logf("wgcfg: %v skipping a single-host peer.\n", peer.Key.ShortString())
  214. continue
  215. }
  216. if i > 0 {
  217. fmt.Fprintf(buf, "\n")
  218. }
  219. fmt.Fprintf(buf, "[Peer]\n")
  220. fmt.Fprintf(buf, "PublicKey = %s\n", base64.StdEncoding.EncodeToString(peer.Key[:]))
  221. var endpoints []string
  222. if !peer.DiscoKey.IsZero() {
  223. fmt.Fprintf(buf, "Endpoint = %x%s\n", peer.DiscoKey[:], EndpointDiscoSuffix)
  224. } else {
  225. if peer.DERP != "" {
  226. endpoints = append(endpoints, peer.DERP)
  227. }
  228. endpoints = append(endpoints, peer.Endpoints...)
  229. if len(endpoints) > 0 {
  230. if len(endpoints) == 1 {
  231. fmt.Fprintf(buf, "Endpoint = %s", endpoints[0])
  232. } else if allEndpoints {
  233. // TODO(apenwarr): This mode is incompatible.
  234. // Normal wireguard clients don't know how to
  235. // parse it (yet?)
  236. fmt.Fprintf(buf, "Endpoint = %s", strings.Join(endpoints, ","))
  237. } else {
  238. fmt.Fprintf(buf, "Endpoint = %s # other endpoints: %s",
  239. endpoints[0],
  240. strings.Join(endpoints[1:], ", "))
  241. }
  242. buf.WriteByte('\n')
  243. }
  244. }
  245. var aips []string
  246. for _, allowedIP := range peer.AllowedIPs {
  247. aip := allowedIP.String()
  248. if allowedIP.Mask == 0 {
  249. if (uflags & UAllowDefaultRoute) == 0 {
  250. logf("wgcfg: %v skipping default route\n", peer.Key.ShortString())
  251. continue
  252. }
  253. if (uflags & UHackDefaultRoute) != 0 {
  254. aip = "10.0.0.0/8"
  255. logf("wgcfg: %v converting default route => %v\n", peer.Key.ShortString(), aip)
  256. }
  257. } else if allowedIP.Mask < 32 {
  258. if (uflags & UAllowSubnetRoutes) == 0 {
  259. logf("wgcfg: %v skipping subnet route\n", peer.Key.ShortString())
  260. continue
  261. }
  262. }
  263. aips = append(aips, aip)
  264. }
  265. fmt.Fprintf(buf, "AllowedIPs = %s\n", strings.Join(aips, ", "))
  266. if peer.KeepAlive {
  267. fmt.Fprintf(buf, "PersistentKeepalive = 25\n")
  268. }
  269. }
  270. return buf.String()
  271. }