tsaddr.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package tsaddr handles Tailscale-specific IPs and ranges.
  4. package tsaddr
  5. import (
  6. "encoding/binary"
  7. "errors"
  8. "net/netip"
  9. "slices"
  10. "sync"
  11. "go4.org/netipx"
  12. "tailscale.com/net/netaddr"
  13. "tailscale.com/types/views"
  14. )
  15. // ChromeOSVMRange returns the subset of the CGNAT IPv4 range used by
  16. // ChromeOS to interconnect the host OS to containers and VMs. We
  17. // avoid allocating Tailscale IPs from it, to avoid conflicts.
  18. func ChromeOSVMRange() netip.Prefix {
  19. chromeOSRange.Do(func() { mustPrefix(&chromeOSRange.v, "100.115.92.0/23") })
  20. return chromeOSRange.v
  21. }
  22. var chromeOSRange oncePrefix
  23. // CGNATRange returns the Carrier Grade NAT address range that
  24. // is the superset range that Tailscale assigns out of.
  25. // See https://tailscale.com/s/cgnat
  26. // Note that Tailscale does not assign out of the ChromeOSVMRange.
  27. func CGNATRange() netip.Prefix {
  28. cgnatRange.Do(func() { mustPrefix(&cgnatRange.v, "100.64.0.0/10") })
  29. return cgnatRange.v
  30. }
  31. var (
  32. cgnatRange oncePrefix
  33. tsUlaRange oncePrefix
  34. tsViaRange oncePrefix
  35. ula4To6Range oncePrefix
  36. ulaEph6Range oncePrefix
  37. serviceIPv6 oncePrefix
  38. )
  39. // TailscaleServiceIP returns the IPv4 listen address of services
  40. // provided by Tailscale itself such as the MagicDNS proxy.
  41. //
  42. // For IPv6, use TailscaleServiceIPv6.
  43. func TailscaleServiceIP() netip.Addr {
  44. return netaddr.IPv4(100, 100, 100, 100) // "100.100.100.100" for those grepping
  45. }
  46. // TailscaleServiceIPv6 returns the IPv6 listen address of the services
  47. // provided by Tailscale itself such as the MagicDNS proxy.
  48. //
  49. // For IPv4, use TailscaleServiceIP.
  50. func TailscaleServiceIPv6() netip.Addr {
  51. serviceIPv6.Do(func() { mustPrefix(&serviceIPv6.v, TailscaleServiceIPv6String+"/128") })
  52. return serviceIPv6.v.Addr()
  53. }
  54. const (
  55. TailscaleServiceIPString = "100.100.100.100"
  56. TailscaleServiceIPv6String = "fd7a:115c:a1e0::53"
  57. )
  58. // IsTailscaleIP reports whether IP is an IP address in a range that
  59. // Tailscale assigns from.
  60. func IsTailscaleIP(ip netip.Addr) bool {
  61. if ip.Is4() {
  62. return IsTailscaleIPv4(ip)
  63. }
  64. return TailscaleULARange().Contains(ip)
  65. }
  66. // IsTailscaleIPv4 reports whether an IPv4 IP is an IP address that
  67. // Tailscale assigns from.
  68. func IsTailscaleIPv4(ip netip.Addr) bool {
  69. return CGNATRange().Contains(ip) && !ChromeOSVMRange().Contains(ip)
  70. }
  71. // TailscaleULARange returns the IPv6 Unique Local Address range that
  72. // is the superset range that Tailscale assigns out of.
  73. func TailscaleULARange() netip.Prefix {
  74. tsUlaRange.Do(func() { mustPrefix(&tsUlaRange.v, "fd7a:115c:a1e0::/48") })
  75. return tsUlaRange.v
  76. }
  77. // TailscaleViaRange returns the IPv6 Unique Local Address subset range
  78. // TailscaleULARange that's used for IPv4 tunneling via IPv6.
  79. func TailscaleViaRange() netip.Prefix {
  80. // Mnemonic: "b1a" sounds like "via".
  81. tsViaRange.Do(func() { mustPrefix(&tsViaRange.v, "fd7a:115c:a1e0:b1a::/64") })
  82. return tsViaRange.v
  83. }
  84. // Tailscale4To6Range returns the subset of TailscaleULARange used for
  85. // auto-translated Tailscale ipv4 addresses.
  86. func Tailscale4To6Range() netip.Prefix {
  87. // This IP range has no significance, beyond being a subset of
  88. // TailscaleULARange. The bits from /48 to /104 were picked at
  89. // random.
  90. ula4To6Range.Do(func() { mustPrefix(&ula4To6Range.v, "fd7a:115c:a1e0:ab12:4843:cd96:6200::/104") })
  91. return ula4To6Range.v
  92. }
  93. // TailscaleEphemeral6Range returns the subset of TailscaleULARange
  94. // used for ephemeral IPv6-only Tailscale nodes.
  95. func TailscaleEphemeral6Range() netip.Prefix {
  96. // This IP range has no significance, beyond being a subset of
  97. // TailscaleULARange. The bits from /48 to /64 were picked at
  98. // random, with the only criterion being to not be the conflict
  99. // with the Tailscale4To6Range above.
  100. ulaEph6Range.Do(func() { mustPrefix(&ulaEph6Range.v, "fd7a:115c:a1e0:efe3::/64") })
  101. return ulaEph6Range.v
  102. }
  103. // Tailscale4To6Placeholder returns an IP address that can be used as
  104. // a source IP when one is required, but a netmap didn't provide
  105. // any. This address never gets allocated by the 4-to-6 algorithm in
  106. // control.
  107. //
  108. // Currently used to work around a Windows limitation when programming
  109. // IPv6 routes in corner cases.
  110. func Tailscale4To6Placeholder() netip.Addr {
  111. return Tailscale4To6Range().Addr()
  112. }
  113. // Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the
  114. // given Tailscale IPv4 address. Returns a zero IP if ipv4 isn't a
  115. // Tailscale IPv4 address.
  116. func Tailscale4To6(ipv4 netip.Addr) netip.Addr {
  117. if !ipv4.Is4() || !IsTailscaleIP(ipv4) {
  118. return netip.Addr{}
  119. }
  120. ret := Tailscale4To6Range().Addr().As16()
  121. v4 := ipv4.As4()
  122. copy(ret[13:], v4[1:])
  123. return netip.AddrFrom16(ret)
  124. }
  125. // Tailscale6to4 returns the IPv4 address corresponding to the given
  126. // tailscale IPv6 address within the 4To6 range. The IPv4 address
  127. // and true are returned if the given address was in the correct range,
  128. // false if not.
  129. func Tailscale6to4(ipv6 netip.Addr) (netip.Addr, bool) {
  130. if !ipv6.Is6() || !Tailscale4To6Range().Contains(ipv6) {
  131. return netip.Addr{}, false
  132. }
  133. v6 := ipv6.As16()
  134. return netip.AddrFrom4([4]byte{100, v6[13], v6[14], v6[15]}), true
  135. }
  136. func mustPrefix(v *netip.Prefix, prefix string) {
  137. var err error
  138. *v, err = netip.ParsePrefix(prefix)
  139. if err != nil {
  140. panic(err)
  141. }
  142. }
  143. type oncePrefix struct {
  144. sync.Once
  145. v netip.Prefix
  146. }
  147. // PrefixesContainsIP reports whether any prefix in ipp contains ip.
  148. func PrefixesContainsIP(ipp []netip.Prefix, ip netip.Addr) bool {
  149. for _, r := range ipp {
  150. if r.Contains(ip) {
  151. return true
  152. }
  153. }
  154. return false
  155. }
  156. // PrefixIs4 reports whether p is an IPv4 prefix.
  157. func PrefixIs4(p netip.Prefix) bool { return p.Addr().Is4() }
  158. // PrefixIs6 reports whether p is an IPv6 prefix.
  159. func PrefixIs6(p netip.Prefix) bool { return p.Addr().Is6() }
  160. // ContainsExitRoutes reports whether rr contains both the IPv4 and
  161. // IPv6 /0 route.
  162. func ContainsExitRoutes(rr views.Slice[netip.Prefix]) bool {
  163. var v4, v6 bool
  164. for _, r := range rr.All() {
  165. if r == allIPv4 {
  166. v4 = true
  167. } else if r == allIPv6 {
  168. v6 = true
  169. }
  170. }
  171. return v4 && v6
  172. }
  173. // ContainsExitRoute reports whether rr contains at least one of IPv4 or
  174. // IPv6 /0 (exit) routes.
  175. func ContainsExitRoute(rr views.Slice[netip.Prefix]) bool {
  176. for _, r := range rr.All() {
  177. if r.Bits() == 0 {
  178. return true
  179. }
  180. }
  181. return false
  182. }
  183. // ContainsNonExitSubnetRoutes reports whether v contains Subnet
  184. // Routes other than ExitNode Routes.
  185. func ContainsNonExitSubnetRoutes(rr views.Slice[netip.Prefix]) bool {
  186. for _, r := range rr.All() {
  187. if r.Bits() != 0 {
  188. return true
  189. }
  190. }
  191. return false
  192. }
  193. // WithoutExitRoutes returns rr unchanged if it has only 1 or 0 /0
  194. // routes. If it has both IPv4 and IPv6 /0 routes, then it returns
  195. // a copy with all /0 routes removed.
  196. func WithoutExitRoutes(rr views.Slice[netip.Prefix]) views.Slice[netip.Prefix] {
  197. if !ContainsExitRoutes(rr) {
  198. return rr
  199. }
  200. var out []netip.Prefix
  201. for _, r := range rr.All() {
  202. if r.Bits() > 0 {
  203. out = append(out, r)
  204. }
  205. }
  206. return views.SliceOf(out)
  207. }
  208. // WithoutExitRoute returns rr unchanged if it has 0 /0
  209. // routes. If it has a IPv4 or IPv6 /0 routes, then it returns
  210. // a copy with all /0 routes removed.
  211. func WithoutExitRoute(rr views.Slice[netip.Prefix]) views.Slice[netip.Prefix] {
  212. if !ContainsExitRoute(rr) {
  213. return rr
  214. }
  215. var out []netip.Prefix
  216. for _, r := range rr.All() {
  217. if r.Bits() > 0 {
  218. out = append(out, r)
  219. }
  220. }
  221. return views.SliceOf(out)
  222. }
  223. var (
  224. allIPv4 = netip.MustParsePrefix("0.0.0.0/0")
  225. allIPv6 = netip.MustParsePrefix("::/0")
  226. )
  227. // AllIPv4 returns 0.0.0.0/0.
  228. func AllIPv4() netip.Prefix { return allIPv4 }
  229. // AllIPv6 returns ::/0.
  230. func AllIPv6() netip.Prefix { return allIPv6 }
  231. // ExitRoutes returns a slice containing AllIPv4 and AllIPv6.
  232. func ExitRoutes() []netip.Prefix { return []netip.Prefix{allIPv4, allIPv6} }
  233. // IsExitRoute reports whether p is an exit node route.
  234. func IsExitRoute(p netip.Prefix) bool {
  235. return p == allIPv4 || p == allIPv6
  236. }
  237. // SortPrefixes sorts the prefixes in place.
  238. func SortPrefixes(p []netip.Prefix) {
  239. slices.SortFunc(p, netipx.ComparePrefix)
  240. }
  241. // FilterPrefixes returns a new slice, not aliasing in, containing elements of
  242. // in that match f.
  243. func FilterPrefixesCopy(in views.Slice[netip.Prefix], f func(netip.Prefix) bool) []netip.Prefix {
  244. var out []netip.Prefix
  245. for i := range in.Len() {
  246. if v := in.At(i); f(v) {
  247. out = append(out, v)
  248. }
  249. }
  250. return out
  251. }
  252. // IsViaPrefix reports whether p is a CIDR in the Tailscale "via" range.
  253. // See TailscaleViaRange.
  254. func IsViaPrefix(p netip.Prefix) bool {
  255. return TailscaleViaRange().Contains(p.Addr())
  256. }
  257. // UnmapVia returns the IPv4 address that corresponds to the provided Tailscale
  258. // "via" IPv4-in-IPv6 address.
  259. //
  260. // If ip is not a via address, it returns ip unchanged.
  261. func UnmapVia(ip netip.Addr) netip.Addr {
  262. if TailscaleViaRange().Contains(ip) {
  263. a := ip.As16()
  264. return netip.AddrFrom4(*(*[4]byte)(a[12:16]))
  265. }
  266. return ip
  267. }
  268. // MapVia returns an IPv6 "via" route for an IPv4 CIDR in a given siteID.
  269. func MapVia(siteID uint32, v4 netip.Prefix) (via netip.Prefix, err error) {
  270. if !v4.Addr().Is4() {
  271. return via, errors.New("want IPv4 CIDR with a site ID")
  272. }
  273. viaRange16 := TailscaleViaRange().Addr().As16()
  274. var a [16]byte
  275. copy(a[:], viaRange16[:8])
  276. binary.BigEndian.PutUint32(a[8:], siteID)
  277. ip4a := v4.Addr().As4()
  278. copy(a[12:], ip4a[:])
  279. return netip.PrefixFrom(netip.AddrFrom16(a), v4.Bits()+64+32), nil
  280. }