server.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package main
  4. import (
  5. "expvar"
  6. "log"
  7. "net"
  8. "net/netip"
  9. "sync"
  10. "time"
  11. "golang.org/x/net/dns/dnsmessage"
  12. "tailscale.com/metrics"
  13. "tailscale.com/tailcfg"
  14. "tailscale.com/types/appctype"
  15. "tailscale.com/types/ipproto"
  16. "tailscale.com/types/nettype"
  17. "tailscale.com/util/clientmetric"
  18. "tailscale.com/util/mak"
  19. )
  20. var tsMBox = dnsmessage.MustNewName("support.tailscale.com.")
  21. // target describes the predicates which route some inbound
  22. // traffic to the app connector to a specific handler.
  23. type target struct {
  24. Dest netip.Prefix
  25. Matching tailcfg.ProtoPortRange
  26. }
  27. // Server implements an App Connector as expressed in sniproxy.
  28. type Server struct {
  29. mu sync.RWMutex // mu guards following fields
  30. connectors map[appctype.ConfigID]connector
  31. }
  32. type appcMetrics struct {
  33. dnsResponses expvar.Int
  34. dnsFailures expvar.Int
  35. tcpConns expvar.Int
  36. sniConns expvar.Int
  37. unhandledConns expvar.Int
  38. }
  39. var getMetrics = sync.OnceValue[*appcMetrics](func() *appcMetrics {
  40. m := appcMetrics{}
  41. stats := new(metrics.Set)
  42. stats.Set("tls_sessions", &m.sniConns)
  43. clientmetric.NewCounterFunc("sniproxy_tls_sessions", m.sniConns.Value)
  44. stats.Set("tcp_sessions", &m.tcpConns)
  45. clientmetric.NewCounterFunc("sniproxy_tcp_sessions", m.tcpConns.Value)
  46. stats.Set("dns_responses", &m.dnsResponses)
  47. clientmetric.NewCounterFunc("sniproxy_dns_responses", m.dnsResponses.Value)
  48. stats.Set("dns_failed", &m.dnsFailures)
  49. clientmetric.NewCounterFunc("sniproxy_dns_failed", m.dnsFailures.Value)
  50. expvar.Publish("sniproxy", stats)
  51. return &m
  52. })
  53. // Configure applies the provided configuration to the app connector.
  54. func (s *Server) Configure(cfg *appctype.AppConnectorConfig) {
  55. s.mu.Lock()
  56. defer s.mu.Unlock()
  57. s.connectors = makeConnectorsFromConfig(cfg)
  58. log.Printf("installed app connector config: %+v", s.connectors)
  59. }
  60. // HandleTCPFlow implements tsnet.FallbackTCPHandler.
  61. func (s *Server) HandleTCPFlow(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
  62. m := getMetrics()
  63. s.mu.RLock()
  64. defer s.mu.RUnlock()
  65. for _, c := range s.connectors {
  66. if handler, intercept := c.handleTCPFlow(src, dst, m); intercept {
  67. return handler, intercept
  68. }
  69. }
  70. return nil, false
  71. }
  72. // HandleDNS handles a DNS request to the app connector.
  73. func (s *Server) HandleDNS(c nettype.ConnPacketConn) {
  74. defer c.Close()
  75. c.SetReadDeadline(time.Now().Add(5 * time.Second))
  76. m := getMetrics()
  77. buf := make([]byte, 1500)
  78. n, err := c.Read(buf)
  79. if err != nil {
  80. log.Printf("HandleDNS: read failed: %v\n ", err)
  81. m.dnsFailures.Add(1)
  82. return
  83. }
  84. addrPortStr := c.LocalAddr().String()
  85. host, _, err := net.SplitHostPort(addrPortStr)
  86. if err != nil {
  87. log.Printf("HandleDNS: bogus addrPort %q", addrPortStr)
  88. m.dnsFailures.Add(1)
  89. return
  90. }
  91. localAddr, err := netip.ParseAddr(host)
  92. if err != nil {
  93. log.Printf("HandleDNS: bogus local address %q", host)
  94. m.dnsFailures.Add(1)
  95. return
  96. }
  97. var msg dnsmessage.Message
  98. err = msg.Unpack(buf[:n])
  99. if err != nil {
  100. log.Printf("HandleDNS: dnsmessage unpack failed: %v\n ", err)
  101. m.dnsFailures.Add(1)
  102. return
  103. }
  104. s.mu.RLock()
  105. defer s.mu.RUnlock()
  106. for _, connector := range s.connectors {
  107. resp, err := connector.handleDNS(&msg, localAddr)
  108. if err != nil {
  109. log.Printf("HandleDNS: connector handling failed: %v\n", err)
  110. m.dnsFailures.Add(1)
  111. return
  112. }
  113. if len(resp) > 0 {
  114. // This connector handled the DNS request
  115. _, err = c.Write(resp)
  116. if err != nil {
  117. log.Printf("HandleDNS: write failed: %v\n", err)
  118. m.dnsFailures.Add(1)
  119. return
  120. }
  121. m.dnsResponses.Add(1)
  122. return
  123. }
  124. }
  125. }
  126. // connector describes a logical collection of
  127. // services which need to be proxied.
  128. type connector struct {
  129. Handlers map[target]handler
  130. }
  131. // handleTCPFlow implements tsnet.FallbackTCPHandler.
  132. func (c *connector) handleTCPFlow(src, dst netip.AddrPort, m *appcMetrics) (handler func(net.Conn), intercept bool) {
  133. for t, h := range c.Handlers {
  134. if t.Matching.Proto != 0 && t.Matching.Proto != int(ipproto.TCP) {
  135. continue
  136. }
  137. if !t.Dest.Contains(dst.Addr()) {
  138. continue
  139. }
  140. if !t.Matching.Ports.Contains(dst.Port()) {
  141. continue
  142. }
  143. switch h.(type) {
  144. case *tcpSNIHandler:
  145. m.sniConns.Add(1)
  146. case *tcpRoundRobinHandler:
  147. m.tcpConns.Add(1)
  148. default:
  149. log.Printf("handleTCPFlow: unhandled handler type %T", h)
  150. }
  151. return h.Handle, true
  152. }
  153. m.unhandledConns.Add(1)
  154. return nil, false
  155. }
  156. // handleDNS returns the DNS response to the given query. If this
  157. // connector is unable to handle the request, nil is returned.
  158. func (c *connector) handleDNS(req *dnsmessage.Message, localAddr netip.Addr) (response []byte, err error) {
  159. for t, h := range c.Handlers {
  160. if t.Dest.Contains(localAddr) {
  161. return makeDNSResponse(req, h.ReachableOn())
  162. }
  163. }
  164. // Did not match, signal 'not handled' to caller
  165. return nil, nil
  166. }
  167. func makeDNSResponse(req *dnsmessage.Message, reachableIPs []netip.Addr) (response []byte, err error) {
  168. resp := dnsmessage.NewBuilder(response,
  169. dnsmessage.Header{
  170. ID: req.Header.ID,
  171. Response: true,
  172. Authoritative: true,
  173. })
  174. resp.EnableCompression()
  175. if len(req.Questions) == 0 {
  176. response, _ = resp.Finish()
  177. return response, nil
  178. }
  179. q := req.Questions[0]
  180. err = resp.StartQuestions()
  181. if err != nil {
  182. return
  183. }
  184. resp.Question(q)
  185. err = resp.StartAnswers()
  186. if err != nil {
  187. return
  188. }
  189. switch q.Type {
  190. case dnsmessage.TypeAAAA:
  191. for _, ip := range reachableIPs {
  192. if ip.Is6() {
  193. err = resp.AAAAResource(
  194. dnsmessage.ResourceHeader{Name: q.Name, Class: q.Class, TTL: 120},
  195. dnsmessage.AAAAResource{AAAA: ip.As16()},
  196. )
  197. }
  198. }
  199. case dnsmessage.TypeA:
  200. for _, ip := range reachableIPs {
  201. if ip.Is4() {
  202. err = resp.AResource(
  203. dnsmessage.ResourceHeader{Name: q.Name, Class: q.Class, TTL: 120},
  204. dnsmessage.AResource{A: ip.As4()},
  205. )
  206. }
  207. }
  208. case dnsmessage.TypeSOA:
  209. err = resp.SOAResource(
  210. dnsmessage.ResourceHeader{Name: q.Name, Class: q.Class, TTL: 120},
  211. dnsmessage.SOAResource{NS: q.Name, MBox: tsMBox, Serial: 2023030600,
  212. Refresh: 120, Retry: 120, Expire: 120, MinTTL: 60},
  213. )
  214. case dnsmessage.TypeNS:
  215. err = resp.NSResource(
  216. dnsmessage.ResourceHeader{Name: q.Name, Class: q.Class, TTL: 120},
  217. dnsmessage.NSResource{NS: tsMBox},
  218. )
  219. }
  220. if err != nil {
  221. return nil, err
  222. }
  223. return resp.Finish()
  224. }
  225. type handler interface {
  226. // Handle handles the given socket.
  227. Handle(c net.Conn)
  228. // ReachableOn returns the IP addresses this handler is reachable on.
  229. ReachableOn() []netip.Addr
  230. }
  231. func installDNATHandler(d *appctype.DNATConfig, out *connector) {
  232. // These handlers don't actually do DNAT, they just
  233. // proxy the data over the connection.
  234. var dialer net.Dialer
  235. dialer.Timeout = 5 * time.Second
  236. h := tcpRoundRobinHandler{
  237. To: d.To,
  238. DialContext: dialer.DialContext,
  239. ReachableIPs: d.Addrs,
  240. }
  241. for _, addr := range d.Addrs {
  242. for _, protoPort := range d.IP {
  243. t := target{
  244. Dest: netip.PrefixFrom(addr, addr.BitLen()),
  245. Matching: protoPort,
  246. }
  247. mak.Set(&out.Handlers, t, handler(&h))
  248. }
  249. }
  250. }
  251. func installSNIHandler(c *appctype.SNIProxyConfig, out *connector) {
  252. var dialer net.Dialer
  253. dialer.Timeout = 5 * time.Second
  254. h := tcpSNIHandler{
  255. Allowlist: c.AllowedDomains,
  256. DialContext: dialer.DialContext,
  257. ReachableIPs: c.Addrs,
  258. }
  259. for _, addr := range c.Addrs {
  260. for _, protoPort := range c.IP {
  261. t := target{
  262. Dest: netip.PrefixFrom(addr, addr.BitLen()),
  263. Matching: protoPort,
  264. }
  265. mak.Set(&out.Handlers, t, handler(&h))
  266. }
  267. }
  268. }
  269. func makeConnectorsFromConfig(cfg *appctype.AppConnectorConfig) map[appctype.ConfigID]connector {
  270. var connectors map[appctype.ConfigID]connector
  271. for cID, d := range cfg.DNAT {
  272. c := connectors[cID]
  273. installDNATHandler(&d, &c)
  274. mak.Set(&connectors, cID, c)
  275. }
  276. for cID, d := range cfg.SNIProxy {
  277. c := connectors[cID]
  278. installSNIHandler(&d, &c)
  279. mak.Set(&connectors, cID, c)
  280. }
  281. return connectors
  282. }