Kyle Isom 97909b7fbc Add L7 TLS-terminating HTTP/2 reverse proxy
New internal/l7 package implements TLS termination and HTTP/2 reverse
proxying for L7 routes. The proxy terminates the client TLS connection
using per-route certificates, then forwards HTTP/2 traffic to backends
over h2c (plaintext HTTP/2) or h2 (re-encrypted TLS).

PrefixConn replays the peeked ClientHello bytes into crypto/tls.Server
so the TLS handshake sees the complete ClientHello despite SNI
extraction having already read it.

Serve() is the L7 entry point: TLS handshake with route certificate,
ALPN negotiation (h2 preferred, HTTP/1.1 fallback), then HTTP reverse
proxy via httputil.ReverseProxy. Backend transport uses h2c by default
(AllowHTTP + plain TCP dial) or h2-over-TLS when backend_tls is set.

Forwarding headers (X-Forwarded-For, X-Forwarded-Proto, X-Real-IP)
are injected from the real client IP in the Rewrite function. PROXY
protocol v2 is sent to backends when send_proxy_protocol is enabled,
using the request context to carry the client address through the
HTTP/2 transport's dial function.

Server integration: handleConn dispatches to handleL7 when route.Mode
is "l7". The L7 handler converts RouteInfo to l7.RouteConfig and
delegates to l7.Serve.

L7 package tests: PrefixConn (4 tests), h2c backend round-trip,
forwarding header injection, backend unreachable (502), multiple
HTTP/2 requests over one connection.

Server integration tests: L7 route through full server pipeline with
TLS client, mixed L4+L7 routes on the same listener verifying both
paths work independently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:43:20 -07:00
2026-03-19 08:09:13 -07:00

mc-proxy

mc-proxy is a Layer 4 TLS SNI proxy and router for Metacircular Dynamics services. It reads the SNI hostname from incoming TLS ClientHello messages and proxies the raw TCP stream to the matched backend. It does not terminate TLS.

A global firewall (IP, CIDR, GeoIP country blocking) is evaluated before any routing decision. Blocked connections receive a TCP RST with no further information.

Quick Start

# Build
make mc-proxy

# Run locally (creates srv/ with example config on first run)
make devserver

# Full CI pipeline: vet → lint → test → build
make all

Configuration

Copy the example config and edit it:

cp mc-proxy.toml.example /srv/mc-proxy/mc-proxy.toml

See ARCHITECTURE.md for the full configuration reference.

Key sections:

  • [database] — SQLite database path (required)
  • [[listeners]] — TCP ports to bind and their route tables (seeds DB on first run)
  • [grpc] — optional gRPC admin API with TLS/mTLS
  • [firewall] — global blocklist (IP, CIDR, GeoIP country)
  • [proxy] — connect timeout, idle timeout, shutdown timeout

CLI Commands

Command Purpose
mc-proxy server -c <config> Start the proxy
mc-proxy status -c <config> Query a running instance's health via gRPC
mc-proxy snapshot -c <config> Create a database backup (VACUUM INTO)

Deployment

See RUNBOOK.md for operational procedures.

# Install on a Linux host
sudo deploy/scripts/install.sh

# Or build and run as a container
make docker
docker run -v /srv/mc-proxy:/srv/mc-proxy mc-proxy server -c /srv/mc-proxy/mc-proxy.toml

Design

mc-proxy intentionally omits a REST API and web frontend. The gRPC admin API is the sole management interface. This is an intentional departure from the Metacircular engineering standards — mc-proxy is pre-auth infrastructure and a minimal attack surface is prioritized over interface breadth.

See ARCHITECTURE.md for the full system specification.

License

Proprietary. Metacircular Dynamics.

Description
No description provided
Readme 101 MiB
Languages
Go 98.1%
Shell 1.2%
Makefile 0.4%
Nix 0.2%
Dockerfile 0.1%