Discovered tokio::io::util::copy_bidirectional() during the M1 plain TCP phase, that creates a TCP pipeline and read/write between TCP/proxy
Feature idea: pluggable protocol dissector for Rustler: user supplies protocol spec, proxy parses and intercepts matching traffic. Got the idea reading Stevens TCP/IP ch.1
Replaced copy_bidirectional with manual tokio::select! loop and forward() helper. Connection handling is now explicit: read, match, write, break on error or Ok(0).
TLS ClientHello mapped to be parsed in Rustler, the Extension Server Name (SNI) is the part I need, I have to skim all the bytes before that using different length hint and fixed size part of the ClientHello request; sources https://tls13.xargs.org
I've mapped Rust rcgen to RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate
Revocation List (CRL). As I use a self-signed certificates I have to modify some fields: a proper validity
"notBefore" and "notAfter", must be set up and issuer should have a relativeDistinguishedName. Another specific part
is related to the extension field in rcgen CertificateParams: params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
and equivalent to Certificate-> tbsCertificate-> extensions-> Extension-> BasicConstraint-> isCa (BOOL) AND
pathLenConstraint absent (that's equivalent to unconstrained). RFC in parallel of rcgen are mandatory due to the
vague documentation of the structure.
I first had to bring some architecture to the project. That should have been the first step for that project, but I had started with a throwaway draft. Refactoring brought new data struct for Proxy and Connection. I also had to temporary divide the path depending on the signal HTTP or HTTPS. Given that other protocols exist beyond HTTP/HTTPS over FTP, I only handle HTTP and HTTPS for now. The problem was that using directly a classic buffer ([u8; n]) doubled the read/write calls due to the architecture. Then it was short-circuiting the pipe() function job, overwriting the buffer. Implementing BufRead for the CONNECT call allowed me to seek the CONNECT bytes, act properly and that without triggering an additional read outside the forward pipeline.
TLS acceptors and TLS connectors with rustls, tokiorustls and pki_types brings a lot of new custom types related to Cert, PEM and DER which are not well documented the first time someone is confronted to that and ask for a bit of experimentation. Moreover, some stuff might be deprecated for example as cargo deny flagged that rustls-pemfile was not maintained anymore and was just a wrapped over rustls-pki-types PemObject and asked for a switch. switched to rustls-pki-types::PemObject with CertificateDer::from_pem_slice()
Refacto: even if that's a TLS proxy we only do HTTP and HTTPS for demo purpose but, I don't have time yet to handle multiple protocol, that would need a totally different architecture. The ideal abstraction for a protocol handler registry would be something like Box. Refactor here keep a C-style architecture with imperative function call; not that much "OOP" style or anything else.
Cursor and Writer parsing, used for DNS and soon CLientHello DNS message building following RFC 1035: STD 13: Domain names, implementation and specification, the part that bring difficulties was stacked entries in the question or the record name,type,class Filtering to 1.1.1.1, Cloudflare