methods.go 4.2 KB

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