srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/mitmuxd
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-01-16 16:26:00 +0200
committersrdusr <[email protected]>2024-01-16 16:26:00 +0200
commit1125afc47b9d6e68d95d0ffdbb74514f4618e624 (patch)
tree63d5150b7dbc74685ebaec35ee0e74ec30c721d5 /cmd/mitmuxd
downloadmitmux-1125afc47b9d6e68d95d0ffdbb74514f4618e624.tar.gz
mitmux-1125afc47b9d6e68d95d0ffdbb74514f4618e624.zip
Scaffold mitmux: proxy daemon, CA generation, HTTP/CONNECT passthrough
Implements build-order step 1: headless proxy daemon (mitmuxd) with plaintext HTTP passthrough and raw CONNECT tunneling, plus root CA generation/persistence for later TLS interception. Verified live against real HTTP and HTTPS requests through the proxy.
Diffstat (limited to 'cmd/mitmuxd')
-rw-r--r--cmd/mitmuxd/main.go62
1 files changed, 62 insertions, 0 deletions
diff --git a/cmd/mitmuxd/main.go b/cmd/mitmuxd/main.go
new file mode 100644
index 0000000..400ca82
--- /dev/null
+++ b/cmd/mitmuxd/main.go
@@ -0,0 +1,62 @@
+// Command mitmuxd is the mitmux headless proxy daemon. It owns the
+// listening socket and (in later build steps) the traffic database; a
+// TUI or other client attaches separately without interrupting capture.
+package main
+
+import (
+ "context"
+ "flag"
+ "log"
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+
+ "mitmux/internal/ca"
+ "mitmux/internal/proxy"
+)
+
+func main() {
+ listen := flag.String("listen", "127.0.0.1:8080", "proxy listen address")
+ caDir := flag.String("ca-dir", "", "directory for CA cert/key (default: XDG config dir)")
+ flag.Parse()
+
+ dir := *caDir
+ if dir == "" {
+ d, err := ca.Dir()
+ if err != nil {
+ log.Fatalf("resolve CA dir: %v", err)
+ }
+ dir = d
+ }
+
+ root, err := ca.EnsureCA(dir)
+ if err != nil {
+ log.Fatalf("load CA: %v", err)
+ }
+ log.Printf("CA ready: %s", root.Cert.Subject.CommonName)
+
+ srv := proxy.New(*listen)
+
+ errCh := make(chan error, 1)
+ go func() {
+ errCh <- srv.ListenAndServe()
+ }()
+
+ sigCh := make(chan os.Signal, 1)
+ signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
+
+ select {
+ case err := <-errCh:
+ if err != nil {
+ log.Fatalf("proxy: %v", err)
+ }
+ case sig := <-sigCh:
+ log.Printf("received %s, shutting down", sig)
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ if err := srv.Shutdown(ctx); err != nil {
+ log.Fatalf("shutdown: %v", err)
+ }
+ }
+}