Code Monkey home page Code Monkey logo

testproxy's Introduction

TestProxy - Tool for end-to-end testing of proxy servers

Version Build Status

Copyright (C) 2019-2022, Soner Tari. https://github.com/sonertari/TestProxy

Overview

TestProxy is designed to be used for end-to-end testing of any program, such as a proxy server, which runs in between a client and a server, and communicates with them over networking packets.

A proxy server accepts connections from a client on the one side, and transfers the packets between that client and a server on the other side (it may or may not modify the packets it transfers). So, TestProxy acts as both the client and the server to simulate this environment. It starts a manager thread to run the tests, and in turn the manager thread starts a client and a server thread for each test. The manager sends commands to these client/server pairs to execute the tests it is started for.

The SSLproxy project uses TestProxy in its end-to-end tests. See the testproxy test sets in the SSLproxy sources to learn how to use TestProxy.

Operation Diagram

TestProxy test steps are composed of a test end, a command, and a payload. For example, a test can instruct a client to send an HTTP request to the proxy server under test using the send command with a payload such as GET / HTTP/1.1\r\nHost: example.com\r\n\r\n. The next step of the same test can instruct the pairing server to receive this HTTP request from the proxy using the recv command with the same payload GET / HTTP/1.1\r\nHost: example.com\r\n\r\n, assuming the proxy is not expected to modify the payload. These send and receive steps of the test are called states, and are executed in the order they are numbered, as below.

"states": {
  "1": {
    "testend": "client",
    "cmd": "send",
    "payload": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
  },
  "2": {
    "testend": "server",
    "cmd": "recv",
    "payload": "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n",
  }
}

This test becomes successful if both of these commands succeed, but it fails if either of the commands fails or the received payload does not match the expected payload of the recv command. Such tests may contain assertions too. See the sample tests under the examples folder in the sources to learn more about possible assertions.

Such tests can be saved in a JSON file to form a test set. The protocol and test ends of the test set are configured in the beginning of the file. The test set can be executed using multiple configuration. For example, the following test set specifies two configuration, which means that the tests in the test set will be executed twice, once for each configuration. Note that the first configuration is for TCP and the second is for SSL tests, and that the client and the server ports are different in each configuration. The proxy server under test should have been configured to accept connections on those client ports and to forward packets to those server ports.

"comment": "Tests for HTTP request/response",
"configs": {
  "1": {
    "proto": {
      "proto": "tcp"
    },
    "client": {
      "ip": "127.0.0.1",
      "port": "8181"
    },
    "server": {
      "ip": "127.0.0.1",
      "port": "9181"
    }
  },
  "2": {
    "proto": {
      "proto": "ssl",
      "crt": "server.crt",
      "key": "server.key"
    },
    "client": {
      "ip": "127.0.0.1",
      "port": "8444"
    },
    "server": {
      "ip": "127.0.0.1",
      "port": "9444"
    }
  }
},
"tests": {
  "1": {
    "comment": "Sends an HTTP request",
    "states": {
      ...
    }
  },
  "2": {
    "comment": "Receives an HTTP response",
    "states": {
      ...
    }
  }
}

Furthermore, such test sets can be bundled to form a test harness. For example, a sample test harness may be as follows:

{
  "comment": "Proxy end-to-end tests",
  "testharnesses": {
    "1": {
      "comment": "HTTP tests",
      "testsets": {
        "1": "http_testset_1.json",
        "2": "http_testset_2.json"
      }
    }
  }
}

One or more test harnesses can be saved in a JSON file. This is the file that the testproxy executable should be started with using the -f option. For example, the following is the screenshot of testproxy output when started with a testharness.json file and the debug level of 3 (which is the default, but TestProxy can produce detailed debug logs and very verbose trace logs as well):

Sample Output

In summary, the main test harnesses file may be composed of multiple test harnesses. Test harnesses may be divided into multiple test sets, which may be composed of tests defined in a test set file. Each test may contain multiple steps called states, and may contain assertions.

TestProxy runs multithreaded. Test harnesses are run serially, starting from the first one, but TestProxy starts a manager thread for each test set in the test harness. Manager thread runs the tests in its test set serially, but it starts a client and a server thread for each test in the test set. Manager thread communicates with those client and server threads over messaging channels, and expects execution results back.

TestProxy currently supports the TCP and SSL protocols.

License

TestProxy is provided under the GPLv3 license.

testproxy's People

Contributors

sonertari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

testproxy's Issues

Test 1 failed: Configures ssl cert, proto, cipher_list correctly

I want to test the SSLProxy with this tool, but whenever I want to run a test. I get the following errors I do not know if I'm doing something wrong or if it's a bug or something else.

With the ssl_testset_1.json

[16:00:21] [WARN] testproxy: SSLproxy tests
[16:00:21] [WARN] testproxy: Start test harness 1: SSL tests
[16:00:21] [WARN] MGR.h1.s1.c1: Start test set 1 for test config 1: Tests for SSL configuration
[16:00:21] [ERROR] MGR.h1.s1.c1: Test 1 failed: Configures ssl cert, proto, cipher_list correctly
[16:00:21] [ERROR] testproxy: Test set h1.s1 failed
[16:00:21] [ERROR] testproxy: Test harness 1 failed: SSL tests
With the http_testset_1.json
[15:53:05] [ERROR] SRV.h1.s1.c1.t1.0: TCP stream connect timed out
[15:53:05] [ERROR] MGR.h1.s1.c1: Test 1 failed: Removes any extra SSLproxy line, and appends Connection: close
[15:53:05] [ERROR] testproxy: Test set h1.s1 failed
[15:53:05] [ERROR] testproxy: Test harness 1 failed: SSL tests

This is the harness.json file i use

{
  "comment": "SSLproxy tests",
  "testharnesses": {
    "1": {
      "comment": "SSL tests",
      "testsets": {
       
        "1": "ssl_testset_1.json"
      }
  }
}
}

I used the ssl and http test in the examples folder to try it out


{
  "comment": "Tests for SSL configuration",
  "configs": {
    "1": {
      "proto": {
        "proto": "ssl",
        "tcp_nodelay": "yes",
        "ip_ttl": "15",
        "connect_timeout": "1000",
        "read_timeout": "50",
        "write_timeout": "50",
        "verify_peer": "no",
        "cipher_list": "MEDIUM:HIGH",
        "no_ssl2": "yes",
        "no_ssl3": "yes",
        "no_tls10": "yes",
        "no_tls11": "yes",
        "no_tls12": "yes",
        "no_tls13": "yes",
        "min_proto_version": "ssl3",
        "max_proto_version": "tls13",
        "ecdhcurve": "prime256v1",
        "use_sni": "no",
        "verify_hostname": "no",
        "compression": "no"
      },
      "client": {
        "ip": "127.0.0.1",
        "port": "8443",
        "crt": "/TestProxy/target/debug/server.crt",
        "key": "/TestProxy/target/debug/server.key",
        "cipher_list": "MEDIUM",
        "use_sni": "yes",
        "sni_servername": "comixwall.org",
        "verify_hostname": "yes",
        "no_tls10": "no",
        "max_proto_version": "tls11"
      },
      "server": {
        "ip": "127.0.0.1",
        "port": "9443",
        "crt": "/TestProxy/target/debug/server.crt",
        "key": "/TestProxy/target/debug/server.key",
        "cipher_list": "HIGH",
        "no_tls12": "no",
        "min_proto_version": "tls12",
        "compression": "yes"
      }
    }
  },
  "tests": {
    "1": {
      "comment": "Configures ssl cert, proto, cipher_list correctly",
      "states": {
        "1": {
          "testend": "client",
          "cmd": "send",
          "payload": "GET / HTTP/1.1\r\nHost: comixwall.org\r\n\r\n",
          "assert": {
            "current_cipher_name": {
              "match": [
                "^DHE-\\w+-\\w+-\\w+",
                "\\w+-\\w+-SEED-\\w+",
                "\\w+-\\w+-\\w+-SHA$"
              ],
              "!match": [
                "ECDHE-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+",
                "[A-Z0-9]+-[A-Z0-9]+-AES256-[A-Z0-9]+-[A-Z0-9]+",
                "[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-SHA384"
              ]
            },
            "current_cipher_version": {
              "==": [
                "SSLv3",
                "TLSv1"
              ],
              "!match": [
                "^TLSv1\\.[1-3]?$"
              ]
            },
            "ssl_proto_version": {
              "==": [
                "TLSv1"
              ],
              "!=": [
                "SSLv3"
              ],
              "!match": [
                "^TLSv1\\.[1-3]?$"
              ]
            },
            "ssl_state": {
              "==": [
                "SSLOK "
              ]
            },
            "peer_certificate": {
              "==": [
                "TR, Antalya, Serik, ComixWall, SSLproxy, comixwall.org, [email protected]"
              ]
            },
            "peer_certificate_not_before": {
              ">=": [
                "-2"
              ],
              "<=": [
                "0"
              ]
            },
            "peer_certificate_not_after": {
              ">=": [
                "363"
              ],
              "<=": [
                "365"
              ]
            }
          }
        },
        "2": {
          "testend": "server",
          "cmd": "recv",
          "payload": "GET / HTTP/1.1\r\nHost: comixwall.org\r\nConnection: close\r\n\r\n",
          "assert": {
            "current_cipher_name": {
              "match": [
                "ECDHE-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+",
                "[A-Z0-9]+-[A-Z0-9]+-AES256-[A-Z0-9]+-[A-Z0-9]+",
                "[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-SHA384"
              ],
              "!match": [
                "^DHE-\\w+-\\w+-\\w+",
                "\\w+-\\w+-SEED-\\w+",
                "\\w+-\\w+-\\w+-SHA$"
              ]
            },
            "current_cipher_version": {
              "==": [
                "TLSv1.2"
              ],
              "!match": [
                "^(SSLv3|TLSv1|TLSv1\\.[13]?)$"
              ]
            },
            "ssl_proto_version": {
              "==": [
                "TLSv1.2"
              ],
              "!match": [
                "^(SSLv3|TLSv1|TLSv1\\.[13]?)$"
              ]
            },
            "ssl_state": {
              "==": [
                "SSLOK "
              ]
            },
            "sni_servername": {
              "==": [
                "comixwall.org"
              ]
            }
          }
        }
      }
    }
  }
}

This is how i start the sslproxy

sudo sslproxy -D4 -k /SSLproxy/server.key -c /SSLproxy/server.crt -l connect.log -J -S /SSLproxy/log -Y /SSLproxy/pcap ssl 127.0.0.1 8443 up:1212
for the lp i you use that on in the test dir.

At least the output of the proxy says that it has received something.

EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]
EOF on outbound connection before connection establishment
SSL_free() in state 0000000c = 000c = TWCH (SSLv3/TLS write client hello) [connect socket]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.