methods.go 3.8 KB

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