diff --git a/ca/ca.go b/ca/ca.go index 707c010b..8f285a21 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -1,41 +1,17 @@ package ca import ( - "crypto/hmac" - "crypto/rsa" - "crypto/sha1" // nolint: gosec + "context" "crypto/tls" "crypto/x509" - "crypto/x509/pkix" - "encoding/binary" - "hash" - "math/big" - "math/rand" - "net" + "hash/fnv" "runtime" "sync" - "time" - "github.com/karlseguin/ccache" + lru "github.com/hashicorp/golang-lru" "golang.org/x/xerrors" ) -const ( - // TTLForCertificate is minimal time until certificate is - // considered as expired. This is a time from the last usage. If the - // certificate is expired, it does not necessary wiped out from LRU - // cache. - TTLForCertificate = 10 * time.Minute - - // RSAKeyLength is the bit size of RSA private key for the certificate. - RSAKeyLength = 2048 -) - -var ( - certWorkerCount = uint32(runtime.NumCPU()) - bigBangTime = time.Unix(0, 0) -) - // CertificateMetrics is a subset of the main Metrics interface which // provides callbacks for certificates. type CertificateMetrics interface { @@ -43,6 +19,10 @@ type CertificateMetrics interface { DropCertificate() } +// DefaultMaxSize defines a default value for TLS certificates to store +// in LRU cache. +const DefaultMaxSize = 1024 + // CA is a datastructure which presents TLS CA (certificate authority). // The main purpose of this type is to generate TLS certificates // on-the-fly, using given CA certificate and private key. @@ -51,180 +31,75 @@ type CertificateMetrics interface { // number of concurrently generated certificates is equal to the number // of CPUs. type CA struct { - ca tls.Certificate - orgNames []string - secret []byte - requestChans []chan *signRequest - cache *ccache.Cache - wg *sync.WaitGroup - metrics CertificateMetrics + cache *lru.Cache + cancel context.CancelFunc + workers []worker + wg sync.WaitGroup } -// Get returns generated TLSConfig instance for the given hostname. -func (c *CA) Get(host string) (TLSConfig, error) { - item := c.cache.TrackingGet(host) - - if item == ccache.NilTracked { - newRequest := signRequestPool.Get().(*signRequest) - defer signRequestPool.Put(newRequest) - - newRequest.host = host - c.getWorkerChan(host) <- newRequest - response := <-newRequest.response - - defer signResponsePool.Put(response) +func (c *CA) Get(host string) (*tls.Config, error) { + if item, ok := c.cache.Get(host); ok { + return item.(*tls.Config), nil + } - if response.err != nil { - return TLSConfig{}, xerrors.Errorf("cannot create TLS certificate for host %s: %w", - host, response.err) - } + hashFunc := fnv.New32a() + hashFunc.Write([]byte(host)) // nolint: errcheck - item = response.item - } + num := int(hashFunc.Sum32() % uint32(len(c.workers))) - return TLSConfig{item}, nil + return c.workers[num].get(host) } // Close stops CA instance. This includes all signing workers and LRU // cache. -func (c *CA) Close() error { - for _, ch := range c.requestChans { - close(ch) - } - +func (c *CA) Close() { + c.cancel() c.wg.Wait() - c.cache.Stop() - - return nil -} - -func (c *CA) worker(requests chan *signRequest, wg *sync.WaitGroup) { - defer wg.Done() - - for req := range requests { - resp := signResponsePool.Get().(*signResponse) - resp.err = nil - - if item := c.cache.TrackingGet(req.host); item != ccache.NilTracked { - resp.item = item - req.response <- resp - - continue - } - - cert, err := c.sign(req.host) - if err != nil { - resp.err = err - req.response <- resp - - continue - } - - c.metrics.NewCertificate() - - conf := &tls.Config{InsecureSkipVerify: true} // nolint: gosec - conf.Certificates = append(conf.Certificates, cert) - c.cache.Set(req.host, conf, TTLForCertificate) - resp.item = c.cache.TrackingGet(req.host) - req.response <- resp - } + c.cache.Purge() } -func (c *CA) sign(host string) (tls.Certificate, error) { - template := x509.Certificate{ - SerialNumber: &big.Int{}, - Issuer: c.ca.Leaf.Subject, - Subject: pkix.Name{Organization: c.orgNames}, - NotBefore: bigBangTime, - NotAfter: timeNotAfter(), - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - hash := hmac.New(sha1.New, c.secret) - hash.Write([]byte(host)) // nolint: errcheck - - if ip := net.ParseIP(host); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, host) - template.Subject.CommonName = host - } - - hashed := hash.Sum(nil) - template.SerialNumber.SetBytes(hashed) - hash.Write(c.secret) // nolint: errcheck - - randSeed := int64(binary.LittleEndian.Uint64(hash.Sum(nil)[:8])) - randGen := rand.New(rand.NewSource(randSeed)) - - certpriv, err := rsa.GenerateKey(randGen, RSAKeyLength) +func NewCA(certCA, certKey []byte, metrics CertificateMetrics, maxSize int, orgNames []string) (*CA, error) { + ca, err := tls.X509KeyPair(certCA, certKey) if err != nil { - panic(err) + return nil, xerrors.Errorf("invalid certificates: %w", err) } - derBytes, err := x509.CreateCertificate(randGen, &template, c.ca.Leaf, - &certpriv.PublicKey, c.ca.PrivateKey) - if err != nil { - return tls.Certificate{}, xerrors.Errorf("cannot generate TLS certificate: %w", err) + if ca.Leaf, err = x509.ParseCertificate(ca.Certificate[0]); err != nil { + return nil, xerrors.Errorf("invalid certificates: %w", err) } - return tls.Certificate{ - Certificate: [][]byte{derBytes, c.ca.Certificate[0]}, - PrivateKey: certpriv, - }, nil -} - -func (c *CA) getWorkerChan(host string) chan<- *signRequest { - newHash := hashPool.Get().(hash.Hash32) - newHash.Reset() - newHash.Write([]byte(host)) // nolint: errcheck - chanNumber := newHash.Sum32() % certWorkerCount - hashPool.Put(newHash) - - return c.requestChans[chanNumber] -} - -// NewCA creates new instance of TLS CA. -func NewCA(certCA, certKey []byte, metrics CertificateMetrics, - cacheMaxSize int64, cacheItemsToPrune uint32, orgNames ...string) (CA, error) { - ca, err := tls.X509KeyPair(certCA, certKey) - if err != nil { - return CA{}, xerrors.Errorf("invalid certificates: %w", err) + if maxSize <= 0 { + maxSize = DefaultMaxSize } - if ca.Leaf, err = x509.ParseCertificate(ca.Certificate[0]); err != nil { - return CA{}, xerrors.Errorf("invalid certificates: %w", err) + cache, err := lru.NewWithEvict(maxSize, func(_, _ interface{}) { + metrics.DropCertificate() + }) + if err != nil { + return nil, xerrors.Errorf("cannot make a new cache: %w", err) } - ccacheConf := ccache.Configure() - ccacheConf = ccacheConf.MaxSize(cacheMaxSize) - ccacheConf = ccacheConf.ItemsToPrune(cacheItemsToPrune) - ccacheConf = ccacheConf.OnDelete(func(_ *ccache.Item) { metrics.DropCertificate() }) - - obj := CA{ - ca: ca, - metrics: metrics, - secret: certKey, - orgNames: orgNames, - cache: ccache.New(ccacheConf), - requestChans: make([]chan *signRequest, 0, certWorkerCount), - wg: &sync.WaitGroup{}, + ctx, cancel := context.WithCancel(context.Background()) + obj := &CA{ + cache: cache, + workers: make([]worker, runtime.NumCPU()), + cancel: cancel, } - for i := 0; i < int(certWorkerCount); i++ { - newChan := make(chan *signRequest) - obj.requestChans = append(obj.requestChans, newChan) - obj.wg.Add(1) - - go obj.worker(newChan, obj.wg) + obj.wg.Add(len(obj.workers)) + + for i := range obj.workers { + obj.workers[i] = worker{ + ca: ca, + cache: cache, + orgNames: orgNames, + secret: certKey, + ctx: ctx, + metrics: metrics, + channelRequests: make(chan workerRequest), + } + go obj.workers[i].run(&obj.wg) } return obj, nil } - -func timeNotAfter() time.Time { - now := time.Now() - return time.Date(now.Year()+10, now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) -} diff --git a/ca/ca_test.go b/ca/ca_test.go index 0535d359..c24a7d00 100644 --- a/ca/ca_test.go +++ b/ca/ca_test.go @@ -1,7 +1,6 @@ package ca import ( - "crypto/x509" "testing" "github.com/stretchr/testify/mock" @@ -63,57 +62,31 @@ type CATestSuite struct { func (suite *CATestSuite) SetupTest() { suite.mock = &MockCertificateMetrics{} - ca, err := NewCA(testCaCACert, testCaPrivateKey, suite.mock, 1000, 100) + ca, err := NewCA(testCaCACert, testCaPrivateKey, suite.mock, -1, []string{"name"}) if err != nil { panic(err) } - suite.ca = &ca -} - -func (suite *CATestSuite) TearDownTest() { - suite.ca.Close() + suite.ca = ca } func (suite *CATestSuite) TestDoubleGet() { - suite.mock.On("NewCertificate") + suite.mock.On("NewCertificate").Once() + suite.mock.On("DropCertificate").Maybe() conf1, err := suite.ca.Get("hostname") - suite.Nil(err) + suite.NoError(err) conf2, err := suite.ca.Get("hostname") - suite.Nil(err) + suite.NoError(err) - suite.Equal(conf1.Get().Certificates[0].PrivateKey, conf2.Get().Certificates[0].PrivateKey) - suite.Equal(conf1.Get().Certificates[0].Certificate[0], conf2.Get().Certificates[0].Certificate[0]) - - suite.mock.AssertExpectations(suite.T()) + suite.Equal(conf1.Certificates[0].PrivateKey, conf2.Certificates[0].PrivateKey) + suite.Equal(conf1.Certificates[0].Certificate[0], conf2.Certificates[0].Certificate[0]) } -func (suite *CATestSuite) TestSigner() { - suite.mock.On("NewCertificate") - - conf, err := suite.ca.Get("hostname") - suite.Nil(err) - - cert := conf.Get().Certificates[0] - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - suite.Nil(err) - - pool := x509.NewCertPool() - pool.AddCert(suite.ca.ca.Leaf) - - suite.Nil(cert.Leaf.VerifyHostname("hostname")) - suite.NotNil(cert.Leaf.VerifyHostname("hostname2")) - suite.Nil(cert.Leaf.CheckSignatureFrom(suite.ca.ca.Leaf)) - - _, err = cert.Leaf.Verify(x509.VerifyOptions{ - DNSName: "hostname", - Roots: pool, - }) - suite.Nil(err) - +func (suite *CATestSuite) TearDownTest() { suite.mock.AssertExpectations(suite.T()) + suite.ca.Close() } func TestCA(t *testing.T) { diff --git a/ca/pools.go b/ca/pools.go deleted file mode 100644 index 490b134d..00000000 --- a/ca/pools.go +++ /dev/null @@ -1,40 +0,0 @@ -package ca - -import ( - "hash/fnv" - "sync" - - "github.com/karlseguin/ccache" -) - -var ( - signRequestPool = sync.Pool{ - New: func() interface{} { - return &signRequest{ - response: make(chan *signResponse), - } - }, - } - - signResponsePool = sync.Pool{ - New: func() interface{} { - return &signResponse{} - }, - } - - hashPool = sync.Pool{ - New: func() interface{} { - return fnv.New32a() - }, - } -) - -type signRequest struct { - host string - response chan *signResponse -} - -type signResponse struct { - item ccache.TrackedItem - err error -} diff --git a/ca/tlsconfig.go b/ca/tlsconfig.go deleted file mode 100644 index 8210e629..00000000 --- a/ca/tlsconfig.go +++ /dev/null @@ -1,32 +0,0 @@ -package ca - -import ( - "crypto/tls" - - "github.com/karlseguin/ccache" -) - -// TLSConfig is a wrapper over *tls.Config. This wrapper is required -// because CA uses LRU cache to store generated certificates. API of -// this structure transparently handles transaction-style access to TLS -// certificate. -type TLSConfig struct { - item ccache.TrackedItem -} - -// Get returns stored TLS configuration instance. -func (t *TLSConfig) Get() *tls.Config { - if t.item == nil { - return nil - } - - return t.item.Value().(*tls.Config) -} - -// Release returns TLS configuration back to the LRU cache. -func (t *TLSConfig) Release() { - if t.item != nil { - t.item.Release() - t.item = nil - } -} diff --git a/ca/tlsconfig_test.go b/ca/tlsconfig_test.go deleted file mode 100644 index 47081045..00000000 --- a/ca/tlsconfig_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package ca - -import ( - "crypto/tls" - "testing" - "time" - - "github.com/karlseguin/ccache" - "github.com/stretchr/testify/suite" -) - -type TLSConfigTestSuite struct { - suite.Suite - - conf *tls.Config - cache *ccache.Cache -} - -func (suite *TLSConfigTestSuite) SetupTest() { - suite.conf = &tls.Config{} - suite.cache = ccache.New(ccache.Configure()) - suite.cache.Set("key", suite.conf, time.Minute) -} - -func (suite *TLSConfigTestSuite) TearDownTest() { - suite.cache.Stop() -} - -func (suite *TLSConfigTestSuite) TestGetReleaseGet() { - item := suite.cache.TrackingGet("key") - suite.NotEqual(item, ccache.NilTracked) - - conf := TLSConfig{item} - suite.Equal(conf.Get(), suite.conf) - - conf.Release() - conf.Release() - suite.Nil(conf.Get()) -} - -func TestTLSConfig(t *testing.T) { - suite.Run(t, &TLSConfigTestSuite{}) -} diff --git a/ca/worker.go b/ca/worker.go new file mode 100644 index 00000000..6e247d3a --- /dev/null +++ b/ca/worker.go @@ -0,0 +1,133 @@ +package ca + +import ( + "context" + "crypto/hmac" + "crypto/md5" // nolint: gosec + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "errors" + "math/big" + "net" + "sync" + "time" + + lru "github.com/hashicorp/golang-lru" +) + +var ( + bigBangTime = time.Unix(0, 0) + + DefaultTLSConfig = &tls.Config{ + InsecureSkipVerify: true, // nolint: gosec + } +) + +// RSAKeyLength defines a length of the key to generate +const RSAKeyLength = 2048 + +type workerRequest struct { + host string + response chan<- *tls.Config +} + +type worker struct { + ca tls.Certificate + cache *lru.Cache + orgNames []string + secret []byte + ctx context.Context + metrics CertificateMetrics + + channelRequests chan workerRequest +} + +func (w *worker) run(wg *sync.WaitGroup) { + defer wg.Done() + + for { + select { + case <-w.ctx.Done(): + return + case req := <-w.channelRequests: + item, ok := w.cache.Get(req.host) + if !ok { + item = w.makeConfig(req.host) + w.cache.Add(req.host, item) + } + + req.response <- item.(*tls.Config) + close(req.response) + } + } +} + +func (w *worker) get(host string) (*tls.Config, error) { + response := make(chan *tls.Config) + req := workerRequest{ + host: host, + response: response, + } + + select { + case w.channelRequests <- req: + return <-response, nil + case <-w.ctx.Done(): + return nil, errors.New("context is closed") + } +} + +func (w *worker) makeConfig(host string) *tls.Config { + template := x509.Certificate{ + SerialNumber: &big.Int{}, + Issuer: w.ca.Leaf.Subject, + Subject: pkix.Name{Organization: w.orgNames}, + NotBefore: bigBangTime, + NotAfter: timeNotAfter(), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + if ip := net.ParseIP(host); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, host) + template.Subject.CommonName = host + } + + hash := hmac.New(md5.New, w.secret) + hash.Write([]byte(host)) // nolint: errcheck + + template.SerialNumber.SetBytes(hash.Sum(nil)) + + certPriv, err := rsa.GenerateKey(rand.Reader, RSAKeyLength) + if err != nil { + panic(err) + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, w.ca.Leaf, + &certPriv.PublicKey, w.ca.PrivateKey) + if err != nil { + panic(err) + } + + certificate := tls.Certificate{ + Certificate: [][]byte{derBytes, w.ca.Certificate[0]}, + PrivateKey: certPriv, + } + config := DefaultTLSConfig.Clone() + config.Certificates = append(config.Certificates, certificate) + + w.metrics.NewCertificate() + + return config +} + +func timeNotAfter() time.Time { + now := time.Now() + return time.Date(now.Year()+10, now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) +} diff --git a/go.mod b/go.mod index df44bbf9..2b02115f 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,14 @@ module github.com/9seconds/httransform require ( - github.com/karlseguin/ccache v2.0.3+incompatible - github.com/karlseguin/expect v1.0.1 // indirect - github.com/klauspost/compress v1.9.2 // indirect + github.com/hashicorp/golang-lru v0.5.3 + github.com/klauspost/compress v1.9.4 // indirect github.com/mccutchen/go-httpbin v0.0.0-20190116014521-c5cb2f4802fa github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.3.0 - github.com/valyala/fasthttp v1.6.0 - github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 // indirect - golang.org/x/net v0.0.0-20191124235446-72fef5d5e266 - golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 - gopkg.in/karlseguin/expect.v1 v1.0.1 // indirect + github.com/valyala/fasthttp v1.7.0 + golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 ) go 1.13 diff --git a/go.sum b/go.sum index bb56671a..4232d15b 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/karlseguin/ccache v2.0.3+incompatible h1:j68C9tWOROiOLWTS/kCGg9IcJG+ACqn5+0+t8Oh83UU= -github.com/karlseguin/ccache v2.0.3+incompatible/go.mod h1:CM9tNPzT6EdRh14+jiW8mEF9mkNZuuE51qmgGYUB93w= -github.com/karlseguin/expect v1.0.1 h1:z4wy4npwwHSWKjGWH85WNJO42VQhovxTCZDSzhjo8hY= -github.com/karlseguin/expect v1.0.1/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= +github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= -github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4= +github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/mccutchen/go-httpbin v0.0.0-20190116014521-c5cb2f4802fa h1:N+a/IauulU9R5B0FQGGdnNbxw28HXN4fjtx2PYQxH8c= @@ -21,19 +19,15 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.7.0 h1:r0Z/fzm2Euss3K0hhkPtt41TigAr9bXueavuXgrThi4= +github.com/valyala/fasthttp v1.7.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= -github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191124235446-72fef5d5e266 h1:QuOiA7GCO0OSDzlNlFyOWOywDsjuzW8M2yvBfCqw+cY= -golang.org/x/net v0.0.0-20191124235446-72fef5d5e266/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/karlseguin/expect.v1 v1.0.1 h1:9u0iUltnhFbJTHaSIH0EP+cuTU5rafIgmcsEsg2JQFw= -gopkg.in/karlseguin/expect.v1 v1.0.1/go.mod h1:uB7QIJBcclvYbwlUDkSCsGjAOMis3fP280LyhuDEf2I= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/opts.go b/opts.go index 8e303db9..540e66e9 100644 --- a/opts.go +++ b/opts.go @@ -31,11 +31,6 @@ const ( // DefaultTLSCertCacheSize is the number of items we store in LRU cache // of generated TLS certificates before starting to prune obsoletes. DefaultTLSCertCacheSize = 10000 - - // DefaultTLSCertCachePrune is the number of items we prune from LRU - // cache per attempt. Big number takes more time but increases the - // throughput. - DefaultTLSCertCachePrune = 500 ) // ServerOpts is the datastructure to configure Server instance. The @@ -73,11 +68,6 @@ type ServerOpts struct { // of generated TLS certificates before starting to prune obsoletes. TLSCertCacheSize int - // TLSCertCachePrune is the number of items we prune from LRU - // cache per attempt. Big number takes more time but increases the - // throughput. - TLSCertCachePrune int - // Tracer is an instance of tracer pool to use. By default pool of // NoopTracers is going to be used. TracerPool *TracerPool @@ -168,22 +158,12 @@ func (s *ServerOpts) GetOrganizationName() string { // GetTLSCertCacheSize returns the number of items to store in LRU cache // of generated TLS certificates before starting to prune obsoletes. -func (s *ServerOpts) GetTLSCertCacheSize() int64 { +func (s *ServerOpts) GetTLSCertCacheSize() int { if s.TLSCertCacheSize == 0 { return DefaultTLSCertCacheSize } - return int64(s.TLSCertCacheSize) -} - -// GetTLSCertCachePrune returns the number of items to prune from LRU -// cache per attempt. -func (s *ServerOpts) GetTLSCertCachePrune() uint32 { - if s.TLSCertCachePrune == 0 { - return DefaultTLSCertCachePrune - } - - return uint32(s.TLSCertCachePrune) + return s.TLSCertCacheSize } // GetTracerPool returns a tracer pool to use. diff --git a/opts_test.go b/opts_test.go index eafe7c0d..4dbbe0a3 100644 --- a/opts_test.go +++ b/opts_test.go @@ -64,15 +64,9 @@ func (suite *ServerOptsTestSuite) TestGetOrganizationName() { } func (suite *ServerOptsTestSuite) TestGetTLSCertCacheSize() { - suite.Equal(suite.opts.GetTLSCertCacheSize(), int64(DefaultTLSCertCacheSize)) + suite.Equal(suite.opts.GetTLSCertCacheSize(), DefaultTLSCertCacheSize) suite.opts.TLSCertCacheSize = DefaultTLSCertCacheSize + 1 - suite.Equal(suite.opts.GetTLSCertCacheSize(), int64(suite.opts.TLSCertCacheSize)) -} - -func (suite *ServerOptsTestSuite) TestGetTLSCertCachePrune() { - suite.Equal(suite.opts.GetTLSCertCachePrune(), uint32(DefaultTLSCertCachePrune)) - suite.opts.TLSCertCachePrune = DefaultTLSCertCachePrune + 1 - suite.Equal(suite.opts.GetTLSCertCachePrune(), uint32(suite.opts.TLSCertCachePrune)) + suite.Equal(suite.opts.GetTLSCertCacheSize(), suite.opts.TLSCertCacheSize) } func (suite *ServerOptsTestSuite) TestGetTracerPool() { diff --git a/server.go b/server.go index cb113ce4..efae27cb 100644 --- a/server.go +++ b/server.go @@ -25,7 +25,7 @@ type Server struct { serverPool sync.Pool tracerPool *TracerPool server *fasthttp.Server - certs ca.CA + certs *ca.CA layers []Layer executor Executor logger Logger @@ -99,9 +99,8 @@ func (s *Server) makeHijackHandler(host string, reqID uint64, user, password []b conn.RemoteAddr(), reqID, host, err) return } - defer conf.Release() - tlsConn := tls.Server(conn, conf.Get()) + tlsConn := tls.Server(conn, conf) defer tlsConn.Close() if err = tlsConn.Handshake(); err != nil { @@ -233,8 +232,7 @@ func NewServer(opts ServerOpts) (*Server, error) { opts.GetCertKey(), metrics, opts.GetTLSCertCacheSize(), - opts.GetTLSCertCachePrune(), - opts.GetOrganizationName()) + []string{opts.GetOrganizationName()}) if err != nil { return nil, xerrors.Errorf("cannot create CA: %w", err)