tls.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright 2014 go-dockerclient authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //
  5. // The content is borrowed from Docker's own source code to provide a simple
  6. // tls based dialer
  7. package docker
  8. import (
  9. "crypto/tls"
  10. "errors"
  11. "net"
  12. "strings"
  13. "time"
  14. )
  15. type tlsClientCon struct {
  16. *tls.Conn
  17. rawConn net.Conn
  18. }
  19. func (c *tlsClientCon) CloseWrite() error {
  20. // Go standard tls.Conn doesn't provide the CloseWrite() method so we do it
  21. // on its underlying connection.
  22. if cwc, ok := c.rawConn.(interface {
  23. CloseWrite() error
  24. }); ok {
  25. return cwc.CloseWrite()
  26. }
  27. return nil
  28. }
  29. func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) {
  30. // We want the Timeout and Deadline values from dialer to cover the
  31. // whole process: TCP connection and TLS handshake. This means that we
  32. // also need to start our own timers now.
  33. timeout := dialer.Timeout
  34. if !dialer.Deadline.IsZero() {
  35. deadlineTimeout := dialer.Deadline.Sub(time.Now())
  36. if timeout == 0 || deadlineTimeout < timeout {
  37. timeout = deadlineTimeout
  38. }
  39. }
  40. var errChannel chan error
  41. if timeout != 0 {
  42. errChannel = make(chan error, 2)
  43. time.AfterFunc(timeout, func() {
  44. errChannel <- errors.New("")
  45. })
  46. }
  47. rawConn, err := dialer.Dial(network, addr)
  48. if err != nil {
  49. return nil, err
  50. }
  51. colonPos := strings.LastIndex(addr, ":")
  52. if colonPos == -1 {
  53. colonPos = len(addr)
  54. }
  55. hostname := addr[:colonPos]
  56. // If no ServerName is set, infer the ServerName
  57. // from the hostname we're connecting to.
  58. if config.ServerName == "" {
  59. // Make a copy to avoid polluting argument or default.
  60. config = copyTLSConfig(config)
  61. config.ServerName = hostname
  62. }
  63. conn := tls.Client(rawConn, config)
  64. if timeout == 0 {
  65. err = conn.Handshake()
  66. } else {
  67. go func() {
  68. errChannel <- conn.Handshake()
  69. }()
  70. err = <-errChannel
  71. }
  72. if err != nil {
  73. rawConn.Close()
  74. return nil, err
  75. }
  76. // This is Docker difference with standard's crypto/tls package: returned a
  77. // wrapper which holds both the TLS and raw connections.
  78. return &tlsClientCon{conn, rawConn}, nil
  79. }
  80. // this exists to silent an error message in go vet
  81. func copyTLSConfig(cfg *tls.Config) *tls.Config {
  82. return &tls.Config{
  83. Certificates: cfg.Certificates,
  84. CipherSuites: cfg.CipherSuites,
  85. ClientAuth: cfg.ClientAuth,
  86. ClientCAs: cfg.ClientCAs,
  87. ClientSessionCache: cfg.ClientSessionCache,
  88. CurvePreferences: cfg.CurvePreferences,
  89. InsecureSkipVerify: cfg.InsecureSkipVerify,
  90. MaxVersion: cfg.MaxVersion,
  91. MinVersion: cfg.MinVersion,
  92. NameToCertificate: cfg.NameToCertificate,
  93. NextProtos: cfg.NextProtos,
  94. PreferServerCipherSuites: cfg.PreferServerCipherSuites,
  95. Rand: cfg.Rand,
  96. RootCAs: cfg.RootCAs,
  97. ServerName: cfg.ServerName,
  98. SessionTicketKey: cfg.SessionTicketKey,
  99. SessionTicketsDisabled: cfg.SessionTicketsDisabled,
  100. }
  101. }