mesh.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package main
  4. import (
  5. "context"
  6. "errors"
  7. "fmt"
  8. "log"
  9. "net"
  10. "strings"
  11. "tailscale.com/derp"
  12. "tailscale.com/derp/derphttp"
  13. "tailscale.com/net/netmon"
  14. "tailscale.com/types/logger"
  15. )
  16. func startMesh(s *derp.Server) error {
  17. if *meshWith == "" {
  18. return nil
  19. }
  20. if !s.HasMeshKey() {
  21. return errors.New("--mesh-with requires --mesh-psk-file")
  22. }
  23. for _, hostTuple := range strings.Split(*meshWith, ",") {
  24. if err := startMeshWithHost(s, hostTuple); err != nil {
  25. return err
  26. }
  27. }
  28. return nil
  29. }
  30. func startMeshWithHost(s *derp.Server, hostTuple string) error {
  31. var host string
  32. var dialHost string
  33. hostParts := strings.Split(hostTuple, "/")
  34. if len(hostParts) > 2 {
  35. return fmt.Errorf("too many components in host tuple %q", hostTuple)
  36. }
  37. host = hostParts[0]
  38. if len(hostParts) == 2 {
  39. dialHost = hostParts[1]
  40. } else {
  41. dialHost = hostParts[0]
  42. }
  43. logf := logger.WithPrefix(log.Printf, fmt.Sprintf("mesh(%q): ", host))
  44. netMon := netmon.NewStatic() // good enough for cmd/derper; no need for netns fanciness
  45. c, err := derphttp.NewClient(s.PrivateKey(), "https://"+host+"/derp", logf, netMon)
  46. if err != nil {
  47. return err
  48. }
  49. c.MeshKey = s.MeshKey()
  50. c.WatchConnectionChanges = true
  51. logf("will dial %q for %q", dialHost, host)
  52. if dialHost != host {
  53. var d net.Dialer
  54. c.SetURLDialer(func(ctx context.Context, network, addr string) (net.Conn, error) {
  55. _, port, err := net.SplitHostPort(addr)
  56. if err != nil {
  57. logf("failed to split %q: %v", addr, err)
  58. return nil, err
  59. }
  60. dialAddr := net.JoinHostPort(dialHost, port)
  61. logf("dialing %q instead of %q", dialAddr, addr)
  62. return d.DialContext(ctx, network, dialAddr)
  63. })
  64. }
  65. add := func(m derp.PeerPresentMessage) { s.AddPacketForwarder(m.Key, c) }
  66. remove := func(m derp.PeerGoneMessage) { s.RemovePacketForwarder(m.Peer, c) }
  67. go c.RunWatchConnectionLoop(context.Background(), s.PublicKey(), logf, add, remove)
  68. return nil
  69. }