Skip to content

Commit

Permalink
Ensure the redis TLS connection uses k6's netext.Dialer under the hood
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Nov 1, 2023
1 parent d542b1f commit 3676bef
Showing 1 changed file with 48 additions and 31 deletions.
79 changes: 48 additions & 31 deletions redis/client.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package redis

import (
"context"
"crypto/tls"
"fmt"
"net"
"time"

"github.com/dop251/goja"
"github.com/redis/go-redis/v9"
"go.k6.io/k6/js/common"
"go.k6.io/k6/js/modules"
"go.k6.io/k6/lib/netext"
)

// Client represents the Client constructor (i.e. `new redis.Client()`) and
Expand Down Expand Up @@ -1080,37 +1081,53 @@ func (c *Client) connect() error {
}

tlsCfg := c.redisOptions.TLSConfig
if tlsCfg != nil {
if vuState.TLSConfig != nil {
// Merge k6 TLS configuration with the one we received from the
// Client constructor. This will need adjusting depending on which
// options we want to expose in the Redis module, and how we want
// the override to work.
tlsCfg.InsecureSkipVerify = vuState.TLSConfig.InsecureSkipVerify
tlsCfg.CipherSuites = vuState.TLSConfig.CipherSuites
tlsCfg.MinVersion = vuState.TLSConfig.MinVersion
tlsCfg.MaxVersion = vuState.TLSConfig.MaxVersion
tlsCfg.Renegotiation = vuState.TLSConfig.Renegotiation
tlsCfg.KeyLogWriter = vuState.TLSConfig.KeyLogWriter

tlsCfg.Certificates = append(tlsCfg.Certificates, vuState.TLSConfig.Certificates...)

// TODO: Merge vuState.TLSConfig.RootCAs with
// c.redisOptions.TLSConfig. k6 currently doesn't allow setting
// this, so it doesn't matter right now, but these should be merged.
// I couldn't find a way to do this with the x509.CertPool API
// though...
if tlsCfg != nil && vuState.TLSConfig != nil {

Check failure on line 1084 in redis/client.go

View workflow job for this annotation

GitHub Actions / checks / lint

`if tlsCfg != nil && vuState.TLSConfig != nil` has complex nested blocks (complexity: 5) (nestif)
// Merge k6 TLS configuration with the one we received from the
// Client constructor. This will need adjusting depending on which
// options we want to expose in the Redis module, and how we want
// the override to work.
tlsCfg.InsecureSkipVerify = vuState.TLSConfig.InsecureSkipVerify
tlsCfg.CipherSuites = vuState.TLSConfig.CipherSuites
tlsCfg.MinVersion = vuState.TLSConfig.MinVersion
tlsCfg.MaxVersion = vuState.TLSConfig.MaxVersion
tlsCfg.Renegotiation = vuState.TLSConfig.Renegotiation
tlsCfg.KeyLogWriter = vuState.TLSConfig.KeyLogWriter
tlsCfg.Certificates = append(tlsCfg.Certificates, vuState.TLSConfig.Certificates...)

// TODO: Merge vuState.TLSConfig.RootCAs with
// c.redisOptions.TLSConfig. k6 currently doesn't allow setting
// this, so it doesn't matter right now, but these should be merged.
// I couldn't find a way to do this with the x509.CertPool API
// though...

// In order to preserve the underlying effects of the [netext.Dialer], such
// as handling blocked hostnames, or handling hostname resolution, we override
// the redis client's dialer with our own function which uses the VU's [netext.Dialer]
// and manually upgrades the connection to TLS.
//
// See Pull Request's #17 [discussion] for more details.
//
// [discussion]: https://github.com/grafana/xk6-redis/pull/17#discussion_r1369707388
c.redisOptions.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
// Use netext.Dialer to establish the connection
rawConn, err := vuState.Dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}

if tlsCfg != nil {
// Upgrade the connection to TLS if needed
tlsConn := tls.Client(rawConn, tlsCfg)
err = tlsConn.Handshake()
if err != nil {
rawConn.Close()

Check failure on line 1123 in redis/client.go

View workflow job for this annotation

GitHub Actions / checks / lint

Error return value of `rawConn.Close` is not checked (errcheck)
return nil, err
}
rawConn = tlsConn // Overwrite rawConn with the TLS connection
}

return rawConn, nil
}

k6dialer, ok := vuState.Dialer.(*netext.Dialer)
if !ok {
panic(fmt.Sprintf("expected *netext.Dialer, got: %T", vuState.Dialer))
}
tlsDialer := &tls.Dialer{
NetDialer: &k6dialer.Dialer,
Config: tlsCfg,
}
c.redisOptions.Dialer = tlsDialer.DialContext
} else {
c.redisOptions.Dialer = vuState.Dialer.DialContext
}
Expand Down

0 comments on commit 3676bef

Please sign in to comment.