def run_test(self, status_code=200, is_frang=False):
        klog = dmesg.DmesgFinder(ratelimited=False)
        curl = self.get_client('curl')
        referer = 'http2-referer-%d' % status_code
        user_agent = 'http2-user-agent-%d' % status_code
        curl.options.append('-e "%s"' % referer)
        curl.options.append('-A "%s"' % user_agent)

        self.start_all_servers()
        self.start_tempesta()

        if is_frang:
            try:
                self.run_curl(curl)
            except:
                pass
        else:
            self.run_curl(curl)

        nginx = self.get_server('nginx')
        nginx.get_stats()
        self.assertEqual(0 if is_frang else 1,
                         nginx.requests,
                         msg="Unexpected number forwarded requests to backend")

        msg = AccessLogLine.from_dmesg(klog)
        self.assertTrue(msg is not None, "No access_log message in dmesg")
        self.assertEqual(msg.method, 'GET', 'Wrong method')
        self.assertEqual(msg.status, status_code, 'Wrong HTTP status')
        self.assertEqual(msg.user_agent, user_agent)
        self.assertEqual(msg.referer, referer)
        return msg
    def test_with_tlsperf(self):
        """
        Test with tls-perf which uses usual openssl configuration and works as
        most usual ssl clients. tls-perf doesn't have fixed frame rate, but it
        works fast and we use small limits to ensure that all messages are
        received almost immediately.
        """

        self.start_all_servers()
        self.start_tempesta()
        srv = self.get_server('0')
        self.deproxy_manager.start()
        self.assertTrue(srv.wait_for_connections(timeout=1))

        klog = dmesg.DmesgFinder(ratelimited=False)

        tls_perf = self.get_client('tls-perf-with-tickets')
        tls_perf.start()
        self.wait_while_busy(tls_perf)
        self.assertEqual(klog.warn_count(self.TLS_WARN), 0,
                         "Frang limits warning was incorrectly shown")

        tls_perf = self.get_client('tls-perf')
        tls_perf.start()
        self.wait_while_busy(tls_perf)
        self.assertEqual(klog.warn_count(self.TLS_WARN), 1,
                         "Frang limits warning is not shown")
    def test_host_sni_mismatch(self):
        """ With the `http_host_required` limit, the host header and SNI name
        must be identical. Otherwise request will be filtered. After client
        send a request that doesnt match his SNI, t is blocked
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: tempesta-tech.com\r\n" \
                   "\r\n" \
                   "GET / HTTP/1.1\r\n" \
                   "Host:    tempesta-tech.com     \r\n" \
                   "\r\n" \
                   "GET / HTTP/1.1\r\n" \
                   "Host: example.com\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('usual-client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(2, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.TLS_WARN), 1,
                         "Frang limits warning is not shown")
示例#4
0
 def setUp(self):
     tf_cfg.dbg(3, '\tInit test case...')
     if not remote.wait_available():
         raise Exception("Tempesta node is unavaliable")
     self.oops = dmesg.DmesgFinder()
     self.oops_ignore = []
     self.__create_servers()
     self.__create_tempesta()
     self.__create_clients()
 def test_success_path_http1x(self):
     self.start_all()
     klog = dmesg.DmesgFinder(ratelimited=False)
     for status, body in [
         (200, 'body http ok'),
         (204, None),
         (302, 'redirect body'),
         (404, 'not-found body'),
         (500, 'internal-server-error body'),
     ]:
         self.check_response(klog, status, body)
 def test_bad_user_agent(self):
     self.start_all()
     klog = dmesg.DmesgFinder(ratelimited=False)
     req = self.make_request('/some-uri',
                             user_agent='bad\nagent',
                             referer='Ok-Referer')
     msg = self.send_request_and_get_dmesg(klog, req)
     self.assertTrue(msg is not None, "No access_log message in dmesg")
     self.assertNotEqual(msg.status, 0, 'Empty response status')
     # Make sure that some fields are properly set
     self.assertEqual(msg.method, 'GET', 'Wrong method')
     self.assertEqual(msg.uri, '/some-uri', 'Wrong uri')
     self.assertNotEqual(msg.ip, '-', 'Wrong ip')
示例#7
0
 def setUp(self):
     # Init members used in tearDown function.
     self.oops = dmesg.DmesgFinder()
     self.oops_ignore = []
     self.tempesta = None
     self.servers = []
     tf_cfg.dbg(3) # Step to the next line after name of test case.
     tf_cfg.dbg(3, '\tInit test case...')
     if not remote.wait_available():
         raise Exception("Tempesta node is unavaliable")
     self.create_clients()
     self.create_servers()
     self.create_tempesta()
 def test_frang(self):
     self.start_all()
     klog = dmesg.DmesgFinder(ratelimited=False)
     req = self.make_request('/longer-than-10-symbols-uri',
                             user_agent='user-agent',
                             referer='referer')
     msg = self.send_request_and_get_dmesg(klog, req)
     self.assertTrue(msg is not None, 'No access_log message in dmesg')
     self.assertEqual(msg.method, 'GET', 'Wrong method')
     self.assertEqual(msg.status, 403, 'Wrong HTTP status')
     self.assertEqual(msg.uri, '/longer-than-10-symbols-uri', 'Wrong uri')
     self.assertEqual(msg.user_agent, 'user-agent', 'Wrong user-agent')
     self.assertEqual(msg.referer, 'referer', 'Wrong referer')
     self.assertNotEqual(msg.ip, '-', 'Wrong ip')
 def test_uri_truncate(self):
     self.start_all()
     klog = dmesg.DmesgFinder(ratelimited=False)
     req = self.make_request('/too-long-uri_' + '1' * 4000,
                             user_agent='user-agent',
                             referer='referer')
     msg = self.send_request_and_get_dmesg(klog, req)
     self.assertTrue(msg is not None, "No access_log message in dmesg")
     self.assertEqual(msg.method, 'GET', 'Wrong method')
     self.assertEqual(msg.status, 200, 'Wrong HTTP status')
     self.assertEqual(msg.uri[:len('/too-long-uri_1111')],
                      '/too-long-uri_1111',
                      'Wrong uri prefix')
     self.assertEqual(msg.uri[-4:], '1...', 'URI does not looks truncated')
     self.assertEqual(msg.user_agent, 'user-agent', 'Wrong user-agent')
     self.assertEqual(msg.referer, 'referer', 'Wrong referer')
     self.assertNotEqual(msg.ip, '-', 'Wrong ip')
示例#10
0
    def test_host_missing(self):
        """ Host header is missing, but required.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.WARN_UNKNOWN), 1,
                          "Frang limits warning is not shown")
    def test_host_sni_bypass_check(self):
        """ SNI is not set. Requests to any ports are allowed.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: example.com\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('no-sni-client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(1, len(deproxy_cl.responses))
        self.assertEqual(klog.warn_count(self.TLS_WARN), 0,
                         "Frang limits warning was unexpectedly shown")
示例#12
0
    def test_host_empty(self):
        """ Host header has empty value. Restricted by Tempesta security rules.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: \r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.WARN_UNKNOWN), 1,
                          "Frang limits warning is not shown")
示例#13
0
    def test_host_mismatch(self):
        """ Host header and authority in uri has different values.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET http://[email protected]/ HTTP/1.1\r\n" \
                   "Host: example.com\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.WARN_DIFFER), 1,
                          "Frang limits warning is not shown")
示例#14
0
 def try_tls_vers(self, version):
     klog = dmesg.DmesgFinder(ratelimited=False)
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.settimeout(self.io_to)
     sock.connect((self.addr, self.port))
     try:
         context = ssl.SSLContext(protocol=version)
         tls_sock = context.wrap_socket(sock)
     except ssl.SSLError as e:
         # Correct connection termination with PROTOCOL_VERSION alert.
         if e.reason == "TLSV1_ALERT_PROTOCOL_VERSION":
             return True
     except IOError as e:
         if self.verbose:
             print("TLS handshake failed w/o warning")
     if self.verbose:
         print("Connection of unsupported TLS 1.%d established" % version)
     return False
示例#15
0
    def test_host_old_proto(self):
        """ Host header in http request below http/1.1. Restricted by
        Tempesta security rules.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.0\r\n" \
                   "Host: tempesta-tech.com\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.WARN_OLD_PROTO), 1,
                          "Frang limits warning is not shown")
    def test_auto_port_mismatch(self):
        """ After client send a request that has port mismatch in host header,
        # it is blocked. Port is defined from implicit values.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: tempesta-tech.com\r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('over-444-port')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.TLS_WARN_PORT), 1,
                         "Frang limits warning is not shown")
示例#17
0
    def test_host_mismatch_empty(self):
        """ Host header is empty, only authority in uri points to specific
        virtual host. Not allowed by RFC.
        """
        self.start_all()
        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET http://[email protected]/ HTTP/1.1\r\n" \
                   "Host: \r\n" \
                   "\r\n"
        deproxy_cl = self.get_client('client')
        deproxy_cl.start()
        deproxy_cl.make_requests(requests)
        deproxy_cl.wait_for_response()

        self.assertEqual(0, len(deproxy_cl.responses))
        self.assertTrue(deproxy_cl.connection_is_closed())
        self.assertEqual(klog.warn_count(self.WARN_UNKNOWN), 1,
                          "Frang limits warning is not shown")
示例#18
0
    def test_pass(self):
        """ Authority header contains host in DNS form, request is allowed.
        """
        curl = self.get_client('curl-dns')

        self.start_all_servers()
        self.start_tempesta()
        srv = self.get_server('0')
        self.deproxy_manager.start()
        self.assertTrue(srv.wait_for_connections(timeout=1))
        klog = dmesg.DmesgFinder(ratelimited=False)

        curl.start()
        self.wait_while_busy(curl)
        self.assertEqual(0, curl.returncode,
                         msg=("Curl return code is not 0 (%d)." %
                              (curl.returncode)))
        self.assertEqual(klog.warn_count(self.WARN_IP_ADDR), 0,
                          "Frang limits warning is incorrectly shown")
        curl.stop()
示例#19
0
    def test_block(self):
        """ Authority header  contains name in IP address form, request is
        rejected.
        """
        curl = self.get_client('curl-ip')

        self.start_all_servers()
        self.start_tempesta()
        srv = self.get_server('0')
        self.deproxy_manager.start()
        self.assertTrue(srv.wait_for_connections(timeout=1))
        klog = dmesg.DmesgFinder(ratelimited=False)

        curl.start()
        self.wait_while_busy(curl)
        self.assertEqual(1, curl.returncode,
                         msg=("Curl return code is not 1 (%d)." %
                              (curl.returncode)))
        self.assertEqual(klog.warn_count(self.WARN_IP_ADDR), 1,
                          "Frang limits warning is not shown")
        curl.stop()
    def test(self):
        self.start_all_servers()
        self.start_tempesta()
        self.deproxy_manager.start()
        srv = self.get_server('0')
        self.assertTrue(srv.wait_for_connections(timeout=1))

        self.klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: tempesta-tech.com\r\n" \
                   "\r\n"
        connected = 0
        not_connected = 0
        for i in range(11):
            deproxy_cl = self.get_client('%d' % i)
            deproxy_cl.start()
            # Push some data as request, but it will be sent as plain HTTP
            # to a TLS socket, so 'Bad TLS record' handshake error happens
            # on the Tempesta side. Since a TLS connection isn't established,
            # not TLS alerts are send by Tempesta.
            deproxy_cl.make_requests(requests)
            # Give some time to process events.
            time.sleep(0.01)
            if not deproxy_cl.connection_is_closed():
                connected += 1
            else:
                not_connected += 1
            # Need to stop client or TLS warning is now shown until Tempesta
            # shutdown
            deproxy_cl.stop()

        self.assertEqual(0, connected)
        self.assertEqual(11, not_connected)
        wc = self.klog.warn_count(self.TLS_WARN)
        # We run more requests to be in time for the limit, so there could be
        # several warnings.
        self.assertTrue(wc >= 1, "Frang limits warning is not shown")
    def test_with_deproxy(self):
        """ Test with deproxy, Python has no session resumption on client side,
        thus clients will use a new TLS session every time. If self.BURST is
        disabled, make a pause to open connections slower. Don't use high limit
        values here: deproxy is not fast.
        """
        self.start_all_servers()
        self.start_tempesta()
        self.deproxy_manager.start()
        srv = self.get_server('0')
        self.assertTrue(srv.wait_for_connections(timeout=1))

        klog = dmesg.DmesgFinder(ratelimited=False)

        requests = "GET / HTTP/1.1\r\n" \
                   "Host: tempesta-tech.com\r\n" \
                   "\r\n"
        connected = 0
        not_connected = 0
        for i in range(11):
            deproxy_cl = self.get_client('%d' % i)
            deproxy_cl.start()
            # Test works more stable if client sends a request
            deproxy_cl.make_requests(requests)
            deproxy_cl.wait_for_response()
            if not deproxy_cl.connection_is_closed():
                connected += 1
            else:
                not_connected += 1
            if i == 5 and not self.BURST:
                time.sleep(0.5)

        self.assertEqual(1, not_connected)
        self.assertEqual(10, connected)
        self.assertEqual(klog.warn_count(self.TLS_WARN), 1,
                         "Frang limits warning is not shown")