// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package proxy
import (
"context"
"crypto/tls"
"net"
"path/filepath"
"runtime"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent"
agConnect "github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/connect"
"github.com/hashicorp/consul/sdk/freeport"
"github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/hashicorp/consul/testrpc"
)
func TestProxy_public ( t * testing . T ) {
if testing . Short ( ) {
t . Skip ( "too slow for testing.Short" )
}
ports := freeport . GetN ( t , 2 )
a := agent . NewTestAgent ( t , "" )
defer a . Shutdown ( )
testrpc . WaitForTestAgent ( t , a . RPC , "dc1" )
client := a . Client ( )
// Register the service so we can get a leaf cert
_ , err := client . Catalog ( ) . Register ( & api . CatalogRegistration {
Datacenter : "dc1" ,
Node : "local" ,
Address : "127.0.0.1" ,
Service : & api . AgentService {
Service : "echo" ,
} ,
} , nil )
require . NoError ( t , err )
// Start the backend service that is being proxied
testApp := NewTestTCPServer ( t )
defer testApp . Close ( )
upstreams := [ ] UpstreamConfig {
{
DestinationName : "just-a-port" ,
LocalBindPort : ports [ 1 ] ,
} ,
}
var unixSocket string
if runtime . GOOS != "windows" {
tempDir := testutil . TempDir ( t , "consul" )
unixSocket = filepath . Join ( tempDir , "test.sock" )
upstreams = append ( upstreams , UpstreamConfig {
DestinationName : "just-a-unix-domain-socket" ,
LocalBindSocketPath : unixSocket ,
LocalBindSocketMode : "0600" ,
} )
}
// Start the proxy
p , err := New ( client , NewStaticConfigWatcher ( & Config {
ProxiedServiceName : "echo" ,
PublicListener : PublicListenerConfig {
BindAddress : "127.0.0.1" ,
BindPort : ports [ 0 ] ,
LocalServiceAddress : testApp . Addr ( ) . String ( ) ,
} ,
Upstreams : upstreams ,
} ) , testutil . Logger ( t ) )
require . NoError ( t , err )
defer p . Close ( )
go p . Serve ( )
// We create this client with an explicit ServerNextProtos here which will use `h2`
// if the proxy supports it. This is so we can verify below that the proxy _doesn't_
// advertise `h2` support as it's only a L4 proxy.
svc , err := connect . NewServiceWithConfig ( "echo" , connect . Config { Client : client , ServerNextProtos : [ ] string { "h2" } } )
require . NoError ( t , err )
// Create a test connection to the proxy. We retry here a few times
// since this is dependent on the agent actually starting up and setting
// up the CA.
var conn net . Conn
retry . Run ( t , func ( r * retry . R ) {
conn , err = svc . Dial ( context . Background ( ) , & connect . StaticResolver {
Addr : TestLocalAddr ( ports [ 0 ] ) ,
CertURI : agConnect . TestSpiffeIDService ( r , "echo" ) ,
} )
if err != nil {
r . Fatalf ( "err: %s" , err )
}
} )
// Verify that we did not select h2 via ALPN since the proxy is layer 4 only
tlsConn := conn . ( * tls . Conn )
require . Equal ( t , "" , tlsConn . ConnectionState ( ) . NegotiatedProtocol )
// Connection works, test it is the right one
TestEchoConn ( t , conn , "" )
t . Run ( "verify port upstream is configured" , func ( t * testing . T ) {
// Verify that it is listening by doing a simple TCP dial.
addr := net . JoinHostPort ( "127.0.0.1" , strconv . Itoa ( ports [ 1 ] ) )
conn , err := net . DialTimeout ( "tcp" , addr , 100 * time . Millisecond )
require . NoError ( t , err )
_ = conn . Close ( )
} )
t . Run ( "verify unix domain socket upstream will never work" , func ( t * testing . T ) {
if runtime . GOOS == "windows" {
t . SkipNow ( )
}
// Ensure the socket was not created
require . NoFileExists ( t , unixSocket )
} )
}