service.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. package derp
  2. import (
  3. "bufio"
  4. "context"
  5. stdTLS "crypto/tls"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "net"
  10. "net/http"
  11. "net/netip"
  12. "os"
  13. "path/filepath"
  14. "regexp"
  15. "strings"
  16. "time"
  17. "github.com/sagernet/sing-box/adapter"
  18. boxService "github.com/sagernet/sing-box/adapter/service"
  19. "github.com/sagernet/sing-box/common/dialer"
  20. "github.com/sagernet/sing-box/common/listener"
  21. "github.com/sagernet/sing-box/common/tls"
  22. C "github.com/sagernet/sing-box/constant"
  23. "github.com/sagernet/sing-box/log"
  24. "github.com/sagernet/sing-box/option"
  25. boxScale "github.com/sagernet/sing-box/protocol/tailscale"
  26. "github.com/sagernet/sing/common"
  27. E "github.com/sagernet/sing/common/exceptions"
  28. F "github.com/sagernet/sing/common/format"
  29. "github.com/sagernet/sing/common/json/badoption"
  30. "github.com/sagernet/sing/common/logger"
  31. M "github.com/sagernet/sing/common/metadata"
  32. N "github.com/sagernet/sing/common/network"
  33. "github.com/sagernet/sing/common/ntp"
  34. aTLS "github.com/sagernet/sing/common/tls"
  35. "github.com/sagernet/sing/service"
  36. "github.com/sagernet/sing/service/filemanager"
  37. "github.com/sagernet/tailscale/client/local"
  38. "github.com/sagernet/tailscale/derp"
  39. "github.com/sagernet/tailscale/derp/derphttp"
  40. "github.com/sagernet/tailscale/derp/derpserver"
  41. "github.com/sagernet/tailscale/net/netmon"
  42. "github.com/sagernet/tailscale/net/stun"
  43. "github.com/sagernet/tailscale/net/wsconn"
  44. "github.com/sagernet/tailscale/tsweb"
  45. "github.com/sagernet/tailscale/types/key"
  46. "github.com/coder/websocket"
  47. "github.com/go-chi/render"
  48. "golang.org/x/net/http2"
  49. "golang.org/x/net/http2/h2c"
  50. )
  51. func Register(registry *boxService.Registry) {
  52. boxService.Register[option.DERPServiceOptions](registry, C.TypeDERP, NewService)
  53. }
  54. type Service struct {
  55. boxService.Adapter
  56. ctx context.Context
  57. logger logger.ContextLogger
  58. listener *listener.Listener
  59. stunListener *listener.Listener
  60. tlsConfig tls.ServerConfig
  61. server *derpserver.Server
  62. configPath string
  63. verifyClientEndpoint []string
  64. verifyClientURL []*option.DERPVerifyClientURLOptions
  65. home string
  66. meshKey string
  67. meshKeyPath string
  68. meshWith []*option.DERPMeshOptions
  69. }
  70. func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.DERPServiceOptions) (adapter.Service, error) {
  71. if options.TLS == nil || !options.TLS.Enabled {
  72. return nil, E.New("TLS is required for DERP server")
  73. }
  74. tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS))
  75. if err != nil {
  76. return nil, err
  77. }
  78. var configPath string
  79. if options.ConfigPath != "" {
  80. configPath = filemanager.BasePath(ctx, os.ExpandEnv(options.ConfigPath))
  81. } else {
  82. return nil, E.New("missing config_path")
  83. }
  84. if options.MeshPSK != "" {
  85. err = checkMeshKey(options.MeshPSK)
  86. if err != nil {
  87. return nil, E.Cause(err, "invalid mesh_psk")
  88. }
  89. }
  90. var stunListener *listener.Listener
  91. if options.STUN != nil && options.STUN.Enabled {
  92. if options.STUN.Listen == nil {
  93. options.STUN.Listen = (*badoption.Addr)(common.Ptr(netip.IPv6Unspecified()))
  94. }
  95. if options.STUN.ListenPort == 0 {
  96. options.STUN.ListenPort = 3478
  97. }
  98. stunListener = listener.New(listener.Options{
  99. Context: ctx,
  100. Logger: logger,
  101. Network: []string{N.NetworkUDP},
  102. Listen: options.STUN.ListenOptions,
  103. })
  104. }
  105. return &Service{
  106. Adapter: boxService.NewAdapter(C.TypeDERP, tag),
  107. ctx: ctx,
  108. logger: logger,
  109. listener: listener.New(listener.Options{
  110. Context: ctx,
  111. Logger: logger,
  112. Network: []string{N.NetworkTCP},
  113. Listen: options.ListenOptions,
  114. }),
  115. stunListener: stunListener,
  116. tlsConfig: tlsConfig,
  117. configPath: configPath,
  118. verifyClientEndpoint: options.VerifyClientEndpoint,
  119. verifyClientURL: options.VerifyClientURL,
  120. home: options.Home,
  121. meshKey: options.MeshPSK,
  122. meshKeyPath: options.MeshPSKFile,
  123. meshWith: options.MeshWith,
  124. }, nil
  125. }
  126. func (d *Service) Start(stage adapter.StartStage) error {
  127. switch stage {
  128. case adapter.StartStateStart:
  129. config, err := readDERPConfig(filemanager.BasePath(d.ctx, d.configPath))
  130. if err != nil {
  131. return err
  132. }
  133. server := derpserver.New(config.PrivateKey, func(format string, args ...any) {
  134. d.logger.Debug(fmt.Sprintf(format, args...))
  135. })
  136. if len(d.verifyClientURL) > 0 {
  137. var httpClients []*http.Client
  138. var urls []string
  139. for index, options := range d.verifyClientURL {
  140. verifyDialer, createErr := dialer.NewWithOptions(dialer.Options{
  141. Context: d.ctx,
  142. Options: options.DialerOptions,
  143. RemoteIsDomain: options.ServerIsDomain(),
  144. NewDialer: true,
  145. })
  146. if createErr != nil {
  147. return E.Cause(createErr, "verify_client_url[", index, "]")
  148. }
  149. httpClients = append(httpClients, &http.Client{
  150. Transport: &http.Transport{
  151. ForceAttemptHTTP2: true,
  152. TLSClientConfig: &stdTLS.Config{
  153. RootCAs: adapter.RootPoolFromContext(d.ctx),
  154. Time: ntp.TimeFuncFromContext(d.ctx),
  155. },
  156. DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
  157. return verifyDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
  158. },
  159. },
  160. })
  161. urls = append(urls, options.URL)
  162. }
  163. server.SetVerifyClientHTTPClient(httpClients)
  164. server.SetVerifyClientURL(urls)
  165. }
  166. if d.meshKey != "" {
  167. server.SetMeshKey(d.meshKey)
  168. } else if d.meshKeyPath != "" {
  169. var meshKeyContent []byte
  170. meshKeyContent, err = os.ReadFile(d.meshKeyPath)
  171. if err != nil {
  172. return err
  173. }
  174. err = checkMeshKey(string(meshKeyContent))
  175. if err != nil {
  176. return E.Cause(err, "invalid mesh_psk_path file")
  177. }
  178. server.SetMeshKey(string(meshKeyContent))
  179. }
  180. d.server = server
  181. derpMux := http.NewServeMux()
  182. derpHandler := derpserver.Handler(server)
  183. derpHandler = addWebSocketSupport(server, derpHandler)
  184. derpMux.Handle("/derp", derpHandler)
  185. homeHandler, ok := getHomeHandler(d.home)
  186. if !ok {
  187. return E.New("invalid home value: ", d.home)
  188. }
  189. derpMux.HandleFunc("/derp/probe", derpserver.ProbeHandler)
  190. derpMux.HandleFunc("/derp/latency-check", derpserver.ProbeHandler)
  191. derpMux.HandleFunc("/bootstrap-dns", tsweb.BrowserHeaderHandlerFunc(handleBootstrapDNS(d.ctx)))
  192. derpMux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  193. tsweb.AddBrowserHeaders(w)
  194. homeHandler.ServeHTTP(w, r)
  195. }))
  196. derpMux.Handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  197. tsweb.AddBrowserHeaders(w)
  198. io.WriteString(w, "User-agent: *\nDisallow: /\n")
  199. }))
  200. derpMux.Handle("/generate_204", http.HandlerFunc(derpserver.ServeNoContent))
  201. err = d.tlsConfig.Start()
  202. if err != nil {
  203. return err
  204. }
  205. tcpListener, err := d.listener.ListenTCP()
  206. if err != nil {
  207. return err
  208. }
  209. if len(d.tlsConfig.NextProtos()) == 0 {
  210. d.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
  211. } else if !common.Contains(d.tlsConfig.NextProtos(), http2.NextProtoTLS) {
  212. d.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, d.tlsConfig.NextProtos()...))
  213. }
  214. tcpListener = aTLS.NewListener(tcpListener, d.tlsConfig)
  215. httpServer := &http.Server{
  216. Handler: h2c.NewHandler(derpMux, &http2.Server{}),
  217. }
  218. go httpServer.Serve(tcpListener)
  219. if d.stunListener != nil {
  220. stunConn, err := d.stunListener.ListenUDP()
  221. if err != nil {
  222. return err
  223. }
  224. go d.loopSTUNPacket(stunConn.(*net.UDPConn))
  225. }
  226. case adapter.StartStatePostStart:
  227. if len(d.verifyClientEndpoint) > 0 {
  228. var endpoints []*local.Client
  229. endpointManager := service.FromContext[adapter.EndpointManager](d.ctx)
  230. for _, endpointTag := range d.verifyClientEndpoint {
  231. endpoint, loaded := endpointManager.Get(endpointTag)
  232. if !loaded {
  233. return E.New("verify_client_endpoint: endpoint not found: ", endpointTag)
  234. }
  235. tsEndpoint, isTailscale := endpoint.(*boxScale.Endpoint)
  236. if !isTailscale {
  237. return E.New("verify_client_endpoint: endpoint is not Tailscale: ", endpointTag)
  238. }
  239. localClient, err := tsEndpoint.Server().LocalClient()
  240. if err != nil {
  241. return err
  242. }
  243. endpoints = append(endpoints, localClient)
  244. }
  245. d.server.SetVerifyClientLocalClient(endpoints)
  246. }
  247. if len(d.meshWith) > 0 {
  248. if !d.server.HasMeshKey() {
  249. return E.New("missing mesh psk")
  250. }
  251. for _, options := range d.meshWith {
  252. err := d.startMeshWithHost(d.server, options)
  253. if err != nil {
  254. return err
  255. }
  256. }
  257. }
  258. }
  259. return nil
  260. }
  261. func checkMeshKey(meshKey string) error {
  262. checkRegex, err := regexp.Compile(`^[0-9a-f]{64}$`)
  263. if err != nil {
  264. return err
  265. }
  266. if !checkRegex.MatchString(meshKey) {
  267. return E.New("key must contain exactly 64 hex digits")
  268. }
  269. return nil
  270. }
  271. func (d *Service) startMeshWithHost(derpServer *derpserver.Server, server *option.DERPMeshOptions) error {
  272. meshDialer, err := dialer.NewWithOptions(dialer.Options{
  273. Context: d.ctx,
  274. Options: server.DialerOptions,
  275. RemoteIsDomain: server.ServerIsDomain(),
  276. NewDialer: true,
  277. })
  278. if err != nil {
  279. return err
  280. }
  281. var hostname string
  282. if server.Host != "" {
  283. hostname = server.Host
  284. } else {
  285. hostname = server.Server
  286. }
  287. var stdConfig *tls.STDConfig
  288. if server.TLS != nil && server.TLS.Enabled {
  289. tlsConfig, err := tls.NewClient(d.ctx, d.logger, hostname, common.PtrValueOrDefault(server.TLS))
  290. if err != nil {
  291. return err
  292. }
  293. stdConfig, err = tlsConfig.STDConfig()
  294. if err != nil {
  295. return err
  296. }
  297. }
  298. logf := func(format string, args ...any) {
  299. d.logger.Debug(F.ToString("mesh(", hostname, "): ", fmt.Sprintf(format, args...)))
  300. }
  301. var meshHost string
  302. if server.ServerPort == 0 || server.ServerPort == 443 {
  303. meshHost = hostname
  304. } else {
  305. meshHost = M.ParseSocksaddrHostPort(hostname, server.ServerPort).String()
  306. }
  307. var serverURL string
  308. if stdConfig != nil {
  309. serverURL = "https://" + meshHost + "/derp"
  310. } else {
  311. serverURL = "http://" + meshHost + "/derp"
  312. }
  313. meshClient, err := derphttp.NewClient(derpServer.PrivateKey(), serverURL, logf, netmon.NewStatic())
  314. if err != nil {
  315. return err
  316. }
  317. meshClient.TLSConfig = stdConfig
  318. meshClient.MeshKey = derpServer.MeshKey()
  319. meshClient.WatchConnectionChanges = true
  320. meshClient.SetURLDialer(func(ctx context.Context, network, addr string) (net.Conn, error) {
  321. return meshDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
  322. })
  323. add := func(m derp.PeerPresentMessage) { derpServer.AddPacketForwarder(m.Key, meshClient) }
  324. remove := func(m derp.PeerGoneMessage) { derpServer.RemovePacketForwarder(m.Peer, meshClient) }
  325. notifyError := func(err error) { d.logger.Error(err) }
  326. go meshClient.RunWatchConnectionLoop(context.Background(), derpServer.PublicKey(), logf, add, remove, notifyError)
  327. return nil
  328. }
  329. func (d *Service) Close() error {
  330. return common.Close(
  331. common.PtrOrNil(d.listener),
  332. d.tlsConfig,
  333. )
  334. }
  335. var homePage = `
  336. <h1>DERP</h1>
  337. <p>
  338. This is a <a href="https://tailscale.com/">Tailscale</a> DERP server.
  339. </p>
  340. <p>
  341. It provides STUN, interactive connectivity establishment, and relaying of end-to-end encrypted traffic
  342. for Tailscale clients.
  343. </p>
  344. <p>
  345. Documentation:
  346. </p>
  347. <ul>
  348. <li><a href="https://tailscale.com/kb/1232/derp-servers">About DERP</a></li>
  349. <li><a href="https://pkg.go.dev/tailscale.com/derp">Protocol & Go docs</a></li>
  350. <li><a href="https://github.com/tailscale/tailscale/tree/main/cmd/derper#derp">How to run a DERP server</a></li>
  351. </body>
  352. </html>
  353. `
  354. func getHomeHandler(val string) (_ http.Handler, ok bool) {
  355. if val == "" {
  356. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  357. w.Header().Set("Content-Type", "text/html; charset=utf-8")
  358. w.WriteHeader(200)
  359. w.Write([]byte(homePage))
  360. }), true
  361. }
  362. if val == "blank" {
  363. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  364. w.Header().Set("Content-Type", "text/html; charset=utf-8")
  365. w.WriteHeader(200)
  366. }), true
  367. }
  368. if strings.HasPrefix(val, "http://") || strings.HasPrefix(val, "https://") {
  369. return http.RedirectHandler(val, http.StatusFound), true
  370. }
  371. return nil, false
  372. }
  373. func addWebSocketSupport(s *derpserver.Server, base http.Handler) http.Handler {
  374. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  375. up := strings.ToLower(r.Header.Get("Upgrade"))
  376. // Very early versions of Tailscale set "Upgrade: WebSocket" but didn't actually
  377. // speak WebSockets (they still assumed DERP's binary framing). So to distinguish
  378. // clients that actually want WebSockets, look for an explicit "derp" subprotocol.
  379. if up != "websocket" || !strings.Contains(r.Header.Get("Sec-Websocket-Protocol"), "derp") {
  380. base.ServeHTTP(w, r)
  381. return
  382. }
  383. c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
  384. Subprotocols: []string{"derp"},
  385. OriginPatterns: []string{"*"},
  386. // Disable compression because we transmit WireGuard messages that
  387. // are not compressible.
  388. // Additionally, Safari has a broken implementation of compression
  389. // (see https://github.com/nhooyr/websocket/issues/218) that makes
  390. // enabling it actively harmful.
  391. CompressionMode: websocket.CompressionDisabled,
  392. })
  393. if err != nil {
  394. return
  395. }
  396. defer c.Close(websocket.StatusInternalError, "closing")
  397. if c.Subprotocol() != "derp" {
  398. c.Close(websocket.StatusPolicyViolation, "client must speak the derp subprotocol")
  399. return
  400. }
  401. wc := wsconn.NetConn(r.Context(), c, websocket.MessageBinary, r.RemoteAddr)
  402. brw := bufio.NewReadWriter(bufio.NewReader(wc), bufio.NewWriter(wc))
  403. s.Accept(r.Context(), wc, brw, r.RemoteAddr)
  404. })
  405. }
  406. func handleBootstrapDNS(ctx context.Context) http.HandlerFunc {
  407. dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
  408. return func(w http.ResponseWriter, r *http.Request) {
  409. w.Header().Set("Content-Type", "application/json")
  410. w.Header().Set("Connection", "close")
  411. if queryDomain := r.URL.Query().Get("q"); queryDomain != "" {
  412. addresses, err := dnsRouter.Lookup(ctx, queryDomain, adapter.DNSQueryOptions{})
  413. if err != nil {
  414. w.WriteHeader(http.StatusInternalServerError)
  415. return
  416. }
  417. render.JSON(w, r, render.M{
  418. queryDomain: addresses,
  419. })
  420. return
  421. }
  422. w.Write([]byte("{}"))
  423. }
  424. }
  425. type derpConfig struct {
  426. PrivateKey key.NodePrivate
  427. }
  428. func readDERPConfig(path string) (*derpConfig, error) {
  429. content, err := os.ReadFile(path)
  430. if err != nil {
  431. if os.IsNotExist(err) {
  432. return writeNewDERPConfig(path)
  433. }
  434. return nil, err
  435. }
  436. var config derpConfig
  437. err = json.Unmarshal(content, &config)
  438. if err != nil {
  439. return nil, err
  440. }
  441. return &config, nil
  442. }
  443. func writeNewDERPConfig(path string) (*derpConfig, error) {
  444. newKey := key.NewNode()
  445. err := os.MkdirAll(filepath.Dir(path), 0o777)
  446. if err != nil {
  447. return nil, err
  448. }
  449. config := derpConfig{
  450. PrivateKey: newKey,
  451. }
  452. content, err := json.Marshal(config)
  453. if err != nil {
  454. return nil, err
  455. }
  456. err = os.WriteFile(path, content, 0o644)
  457. if err != nil {
  458. return nil, err
  459. }
  460. return &config, nil
  461. }
  462. func (d *Service) loopSTUNPacket(packetConn *net.UDPConn) {
  463. buffer := make([]byte, 65535)
  464. oob := make([]byte, 1024)
  465. var (
  466. n int
  467. oobN int
  468. addrPort netip.AddrPort
  469. err error
  470. )
  471. for {
  472. n, oobN, _, addrPort, err = packetConn.ReadMsgUDPAddrPort(buffer, oob)
  473. if err != nil {
  474. if E.IsClosedOrCanceled(err) {
  475. return
  476. }
  477. time.Sleep(time.Second)
  478. continue
  479. }
  480. if !stun.Is(buffer[:n]) {
  481. continue
  482. }
  483. txid, err := stun.ParseBindingRequest(buffer[:n])
  484. if err != nil {
  485. continue
  486. }
  487. packetConn.WriteMsgUDPAddrPort(stun.Response(txid, addrPort), oob[:oobN], addrPort)
  488. }
  489. }