[PATCH] Mail: tests for PROXY PROTOCOL support

muradm mail at muradm.net
Sat Jan 16 11:58:07 UTC 2021


# HG changeset patch
# User muradm <mail at muradm.net>
# Date 1610797338 -10800
#      Sat Jan 16 14:42:18 2021 +0300
# Node ID 76e7def783657962088ec2e8346b839cda744efb
# Parent  6c323c672a8678b7cff4c0ccc7b303ef2e477f7c
Mail: tests for PROXY PROTOCOL support

diff -r 6c323c672a86 -r 76e7def78365 mail_proxy_protocol_handle.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mail_proxy_protocol_handle.t	Sat Jan 16 14:42:18 2021 +0300
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+# Tests for imap/pop3/smtp proxy protocol handling.
+# Note: testing only v1 protocol here with hope that v2 is tested by core
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use Test::Nginx::IMAP;
+use Test::Nginx::POP3;
+use Test::Nginx::SMTP;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/mail imap pop3 smtp/)->plan(7);
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+mail {
+    auth_http  http://127.0.0.1:8080; # unused
+
+    server {
+        listen     127.0.0.1:8143 proxy_protocol;
+        protocol   imap;
+    }
+
+    server {
+        listen     127.0.0.1:8110 proxy_protocol;
+        protocol   pop3;
+    }
+
+    server {
+        listen     127.0.0.1:8025 proxy_protocol;
+        protocol   smtp;
+    }
+}
+
+EOF
+
+$t->run();
+
+###############################################################################
+
+# imap, proxy protocol handler
+
+my $s = Test::Nginx::IMAP->new(PeerAddr => '127.0.0.1:' . port(8143));
+$s->send('PROXY TCP4 192.168.1.10 192.168.1.1 18143 8143');
+$s->read();
+
+$s->send('1 CAPABILITY');
+$s->check(qr/^\* CAPABILITY IMAP4 IMAP4rev1 UIDPLUS AUTH=PLAIN/, 'imap proxy protocol');
+$s->ok('imap proxy protocol handler');
+
+###############################################################################
+
+# pop3, proxy protocol handler
+
+$s = Test::Nginx::POP3->new(PeerAddr => '127.0.0.1:' . port(8110));
+$s->send('PROXY TCP4 192.168.1.10 192.168.1.1 18143 8110');
+$s->read();
+
+$s->send('CAPA');
+$s->ok('pop3 capa');
+
+my $caps = get_auth_caps($s);
+like($caps, qr/USER/, 'pop3 - user');
+like($caps, qr/TOP:USER:UIDL:SASL PLAIN LOGIN/, 'pop3 - methods');
+unlike($caps, qr/STLS/, 'pop3 - no stls');
+
+###############################################################################
+
+# smtp, proxy protocol handler
+
+$s = Test::Nginx::SMTP->new(PeerAddr => '127.0.0.1:' . port(8025));
+$s->send('PROXY TCP4 192.168.1.10 192.168.1.1 18143 8110');
+$s->read();
+
+$s->send('EHLO example.com');
+$s->check(qr/^250 AUTH PLAIN LOGIN\x0d\x0a?/, 'smtp ehlo');
+
+###############################################################################
+
+sub get_auth_caps {
+	my ($s) = @_;
+	my @meth;
+
+	while ($s->read()) {
+		last if /^\./;
+		push @meth, $1 if /(.*?)\x0d\x0a?/ms;
+	}
+	join ':', @meth;
+}
+
+###############################################################################
diff -r 6c323c672a86 -r 76e7def78365 mail_proxy_protocol_handle_ssl.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mail_proxy_protocol_handle_ssl.t	Sat Jan 16 14:42:18 2021 +0300
@@ -0,0 +1,156 @@
+#!/usr/bin/perl
+
+# Tests for mail proxy protocol handler with ssl.
+# Note: testing only v1 protocol here with hope that v2 is tested by core
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Socket qw/ CRLF /;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+eval {
+	require Net::SSLeay;
+	Net::SSLeay::load_error_strings();
+	Net::SSLeay::SSLeay_add_ssl_algorithms();
+	Net::SSLeay::randomize();
+};
+plan(skip_all => 'Net::SSLeay not installed') if $@;
+
+my $t = Test::Nginx->new()->has(qw/mail mail_ssl imap pop3 smtp/)
+	->has_daemon('openssl')->plan(6);
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+mail {
+    auth_http  http://127.0.0.1:8080; # unused
+
+    ssl_certificate_key localhost.key;
+    ssl_certificate localhost.crt;
+    ssl_session_tickets off;
+
+    ssl_password_file password;
+
+    ssl_session_cache none;
+
+    server {
+        listen             127.0.0.1:8993 ssl;
+        protocol           imap;
+    }
+
+    server {
+        listen             127.0.0.1:8994 ssl proxy_protocol;
+        protocol           imap;
+    }
+
+    server {
+        listen             127.0.0.1:8995 ssl;
+        protocol           pop3;
+    }
+
+    server {
+        listen             127.0.0.1:8996 ssl proxy_protocol;
+        protocol           pop3;
+    }
+
+    server {
+        listen             127.0.0.1:8465 ssl;
+        protocol           smtp;
+    }
+
+    server {
+        listen             127.0.0.1:8466 ssl proxy_protocol;
+        protocol           smtp;
+    }
+}
+
+EOF
+
+$t->write_file('openssl.conf', <<EOF);
+[ req ]
+default_bits = 2048
+encrypt_key = no
+distinguished_name = req_distinguished_name
+[ req_distinguished_name ]
+EOF
+
+my $d = $t->testdir();
+
+foreach my $name ('localhost', 'inherits') {
+	system("openssl genrsa -out $d/$name.key -passout pass:localhost "
+		. "-aes128 2048 >>$d/openssl.out 2>&1") == 0
+		or die "Can't create private key: $!\n";
+	system('openssl req -x509 -new '
+		. "-config $d/openssl.conf -subj /CN=$name/ "
+		. "-out $d/$name.crt "
+		. "-key $d/$name.key -passin pass:localhost"
+		. ">>$d/openssl.out 2>&1") == 0
+		or die "Can't create certificate for $name: $!\n";
+}
+
+my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
+$t->write_file('password', 'localhost');
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+###############################################################################
+
+my @list = (qw(8993 8994 8995 8996 8465 8466));
+
+while (my ($p1, $p2) = splice (@list,0,2)) {
+    my ($s, $ssl, $ses);
+
+    $s = get_socket($p1);
+
+    $ssl = make_ssl_socket($s);
+    $ses = Net::SSLeay::get_session($ssl);
+    like(Net::SSLeay::dump_peer_certificate($ssl), qr/CN=localhost/, 'CN');
+
+    $s = get_socket($p2);
+    $s->print('PROXY TCP4 192.168.1.10 192.168.1.1 18143 8110' . CRLF);
+
+    $ssl = make_ssl_socket($s);
+    $ses = Net::SSLeay::get_session($ssl);
+    like(Net::SSLeay::dump_peer_certificate($ssl), qr/CN=localhost/, 'CN');
+}
+
+###############################################################################
+
+sub get_socket {
+	my ($port) = @_;
+    return IO::Socket::INET->new('127.0.0.1:' . port($port));
+}
+
+sub make_ssl_socket {
+	my ($socket, $ses) = @_;
+
+	my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
+	Net::SSLeay::set_session($ssl, $ses) if defined $ses;
+	Net::SSLeay::set_fd($ssl, fileno($socket));
+	Net::SSLeay::connect($ssl) or die("ssl connect");
+	return $ssl;
+}
+
+###############################################################################
diff -r 6c323c672a86 -r 76e7def78365 mail_proxy_proxy_protocol.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mail_proxy_proxy_protocol.t	Sat Jan 16 14:42:18 2021 +0300
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+
+# Tests for nginx mail proxy module, the proxy_protocol directive.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Socket qw/ CRLF /;
+
+use Test::More;
+
+use MIME::Base64;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use Test::Nginx::SMTP;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+local $SIG{PIPE} = 'IGNORE';
+
+my $t = Test::Nginx->new()->has(qw/mail smtp http rewrite/)->plan(9);
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+    worker_connections 48;
+}
+
+mail {
+    auth_http  http://127.0.0.1:8080/mail/auth;
+    smtp_auth  login plain external;
+
+    server {
+        listen     127.0.0.1:8025;
+        protocol   smtp;
+        xclient    off;
+    }
+
+    server {
+        listen     127.0.0.1:8027;
+        protocol   smtp;
+        xclient    off;
+        proxy_protocol on;
+    }
+
+    server {
+        listen     127.0.0.1:8029 proxy_protocol;
+        protocol   smtp;
+        xclient    off;
+        proxy_protocol on;
+        proxy_smtp_auth on;
+    }
+}
+
+http {
+    %%TEST_GLOBALS_HTTP%%
+
+    server {
+        listen       127.0.0.1:8080;
+        server_name  localhost;
+
+        location = /mail/auth {
+            add_header Auth-Status OK;
+            add_header Auth-Server 127.0.0.1;
+            add_header Auth-Port   %%PORT_8026%%;
+            add_header Auth-User   test at example.com;
+            add_header Auth-Pass   test at example.com;
+            return 204;
+        }
+    }
+}
+
+EOF
+
+$t->run();
+
+###############################################################################
+
+my ($s, $pp_data);
+
+# no proxy_protocol in or out
+
+$t->run_daemon(\&smtp_test_listener, port(8026));
+$t->waitforsocket('127.0.0.1:' . port(8026));
+
+$s = Test::Nginx::SMTP->new(PeerAddr => '127.0.0.1:' . port(8025));
+$s->check(qr/ESMTP ready/);
+$s->send('EHLO example.com');
+$s->check(qr/250 AUTH PLAIN LOGIN EXTERNAL/);
+$s->send('AUTH PLAIN ' . encode_base64("\0test\@example.com\0secret", ''));
+$s->authok('ehlo, auth');
+$t->stop_daemons();
+
+# proxy_protocol only out
+
+$pp_data = 'PROXY TCP4 192.168.1.10 192.168.1.11';
+$t->run_daemon(\&smtp_test_listener, port(8026), $pp_data);
+$t->waitforsocket('127.0.0.1:' . port(8026));
+
+$s = Test::Nginx::SMTP->new(PeerAddr => '127.0.0.1:' . port(8027));
+$s->check(qr/ESMTP ready/);
+$s->send('EHLO example.com');
+$s->check(qr/250 AUTH PLAIN LOGIN EXTERNAL/);
+$s->send('AUTH PLAIN ' . encode_base64("\0test\@example.com\0secret", ''));
+$s->authok('ehlo, auth');
+$t->stop_daemons();
+
+# proxy_protocol only out and in
+$pp_data = 'PROXY TCP4 192.168.1.10 192.168.1.11';
+$t->run_daemon(\&smtp_test_listener, port(8026), $pp_data);
+$t->waitforsocket('127.0.0.1:' . port(8026));
+
+$s = Test::Nginx::SMTP->new(PeerAddr => '127.0.0.1:' . port(8029));
+$s->send($pp_data . ' 51298 8027');
+$s->check(qr/ESMTP ready/);
+$s->send('EHLO example.com');
+$s->check(qr/250 AUTH PLAIN LOGIN EXTERNAL/);
+$s->send('AUTH PLAIN ' . encode_base64("\0test\@example.com\0secret", ''));
+$s->authok('ehlo, auth');
+$t->stop_daemons();
+
+
+###############################################################################
+
+sub smtp_test_listener {
+	my ($port, $expected) = @_;
+    my $server = IO::Socket::INET->new(
+		Proto => 'tcp',
+		LocalAddr => '127.0.0.1:' . ($port || port(8026)),
+		Listen => 5,
+        Reuse => 1
+	)
+		or die "Can't create listening socket: $!\n";
+
+    while (my $client = $server->accept()) {
+        $client->autoflush(1);
+
+        if (defined($expected)) {
+            $expected = $expected . CRLF;
+            while (<$client>) {
+                if (/^proxy/i) {
+                    Test::Nginx::log_core('||>>', $_);
+                    last;
+                }
+            }
+        }
+
+        sub send_client {
+            my ($c, $d) = @_;
+            Test::Nginx::log_core('||<<', $d);
+            print $c $d . CRLF;
+        }
+
+        print $client "220 fake esmtp server ready" . CRLF;
+
+        while (<$client>) {
+            Test::Nginx::log_core('||>>', $_);
+
+            my $res = '';
+
+            if (/^quit/i) {
+                send_client($client, '221 quit ok');
+            } elsif (/^(ehlo|helo)/i) {
+                send_client($client, '250-ok');
+                send_client($client, '250 AUTH PLAIN LOGIN EXTERNAL');
+            } elsif (/^rset/i) {
+                send_client($client, '250 rset ok');
+            } elsif (/^auth plain/i) {
+                send_client($client, '235 auth ok');
+            } elsif (/^mail from:[^@]+$/i) {
+                send_client($client, '500 mail from error');
+            } elsif (/^mail from:/i) {
+                send_client($client, '250 mail from ok');
+            } elsif (/^rcpt to:[^@]+$/i) {
+                send_client($client, '500 rcpt to error');
+            } elsif (/^rcpt to:/i) {
+                send_client($client, '250 rcpt to ok');
+            } else {
+                send_client($client, '500 unknown command');
+            }
+        }
+
+		close $client;
+    }
+}
+
+###############################################################################


More information about the nginx-devel mailing list