Unit test for proxy_protocol

Greeshma A greeshma.avadhootha at gmail.com
Tue Sep 21 04:56:10 UTC 2021


I am trying to test the following config :
For proxy_protocol I have made changes in the nginx source code to support
variable input parameter as well.
Im writing unit tests for this. However, Im not sure how to configure the
map directive. The variable  $ssl_preread_server_nameis wrong. I need to
give the destination address and port. What would I have to give in the key
part of the map definition?
ie something like
map $remote_addr:$remote_port $proxy_state {
# conditions
}

stream {
    %%TEST_GLOBALS_STREAM%%

    map $ssl_preread_server_name $proxy_state{
        default off;
        127.0.0.1:8084 on;
    }

    server {
        listen          127.0.0.1:8080;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol on;
    }

    server {
        listen          127.0.0.1:8082;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  off;
    }

    server {
        listen          127.0.0.1:8083;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  $proxy_state;
    }

    server {
        listen          127.0.0.1:8084;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  $proxy_state;
    }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20210920/33ea2ef5/attachment.htm>
-------------- next part --------------
#!/usr/bin/perl

# Tests for stream proxy module with haproxy protocol.

###############################################################################

use warnings;
use strict;

use Test::More;

use IO::Select;
use Socket qw/ $CRLF /;

BEGIN { use FindBin; chdir($FindBin::Bin); }

use lib '../nginx-tests/lib';
use Test::Nginx;
use Test::Nginx::Stream qw/ stream /;

###############################################################################

select STDERR; $| = 1;
select STDOUT; $| = 1;

my $t = Test::Nginx->new()->has(qw/stream/)
	->write_file_expand('nginx.conf', <<'EOF');

%%TEST_GLOBALS%%

daemon off;

events {
}

stream {
    %%TEST_GLOBALS_STREAM%%

    map $ssl_preread_server_name $proxy_state{
        default off;
		127.0.0.1:8084 on;
    }

    server {
        listen          127.0.0.1:8080;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol on;
    }

    server {
        listen          127.0.0.1:8082;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  off;
    }

    server {
        listen          127.0.0.1:8083;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  $proxy_state;
    }

    server {
        listen          127.0.0.1:8084;
        proxy_pass      127.0.0.1:8081;
        proxy_protocol  $proxy_state;
    }
}

EOF

$t->run_daemon(\&stream_daemon);
$t->run()->plan(4);
$t->waitforsocket('127.0.0.1:' . port(8081));

###############################################################################
# Proxy header format
# PROXY <INET PROTOCOL> <SRC IP> <DEST IP> <SRC PORT> <DEST PORT> <CRLF SEQ>
# PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n
my $dp = port(8080);
my $s = stream('127.0.0.1:' . $dp);
my $data = $s->io('close');
my $sp = $s->sockport();

$DB::single = 1;

my $dp2 = port(8083);
my $s2 = stream('127.0.0.1:' . $dp2);
my $data2 = $s2->io('close');
my $sp2 = $s2->sockport();
$DB::single = 1;
is($data, "PROXY TCP4 127.0.0.1 127.0.0.1 $sp $dp${CRLF}close", 'protocol on');

is(stream('127.0.0.1:' . port(8082))->io('close'), 'close', 'protocol off');

is($data2, "PROXY TCP4 127.0.0.1 127.0.0.1 $sp2 $dp2${CRLF}close", 'protocol variable - on');

is(stream('127.0.0.1:' . port(8084))->io('close'), 'close', 'protocol variable - off');
###############################################################################

sub stream_daemon {
	my $server = IO::Socket::INET->new(
		Proto => 'tcp',
		LocalAddr => '127.0.0.1:' . port(8081),
		Listen => 5,
		Reuse => 1
	)
		or die "Can't create listening socket: $!\n";

	my $sel = IO::Select->new($server);

	local $SIG{PIPE} = 'IGNORE';

	while (my @ready = $sel->can_read) {
		foreach my $fh (@ready) {
			if ($server == $fh) {
				my $new = $fh->accept;
				$new->autoflush(1);
				$sel->add($new);

			} elsif (stream_handle_client($fh)) {
				$sel->remove($fh);
				$fh->close;
			}
		}
	}
}

sub stream_handle_client {
	my ($client) = @_;

	log2c("(new connection $client)");

	$client->sysread(my $buffer, 65536) or return 1;

	log2i("$client $buffer");

	log2o("$client $buffer");

	$client->syswrite($buffer);

	return $buffer =~ /close/;
}

sub log2i { Test::Nginx::log_core('|| <<', @_); }
sub log2o { Test::Nginx::log_core('|| >>', @_); }
sub log2c { Test::Nginx::log_core('||', @_); }

###############################################################################


More information about the nginx-devel mailing list