@@ -133,7 +133,7 @@ func TestServerClose(t *testing.T) {
133133 }
134134}
135135
136- func TestProxyProtocol (t * testing.T ) {
136+ func TestProxyProtocolEnabled (t * testing.T ) {
137137 const (
138138 CORRECT_IP = "1.1.1.1"
139139 CORRECT_PORT = 55555
@@ -232,3 +232,103 @@ func TestProxyProtocol(t *testing.T) {
232232 t .Fatal (testResult )
233233 }
234234}
235+
236+ func TestProxyProtocolDisabled (t * testing.T ) {
237+ const (
238+ INCORRECT_IP = "1.1.1.1"
239+ INCORRECT_PORT = 55555
240+ )
241+ handlerDone := make (chan struct {})
242+ var testResult error
243+
244+ handler := func (sess Session ) {
245+ defer close (handlerDone )
246+ sourceAddress := sess .RemoteAddr ()
247+
248+ index := strings .Index (sourceAddress .String (), ":" )
249+ ip := sourceAddress .String ()[:index ]
250+ portStr := sourceAddress .String ()[index + 1 :]
251+
252+ if ip == INCORRECT_IP {
253+ errorMsg := fmt .Sprintf ("Expected source address to be anything but '%s' but got '%s'" , INCORRECT_IP , ip )
254+ testResult = errors .Join (testResult , fmt .Errorf ("%s" , errorMsg ))
255+ }
256+ port , err := strconv .Atoi (portStr )
257+ if err != nil {
258+ testResult = errors .Join (testResult , fmt .Errorf ("%s" , err ))
259+ } else if port == INCORRECT_PORT {
260+ errorMsg := fmt .Sprintf ("Expected source port anything but '%d' but got '%d'" , INCORRECT_PORT , port )
261+ testResult = errors .Join (testResult , fmt .Errorf ("%s" , errorMsg ))
262+ }
263+ }
264+
265+ // Bind the port before starting the goroutine so net.Dial never races
266+ // with the server not yet listening.
267+ l := newLocalListener ()
268+ srv := & Server {Handler : handler }
269+
270+ serverDone := make (chan error , 1 )
271+
272+ go func () {
273+ serverDone <- srv .Serve (l )
274+ }()
275+
276+ defer func () {
277+ srv .Close ()
278+ if err := <- serverDone ; err != nil && err != ErrServerClosed {
279+ t .Error (err )
280+ }
281+ }()
282+
283+ serverIP , serverPortStr , _ := net .SplitHostPort (l .Addr ().String ())
284+ serverPort , _ := strconv .Atoi (serverPortStr )
285+ conn , err := net .Dial ("tcp" , l .Addr ().String ())
286+
287+ if err != nil {
288+ t .Fatal (err )
289+ }
290+
291+ //Set the PROXY header information. The server should not read it
292+ header := & proxyproto.Header {
293+ Version : 1 ,
294+ Command : proxyproto .PROXY ,
295+ TransportProtocol : proxyproto .TCPv4 ,
296+ SourceAddr : & net.TCPAddr {
297+ IP : net .ParseIP (INCORRECT_IP ),
298+ Port : INCORRECT_PORT ,
299+ },
300+ DestinationAddr : & net.TCPAddr {
301+ IP : net .ParseIP (serverIP ),
302+ Port : serverPort ,
303+ },
304+ }
305+
306+ // Writes the PROXY header to the TCP stream before SSH begins
307+ _ , err = header .WriteTo (conn )
308+ if err != nil {
309+ t .Fatal (err )
310+ }
311+
312+ // Hand the same conn to the SSH stack — handshake starts from here.
313+ clientConn , chans , reqs , err := gossh .NewClientConn (conn , l .Addr ().String (), & gossh.ClientConfig {
314+ User : "testuser" ,
315+ HostKeyCallback : gossh .InsecureIgnoreHostKey (),
316+ })
317+ if err != nil {
318+ t .Fatal (err )
319+ }
320+ client := gossh .NewClient (clientConn , chans , reqs )
321+ defer client .Close ()
322+
323+ session , err := client .NewSession ()
324+ if err != nil {
325+ t .Fatal (err )
326+ }
327+ session .Run ("" ) // triggers the handler; ignore exec error
328+
329+ <- handlerDone
330+
331+ if testResult != nil {
332+ t .Fatal (testResult )
333+ }
334+ }
0 commit comments