2026-03-17 02:56:24 -07:00
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
2026-03-25 13:15:51 -07:00
mc-proxy is a TLS proxy and router for Metacircular Dynamics services. It operates in two per-route modes: **L4 passthrough** (reads SNI, proxies raw TCP without terminating TLS) and **L7 terminating** (terminates TLS, reverse proxies HTTP/2 and HTTP/1.1 traffic including gRPC). A global firewall (IP, CIDR, GeoIP, rate limiting) is evaluated before routing. PROXY protocol support enables multi-hop deployments preserving real client IPs. See `ARCHITECTURE.md` for full design.
2026-03-17 02:56:24 -07:00
## Build Commands
```bash
make all # vet → lint → test → build
make mc-proxy # build the binary with version injection
make build # compile all packages
make test # run all tests
make vet # go vet
make lint # golangci-lint
2026-03-17 03:10:04 -07:00
make proto # regenerate gRPC code from proto definitions
make devserver # build and run locally with srv/mc-proxy.toml
2026-03-17 02:56:24 -07:00
```
Run a single test:
```bash
go test ./internal/sni -run TestExtract
```
## Architecture
2026-03-27 02:05:59 -07:00
- **Module path**: `git.wntrmute.dev/mc/mc-proxy`
2026-03-17 02:56:24 -07:00
- **Go with CGO_ENABLED=0**, statically linked, Alpine containers
2026-03-25 13:15:51 -07:00
- **Dual mode, per-route** — L4 (passthrough) and L7 (TLS-terminating HTTP/2 reverse proxy) coexist on the same listener
- **PROXY protocol** — listeners accept v1/v2; routes send v2. Enables edge→origin deployments over Tailscale
- **gRPC admin API** — manages routes and firewall rules at runtime; Unix socket only; optional (disabled if `[grpc]` section omitted from config)
2026-03-17 03:10:04 -07:00
- **No auth on proxy listeners** — this is pre-auth infrastructure; services behind it handle their own MCIAS auth
- **SQLite database** — persists listeners, routes, and firewall rules; pure-Go driver (`modernc.org/sqlite` ); seeded from TOML on first run, DB is source of truth thereafter
- **Write-through pattern** — gRPC mutations write to DB first, then update in-memory state
2026-03-17 02:56:24 -07:00
- **Config**: TOML via `go-toml/v2` , runtime data in `/srv/mc-proxy/`
- **Testing**: stdlib `testing` only, `t.TempDir()` for isolation
- **Linting**: golangci-lint v2 with `.golangci.yaml`
## Package Structure
- `internal/config/` — TOML config loading and validation
2026-03-17 03:10:04 -07:00
- `internal/db/` — SQLite database: migrations, CRUD for listeners/routes/firewall rules, seeding, snapshots
2026-03-17 02:56:24 -07:00
- `internal/sni/` — TLS ClientHello parser; extracts SNI hostname without consuming bytes
2026-03-25 13:15:51 -07:00
- `internal/firewall/` — global blocklist evaluation (IP, CIDR, GeoIP via MaxMind GeoLite2); rate limiting; thread-safe mutations and GeoIP reload
- `internal/proxy/` — L4 bidirectional TCP relay with half-close propagation and idle timeout
- `internal/proxyproto/` — PROXY protocol v1/v2 parser and v2 writer
- `internal/l7/` — L7 TLS termination, `prefixConn` , HTTP/2 reverse proxy with h2c backend transport
- `internal/server/` — orchestrates listeners → PROXY protocol → firewall → SNI → route → L4/L7 dispatch; per-listener state with connection tracking
2026-03-17 03:10:04 -07:00
- `internal/grpcserver/` — gRPC admin API: route/firewall CRUD, status, write-through to DB
2026-03-25 18:05:25 -07:00
- `internal/metrics/` — Prometheus metric definitions and HTTP server; optional `[metrics]` config section
2026-03-17 08:34:37 -07:00
- `proto/mc_proxy/v1/` — protobuf definitions; `gen/mc_proxy/v1/` has generated code
2026-03-17 02:56:24 -07:00
## Signals
- `SIGINT` /`SIGTERM` — graceful shutdown (drain in-flight connections up to `shutdown_timeout` )
- `SIGHUP` — reload GeoIP database without restart
## Critical Rules
2026-03-25 13:15:51 -07:00
- L4 routes never terminate TLS and never modify the byte stream.
- L7 routes terminate TLS at the proxy and reverse proxy HTTP/2 (including gRPC) to backends.
2026-03-17 02:56:24 -07:00
- Firewall rules are always evaluated before any routing decision.
2026-03-25 13:15:51 -07:00
- PROXY protocol is only parsed on explicitly enabled listeners.
2026-03-17 02:56:24 -07:00
- SNI matching is exact and case-insensitive.
- Blocked connections get a TCP RST — no error messages, no TLS alerts.
2026-03-17 03:10:04 -07:00
- Database writes must succeed before in-memory state is updated (write-through).