2020-04-01 02:08:21 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"fmt"
|
2020-04-25 22:22:45 +00:00
|
|
|
"github.com/baez90/inetmock/pkg/api"
|
|
|
|
"github.com/baez90/inetmock/pkg/cert"
|
2020-04-13 22:14:56 +00:00
|
|
|
"github.com/baez90/inetmock/pkg/logging"
|
2020-04-25 23:18:35 +00:00
|
|
|
"github.com/google/uuid"
|
2020-04-01 02:08:21 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
name = "tls_interceptor"
|
|
|
|
)
|
|
|
|
|
|
|
|
type tlsInterceptor struct {
|
2020-04-25 22:22:45 +00:00
|
|
|
options tlsOptions
|
2020-04-13 22:14:56 +00:00
|
|
|
logger logging.Logger
|
2020-04-01 02:08:21 +00:00
|
|
|
listener net.Listener
|
2020-04-25 22:22:45 +00:00
|
|
|
certStore cert.Store
|
2020-04-01 02:08:21 +00:00
|
|
|
shutdownRequested bool
|
|
|
|
currentConnectionsCount *sync.WaitGroup
|
2020-04-25 23:18:35 +00:00
|
|
|
currentConnections map[uuid.UUID]*proxyConn
|
2020-04-01 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-04-25 22:22:45 +00:00
|
|
|
func (t *tlsInterceptor) Start(config api.HandlerConfig) (err error) {
|
2020-04-01 02:08:21 +00:00
|
|
|
t.options = loadFromConfig(config.Options())
|
|
|
|
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
|
|
|
|
|
|
|
t.logger = t.logger.With(
|
|
|
|
zap.String("address", addr),
|
|
|
|
zap.String("target", t.options.redirectionTarget.address()),
|
|
|
|
)
|
|
|
|
|
2020-04-25 22:22:45 +00:00
|
|
|
if t.listener, err = tls.Listen("tcp", addr, api.ServicesInstance().CertStore().TLSConfig()); err != nil {
|
2020-04-01 02:08:21 +00:00
|
|
|
t.logger.Fatal(
|
|
|
|
"failed to create tls listener",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
2020-04-13 22:14:56 +00:00
|
|
|
err = fmt.Errorf(
|
|
|
|
"failed to create tls listener: %w",
|
|
|
|
err,
|
|
|
|
)
|
2020-04-01 02:08:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
go t.startListener()
|
2020-04-13 22:14:56 +00:00
|
|
|
return
|
2020-04-01 02:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 22:14:56 +00:00
|
|
|
func (t *tlsInterceptor) Shutdown() (err error) {
|
2020-04-12 01:51:41 +00:00
|
|
|
t.logger.Info("Shutting down TLS interceptor")
|
2020-04-01 02:08:21 +00:00
|
|
|
t.shutdownRequested = true
|
|
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
t.currentConnectionsCount.Wait()
|
|
|
|
close(done)
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-done:
|
2020-04-13 22:14:56 +00:00
|
|
|
return
|
2020-04-01 02:08:21 +00:00
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
for _, proxyConn := range t.currentConnections {
|
2020-04-13 22:14:56 +00:00
|
|
|
if err = proxyConn.Close(); err != nil {
|
2020-04-01 02:08:21 +00:00
|
|
|
t.logger.Error(
|
|
|
|
"error while closing remaining proxy connections",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
2020-04-13 22:14:56 +00:00
|
|
|
err = fmt.Errorf(
|
|
|
|
"error while closing remaining proxy connections: %w",
|
|
|
|
err,
|
|
|
|
)
|
2020-04-01 02:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-13 22:14:56 +00:00
|
|
|
return
|
2020-04-01 02:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tlsInterceptor) startListener() {
|
|
|
|
for !t.shutdownRequested {
|
|
|
|
conn, err := t.listener.Accept()
|
|
|
|
if err != nil {
|
|
|
|
t.logger.Error(
|
|
|
|
"error during accept",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
t.currentConnectionsCount.Add(1)
|
|
|
|
go t.proxyConn(conn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tlsInterceptor) proxyConn(conn net.Conn) {
|
|
|
|
defer conn.Close()
|
2020-04-25 23:18:35 +00:00
|
|
|
defer t.currentConnectionsCount.Done()
|
2020-04-01 02:08:21 +00:00
|
|
|
|
|
|
|
rAddr, err := net.ResolveTCPAddr("tcp", t.options.redirectionTarget.address())
|
|
|
|
if err != nil {
|
|
|
|
t.logger.Error(
|
|
|
|
"failed to resolve proxy target",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
targetConn, err := net.DialTCP("tcp", nil, rAddr)
|
|
|
|
if err != nil {
|
|
|
|
t.logger.Error(
|
|
|
|
"failed to connect to proxy target",
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer targetConn.Close()
|
|
|
|
|
2020-04-25 23:18:35 +00:00
|
|
|
proxyCon := &proxyConn{
|
2020-04-01 02:08:21 +00:00
|
|
|
source: conn,
|
|
|
|
target: targetConn,
|
2020-04-25 23:18:35 +00:00
|
|
|
}
|
2020-04-01 02:08:21 +00:00
|
|
|
|
2020-04-25 23:18:35 +00:00
|
|
|
conUID := uuid.New()
|
|
|
|
t.currentConnections[conUID] = proxyCon
|
2020-04-01 02:08:21 +00:00
|
|
|
Pipe(conn, targetConn)
|
2020-04-25 23:18:35 +00:00
|
|
|
delete(t.currentConnections, conUID)
|
2020-04-01 02:08:21 +00:00
|
|
|
|
|
|
|
t.logger.Info(
|
|
|
|
"connection closed",
|
|
|
|
zap.String("remoteAddr", conn.RemoteAddr().String()),
|
|
|
|
)
|
|
|
|
}
|