@@ -23,13 +23,16 @@ import (
2323 "encoding/pem"
2424 "fmt"
2525 "io"
26+ "net"
2627 "net/http"
2728 "os"
2829 "regexp"
2930 "strconv"
3031 "strings"
3132 "time"
3233
34+ "github.com/paultag/sniff/parser"
35+
3336 "golang.org/x/net/http2"
3437 "golang.org/x/net/http2/h2c"
3538 "golang.org/x/net/websocket"
@@ -48,15 +51,17 @@ type RequestAssertions struct {
4851 Context `json:",inline"`
4952
5053 TLS * TLSAssertions `json:"tls,omitempty"`
54+ SNI string `json:"sni"`
5155}
5256
5357// TLSAssertions contains information about the TLS connection.
5458type TLSAssertions struct {
55- Version string `json:"version"`
56- PeerCertificates []string `json:"peerCertificates,omitempty"`
57- ServerName string `json:"serverName"`
58- NegotiatedProtocol string `json:"negotiatedProtocol,omitempty"`
59- CipherSuite string `json:"cipherSuite"`
59+ Version string `json:"version"`
60+ PeerCertificates []string `json:"peerCertificates,omitempty"`
61+ // ServerName is the SNI.
62+ ServerName string `json:"serverName"`
63+ NegotiatedProtocol string `json:"negotiatedProtocol,omitempty"`
64+ CipherSuite string `json:"cipherSuite"`
6065}
6166
6267type preserveSlashes struct {
@@ -109,6 +114,7 @@ func main() {
109114 httpMux .HandleFunc ("/health" , healthHandler )
110115 httpMux .HandleFunc ("/status/" , statusHandler )
111116 httpMux .HandleFunc ("/" , echoHandler )
117+ httpMux .HandleFunc ("/backendTLS" , echoHandler )
112118 httpMux .Handle ("/ws" , websocket .Handler (wsHandler ))
113119 httpHandler := & preserveSlashes {httpMux }
114120
@@ -124,11 +130,13 @@ func main() {
124130
125131 go runH2CServer (h2cPort , errchan )
126132
127- // Enable HTTPS if certificate and private key are given.
128- if os .Getenv ("TLS_SERVER_CERT" ) != "" && os .Getenv ("TLS_SERVER_PRIVKEY" ) != "" {
133+ // Enable HTTPS if server certificate and private key are given. (TLS_SERVER_CERT, TLS_SERVER_PRIVKEY)
134+ // Enable secure backend if CA certificate and key are given. (CA_CERT, CA_CERT_KEY)
135+ if os .Getenv ("TLS_SERVER_CERT" ) != "" && os .Getenv ("TLS_SERVER_PRIVKEY" ) != "" ||
136+ os .Getenv ("CA_CERT" ) != "" && os .Getenv ("CA_CERT_KEY" ) != "" {
129137 go func () {
130138 fmt .Printf ("Starting server, listening on port %s (https)\n " , httpsPort )
131- err := listenAndServeTLS (fmt .Sprintf (":%s" , httpsPort ), os .Getenv ("TLS_SERVER_CERT" ), os .Getenv ("TLS_SERVER_PRIVKEY" ), os .Getenv ("TLS_CLIENT_CACERTS " ), httpHandler )
139+ err := listenAndServeTLS (fmt .Sprintf (":%s" , httpsPort ), os .Getenv ("TLS_SERVER_CERT" ), os .Getenv ("TLS_SERVER_PRIVKEY" ), os .Getenv ("CA_CERT " ), httpHandler )
132140 if err != nil {
133141 errchan <- err
134142 }
@@ -201,15 +209,27 @@ func runH2CServer(h2cPort string, errchan chan<- error) {
201209}
202210
203211func echoHandler (w http.ResponseWriter , r * http.Request ) {
212+ var sni string
213+
204214 fmt .Printf ("Echoing back request made to %s to client (%s)\n " , r .RequestURI , r .RemoteAddr )
205215
206216 // If the request has form ?delay=[:duration] wait for duration
207217 // For example, ?delay=10s will cause the response to wait 10s before responding
208- if err := delayResponse (r ); err != nil {
218+ err := delayResponse (r )
219+ if err != nil {
209220 processError (w , err , http .StatusInternalServerError )
210221 return
211222 }
212223
224+ // If the request was made to URI backendTLS, then get the server name indication and
225+ // add it to the RequestAssertions. It will be echoed back later.
226+ if strings .Contains (r .RequestURI , "backendTLS" ) {
227+ sni , err = sniffForSNI (r .RemoteAddr )
228+ if err != nil {
229+ // Todo: research if for some test cases there won't be one
230+ }
231+ }
232+
213233 requestAssertions := RequestAssertions {
214234 r .RequestURI ,
215235 r .Host ,
@@ -220,6 +240,7 @@ func echoHandler(w http.ResponseWriter, r *http.Request) {
220240 context ,
221241
222242 tlsStateToAssertions (r .TLS ),
243+ sni ,
223244 }
224245
225246 js , err := json .MarshalIndent (requestAssertions , "" , " " )
@@ -296,6 +317,40 @@ func listenAndServeTLS(addr string, serverCert string, serverPrivKey string, cli
296317 return srv .ListenAndServeTLS (serverCert , serverPrivKey )
297318}
298319
320+ // sniffForSNI uses the request address to listen for the incoming TLS connection,
321+ // and tries to find the server name indication from that connection.
322+ func sniffForSNI (addr string ) (string , error ) {
323+ var sni string
324+
325+ // Listen to get the SNI, and store in config.
326+ listener , err := net .Listen ("tcp" , addr )
327+ if err != nil {
328+ return "" , err
329+ }
330+ defer listener .Close ()
331+
332+ for {
333+ conn , err := listener .Accept ()
334+ if err != nil {
335+ return "" , err
336+ }
337+ data := make ([]byte , 4096 )
338+ _ , err = conn .Read (data )
339+ if err != nil {
340+ return "" , fmt .Errorf ("could not read socket: %v" , err )
341+ }
342+ // Take an incoming TLS Client Hello and return the SNI name.
343+ sni , err = parser .GetHostname (data [:])
344+ if err != nil {
345+ return "" , fmt .Errorf ("error getting SNI: %v" , err )
346+ }
347+ if sni == "" {
348+ return "" , fmt .Errorf ("no server name indication found" )
349+ }
350+ return sni , nil
351+ }
352+ }
353+
299354func tlsStateToAssertions (connectionState * tls.ConnectionState ) * TLSAssertions {
300355 if connectionState != nil {
301356 var state TLSAssertions
0 commit comments