File: bad_dns_request_test

package info (click to toggle)
sniproxy 0.6.0-2%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 704 kB
  • sloc: ansic: 5,539; perl: 1,673; sh: 237; makefile: 131
file content (176 lines) | stat: -rwxr-xr-x 4,193 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/usr/bin/env perl

use strict;
use warnings;
use File::Basename;
use lib dirname (__FILE__);
use TestUtils;
use TestHTTPD;
use File::Temp;
use IO::Socket::INET;

my $bad_requests = [
    {
        # Test bad name server
        request => "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n",
        client => \&http_client,
    },
    {
        # Invalid hostname
        request => "GET / HTTP/1.1\r\nHost: ...........\r\n\r\n",
        client => \&http_client,
    },
    {
        # Exceed buffer size
        request => "PUT / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 65536\r\n\r\n" . 'x' x 65536,
        client => \&http_client,
    },
    {
        # Exceed buffer size before host header
        request => "GET /" . 'x' x 65536,
        client => \&http_client,
    },
    {
        # Invalid hostname
        request => "GET / HTTP/1.1\r\nHost: \0example.com\r\n\r\n",
        client => \&http_client,
    },
    {
        # Exceed hostname buffer size
        request => "GET / HTTP/1.1\r\nHost: [" . 'long.' x 60 . "example.com]\r\n\r\n",
        client => \&http_client,
    },
    {
        # Test client aborting connection before DNS response received
        request => "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n",
        client => \&http_client_abort,
    },
];

sub http_client($$) {
    my $port = shift;
    my $request = shift;

    my $socket = IO::Socket::INET->new(PeerAddr => '127.0.0.1',
                                       PeerPort => $port,
                                       Proto => "tcp",
                                       Type => SOCK_STREAM)
        or die "couldn't connect $!";

    $socket->send($request);

    my $buffer;
    $socket->recv($buffer, 4096);

    $socket->close();

    return undef;
}

sub http_client_abort($$) {
    my $port = shift;
    my $request = shift;

    my $socket = IO::Socket::INET->new(PeerAddr => '127.0.0.1',
                                       PeerPort => $port,
                                       Proto => "tcp",
                                       Type => SOCK_STREAM)
        or die "couldn't connect $!";

    $socket->send($request);
    sleep(1);

    $socket->close();

    return undef;
}

sub proxy {
    my $config = shift;

    exec(@_, '../src/sniproxy', '-f', '-c', $config);
}


sub worker($$$) {
    my ($port, $requests, $offset) = @_;

    for (my $i = 0; $i < $requests; $i++) {
        my $test = $bad_requests->[($i + $offset) % int(@$bad_requests)];
        my $error = $test->{client}($port, $test->{request});

        die($error) if defined $error;
    }
    # Success
    exit 0;
}

sub make_wildcard_config($) {
    my $proxy_port = shift;

    my ($fh, $filename) = File::Temp::tempfile();

    # Write out a test config file
    print $fh <<END;
# Minimal test configuration

resolver {
    # Use an RFC1166 documentation prefix IP address as the nameserver
    # this should be not respond to DNS queries in any environment
    nameserver 192.0.2.99
}

listen 127.0.0.1 $proxy_port {
    proto http
}

table {
    .* *:80
}
END

    close ($fh);

    return $filename;
}

sub main {
    my $proxy_port = $ENV{SNI_PROXY_PORT} || 8080;
    my $workers = $ENV{WORKERS} || 3;
    my $iterations = $ENV{ITERATIONS} || int(@$bad_requests);

    my $config = make_wildcard_config($proxy_port);
    my $proxy_pid = start_child('server', \&proxy, $config, @ARGV);

    # Wait for proxy to load and parse config
    wait_for_port(port => $proxy_port);

    for (my $i = 0; $i < $workers; $i++) {
        start_child('worker', \&worker, $proxy_port, $iterations, $i);
    }

    # Wait for all our children to finish
    wait_for_type('worker');

    # Give the proxy a second to flush buffers and close server connections
    sleep 1;

    # For troubleshooting connections stuck in CLOSE_WAIT state
    #kill 10, $proxy_pid;
    #system("netstat -ptn | grep $proxy_pid\/sniproxy");

    # For troubleshooting 100% CPU usage
    #system("top -n 1 -p $proxy_pid -b");

    # Orderly shutdown of the server
    kill 15, $proxy_pid;
    sleep 1;

    # Delete our test configuration
    unlink($config);

    # Kill off any remaining children
    reap_children();
}

main();