1
0

service.go 15 KB

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