structs.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package connections
  7. import (
  8. "context"
  9. "crypto/tls"
  10. "fmt"
  11. "io"
  12. "log/slog"
  13. "net"
  14. "net/url"
  15. "time"
  16. "github.com/thejerf/suture/v4"
  17. "github.com/syncthing/syncthing/lib/config"
  18. "github.com/syncthing/syncthing/lib/connections/registry"
  19. "github.com/syncthing/syncthing/lib/nat"
  20. "github.com/syncthing/syncthing/lib/osutil"
  21. "github.com/syncthing/syncthing/lib/protocol"
  22. "github.com/syncthing/syncthing/lib/stats"
  23. )
  24. type tlsConn interface {
  25. io.ReadWriteCloser
  26. ConnectionState() tls.ConnectionState
  27. RemoteAddr() net.Addr
  28. SetDeadline(time.Time) error
  29. SetWriteDeadline(time.Time) error
  30. LocalAddr() net.Addr
  31. }
  32. // internalConn is the raw TLS connection plus some metadata on where it
  33. // came from (type, priority).
  34. type internalConn struct {
  35. tlsConn
  36. connType connType
  37. isLocal bool
  38. priority int
  39. establishedAt time.Time
  40. connectionID string // set after Hello exchange
  41. }
  42. type connType int
  43. const (
  44. connTypeRelayClient connType = iota
  45. connTypeRelayServer
  46. connTypeTCPClient
  47. connTypeTCPServer
  48. connTypeQUICClient
  49. connTypeQUICServer
  50. )
  51. func (t connType) String() string {
  52. switch t {
  53. case connTypeRelayClient:
  54. return "relay-client"
  55. case connTypeRelayServer:
  56. return "relay-server"
  57. case connTypeTCPClient:
  58. return "tcp-client"
  59. case connTypeTCPServer:
  60. return "tcp-server"
  61. case connTypeQUICClient:
  62. return "quic-client"
  63. case connTypeQUICServer:
  64. return "quic-server"
  65. default:
  66. return "unknown-type"
  67. }
  68. }
  69. func (t connType) Transport() string {
  70. switch t {
  71. case connTypeRelayClient, connTypeRelayServer:
  72. return "relay"
  73. case connTypeTCPClient, connTypeTCPServer:
  74. return "tcp"
  75. case connTypeQUICClient, connTypeQUICServer:
  76. return "quic"
  77. default:
  78. return "unknown"
  79. }
  80. }
  81. func newInternalConn(tc tlsConn, connType connType, isLocal bool, priority int) internalConn {
  82. now := time.Now()
  83. return internalConn{
  84. tlsConn: tc,
  85. connType: connType,
  86. isLocal: isLocal,
  87. priority: priority,
  88. establishedAt: now.Truncate(time.Second),
  89. }
  90. }
  91. func (c internalConn) Close() error {
  92. // *tls.Conn.Close() does more than it says on the tin. Specifically, it
  93. // sends a TLS alert message, which might block forever if the
  94. // connection is dead and we don't have a deadline set.
  95. _ = c.SetWriteDeadline(time.Now().Add(250 * time.Millisecond))
  96. return c.tlsConn.Close()
  97. }
  98. func (c internalConn) Type() string {
  99. return c.connType.String()
  100. }
  101. func (c internalConn) IsLocal() bool {
  102. return c.isLocal
  103. }
  104. func (c internalConn) Priority() int {
  105. return c.priority
  106. }
  107. func (c internalConn) Crypto() string {
  108. cs := c.ConnectionState()
  109. return fmt.Sprintf("%s-%s", tlsVersionNames[cs.Version], tlsCipherSuiteNames[cs.CipherSuite])
  110. }
  111. func (c internalConn) Transport() string {
  112. transport := c.connType.Transport()
  113. ip, err := osutil.IPFromAddr(c.RemoteAddr())
  114. if err != nil {
  115. return transport
  116. }
  117. if ip.To4() != nil {
  118. return transport + "4"
  119. }
  120. return transport + "6"
  121. }
  122. func (c internalConn) EstablishedAt() time.Time {
  123. return c.establishedAt
  124. }
  125. func (c internalConn) ConnectionID() string {
  126. return c.connectionID
  127. }
  128. func (c internalConn) String() string {
  129. t := "WAN"
  130. if c.isLocal {
  131. t = "LAN"
  132. }
  133. return fmt.Sprintf("%s-%s/%s/%s/%s-P%d-%s", c.LocalAddr(), c.RemoteAddr(), c.Type(), c.Crypto(), t, c.Priority(), c.connectionID)
  134. }
  135. func (c internalConn) LogValue() slog.Value {
  136. return slog.GroupValue(slog.String("local", c.LocalAddr().String()), slog.String("remote", c.RemoteAddr().String()), slog.String("type", c.Type()), slog.Bool("lan", c.isLocal), slog.String("crypto", c.Crypto()), slog.Int("prio", c.priority), slog.String("id", c.ConnectionID()))
  137. }
  138. type dialerFactory interface {
  139. New(config.OptionsConfiguration, *tls.Config, *registry.Registry, *lanChecker) genericDialer
  140. AlwaysWAN() bool
  141. Valid(config.Configuration) error
  142. String() string
  143. }
  144. type commonDialer struct {
  145. trafficClass int
  146. reconnectInterval time.Duration
  147. tlsCfg *tls.Config
  148. lanChecker *lanChecker
  149. lanPriority int
  150. wanPriority int
  151. allowsMultiConns bool
  152. }
  153. func (d *commonDialer) RedialFrequency() time.Duration {
  154. return d.reconnectInterval
  155. }
  156. func (d *commonDialer) Priority(host string) int {
  157. if d.lanChecker.isLANHost(host) {
  158. return d.lanPriority
  159. }
  160. return d.wanPriority
  161. }
  162. func (d *commonDialer) AllowsMultiConns() bool {
  163. return d.allowsMultiConns
  164. }
  165. type genericDialer interface {
  166. Dial(context.Context, protocol.DeviceID, *url.URL) (internalConn, error)
  167. RedialFrequency() time.Duration
  168. Priority(host string) int
  169. AllowsMultiConns() bool
  170. }
  171. type listenerFactory interface {
  172. New(*url.URL, config.Wrapper, *tls.Config, chan internalConn, *nat.Service, *registry.Registry, *lanChecker) genericListener
  173. Valid(config.Configuration) error
  174. }
  175. type ListenerAddresses struct {
  176. URI *url.URL
  177. WANAddresses []*url.URL
  178. LANAddresses []*url.URL
  179. }
  180. type genericListener interface {
  181. suture.Service
  182. URI() *url.URL
  183. // A given address can potentially be mutated by the listener.
  184. // For example we bind to tcp://0.0.0.0, but that for example might return
  185. // tcp://gateway1.ip and tcp://gateway2.ip as WAN addresses due to there
  186. // being multiple gateways, and us managing to get a UPnP mapping on both
  187. // and tcp://192.168.0.1 and tcp://10.0.0.1 due to there being multiple
  188. // network interfaces. (The later case for LAN addresses is made up just
  189. // to provide an example)
  190. WANAddresses() []*url.URL
  191. LANAddresses() []*url.URL
  192. Error() error
  193. OnAddressesChanged(func(ListenerAddresses))
  194. String() string
  195. Factory() listenerFactory
  196. NATType() string
  197. }
  198. type Model interface {
  199. protocol.Model
  200. AddConnection(conn protocol.Connection, hello protocol.Hello)
  201. OnHello(protocol.DeviceID, net.Addr, protocol.Hello) error
  202. DeviceStatistics() (map[protocol.DeviceID]stats.DeviceStatistics, error)
  203. }
  204. type onAddressesChangedNotifier struct {
  205. callbacks []func(ListenerAddresses)
  206. }
  207. func (o *onAddressesChangedNotifier) OnAddressesChanged(callback func(ListenerAddresses)) {
  208. o.callbacks = append(o.callbacks, callback)
  209. }
  210. func (o *onAddressesChangedNotifier) notifyAddressesChanged(l genericListener) {
  211. o.notifyAddresses(ListenerAddresses{
  212. URI: l.URI(),
  213. WANAddresses: l.WANAddresses(),
  214. LANAddresses: l.LANAddresses(),
  215. })
  216. }
  217. func (o *onAddressesChangedNotifier) clearAddresses(l genericListener) {
  218. o.notifyAddresses(ListenerAddresses{
  219. URI: l.URI(),
  220. })
  221. }
  222. func (o *onAddressesChangedNotifier) notifyAddresses(l ListenerAddresses) {
  223. for _, callback := range o.callbacks {
  224. callback(l)
  225. }
  226. }
  227. type dialTarget struct {
  228. addr string
  229. dialer genericDialer
  230. priority int
  231. uri *url.URL
  232. deviceID protocol.DeviceID
  233. }
  234. func (t dialTarget) Dial(ctx context.Context) (internalConn, error) {
  235. l.Debugln("dialing", t.deviceID, t.uri, "prio", t.priority)
  236. return t.dialer.Dial(ctx, t.deviceID, t.uri)
  237. }