methods.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright (C) 2015 Audrius Butkevicius and Contributors (see the CONTRIBUTORS file).
  2. package client
  3. import (
  4. "context"
  5. "crypto/tls"
  6. "fmt"
  7. "net"
  8. "net/url"
  9. "strconv"
  10. "time"
  11. "github.com/syncthing/syncthing/lib/dialer"
  12. syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
  13. "github.com/syncthing/syncthing/lib/relay/protocol"
  14. )
  15. type incorrectResponseCodeErr struct {
  16. code int32
  17. msg string
  18. }
  19. func (e *incorrectResponseCodeErr) Error() string {
  20. return fmt.Sprintf("incorrect response code %d: %s", e.code, e.msg)
  21. }
  22. func GetInvitationFromRelay(ctx context.Context, uri *url.URL, id syncthingprotocol.DeviceID, certs []tls.Certificate, timeout time.Duration) (protocol.SessionInvitation, error) {
  23. if uri.Scheme != "relay" {
  24. return protocol.SessionInvitation{}, fmt.Errorf("unsupported relay scheme: %v", uri.Scheme)
  25. }
  26. ctx, cancel := context.WithTimeout(ctx, timeout)
  27. defer cancel()
  28. rconn, err := dialer.DialContext(ctx, "tcp", uri.Host)
  29. if err != nil {
  30. return protocol.SessionInvitation{}, err
  31. }
  32. conn := tls.Client(rconn, configForCerts(certs))
  33. conn.SetDeadline(time.Now().Add(timeout))
  34. if err := performHandshakeAndValidation(conn, uri); err != nil {
  35. return protocol.SessionInvitation{}, err
  36. }
  37. defer conn.Close()
  38. request := protocol.ConnectRequest{
  39. ID: id[:],
  40. }
  41. if err := protocol.WriteMessage(conn, request); err != nil {
  42. return protocol.SessionInvitation{}, err
  43. }
  44. message, err := protocol.ReadMessage(conn)
  45. if err != nil {
  46. return protocol.SessionInvitation{}, err
  47. }
  48. switch msg := message.(type) {
  49. case protocol.Response:
  50. return protocol.SessionInvitation{}, &incorrectResponseCodeErr{msg.Code, msg.Message}
  51. case protocol.SessionInvitation:
  52. l.Debugln("Received invitation", msg, "via", conn.LocalAddr())
  53. ip := net.IP(msg.Address)
  54. if len(ip) == 0 || ip.IsUnspecified() {
  55. msg.Address = remoteIPBytes(conn)
  56. }
  57. return msg, nil
  58. default:
  59. return protocol.SessionInvitation{}, fmt.Errorf("protocol error: unexpected message %v", msg)
  60. }
  61. }
  62. func JoinSession(ctx context.Context, invitation protocol.SessionInvitation) (net.Conn, error) {
  63. addr := net.JoinHostPort(net.IP(invitation.Address).String(), strconv.Itoa(int(invitation.Port)))
  64. ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
  65. defer cancel()
  66. conn, err := dialer.DialContext(ctx, "tcp", addr)
  67. if err != nil {
  68. return nil, err
  69. }
  70. request := protocol.JoinSessionRequest{
  71. Key: invitation.Key,
  72. }
  73. conn.SetDeadline(time.Now().Add(10 * time.Second))
  74. err = protocol.WriteMessage(conn, request)
  75. if err != nil {
  76. return nil, err
  77. }
  78. message, err := protocol.ReadMessage(conn)
  79. if err != nil {
  80. return nil, err
  81. }
  82. conn.SetDeadline(time.Time{})
  83. switch msg := message.(type) {
  84. case protocol.Response:
  85. if msg.Code != 0 {
  86. return nil, fmt.Errorf("incorrect response code %d: %s", msg.Code, msg.Message)
  87. }
  88. return conn, nil
  89. default:
  90. return nil, fmt.Errorf("protocol error: expecting response got %v", msg)
  91. }
  92. }
  93. func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep, timeout time.Duration, times int) error {
  94. id := syncthingprotocol.NewDeviceID(certs[0].Certificate[0])
  95. invs := make(chan protocol.SessionInvitation, 1)
  96. c, err := NewClient(uri, certs, invs, timeout)
  97. if err != nil {
  98. close(invs)
  99. return fmt.Errorf("creating client: %w", err)
  100. }
  101. go c.Serve()
  102. defer func() {
  103. c.Stop()
  104. close(invs)
  105. }()
  106. for i := 0; i < times; i++ {
  107. _, err = GetInvitationFromRelay(ctx, uri, id, certs, timeout)
  108. if err == nil {
  109. return nil
  110. }
  111. if _, ok := err.(*incorrectResponseCodeErr); !ok {
  112. return fmt.Errorf("getting invitation: %w", err)
  113. }
  114. time.Sleep(sleep)
  115. }
  116. return fmt.Errorf("getting invitation: %w", err) // last of the above errors
  117. }
  118. func configForCerts(certs []tls.Certificate) *tls.Config {
  119. return &tls.Config{
  120. Certificates: certs,
  121. NextProtos: []string{protocol.ProtocolName},
  122. ClientAuth: tls.RequestClientCert,
  123. SessionTicketsDisabled: true,
  124. InsecureSkipVerify: true,
  125. MinVersion: tls.VersionTLS12,
  126. CipherSuites: []uint16{
  127. tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  128. tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  129. tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  130. tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  131. tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  132. tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  133. },
  134. }
  135. }
  136. func remoteIPBytes(conn net.Conn) []byte {
  137. addr := conn.RemoteAddr().String()
  138. if host, _, err := net.SplitHostPort(addr); err == nil {
  139. addr = host
  140. }
  141. return net.ParseIP(addr)[:]
  142. }