srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile59
-rw-r--r--README.md47
-rw-r--r--cmd/mitmux/main.go7
-rw-r--r--cmd/mitmuxd/main.go7
-rw-r--r--internal/version/version.go30
-rw-r--r--internal/version/version_test.go32
7 files changed, 179 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 1915ed4..12694fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/bin/
+/dist/
*.pem
*.db
*.db-wal
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..58f2f3f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,59 @@
+# mitmux build automation. Plain `make` builds both binaries for the
+# current platform into bin/; `make release` cross-compiles every
+# binary for every platform in PLATFORMS into dist/. Every target here
+# is CGO_ENABLED=0 - modernc.org/sqlite is pure Go, so no C toolchain
+# is needed on any platform, cross-compiling included.
+
+BIN_DIR := bin
+DIST_DIR := dist
+
+VERSION := $(shell git describe --tags --dirty --always 2>/dev/null || echo dev)
+COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
+DATE := $(shell date -u +%Y-%m-%d)
+LDFLAGS := -X mitmux/internal/version.Version=$(VERSION) -X mitmux/internal/version.Commit=$(COMMIT) -X mitmux/internal/version.Date=$(DATE)
+
+# darwin/amd64 and freebsd/amd64 cross-compile and pass `go vet` cleanly
+# (verified) but, unlike linux/amd64, have not been run on real hardware
+# - see README's Platforms section.
+PLATFORMS := linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 freebsd/amd64
+
+.PHONY: all build test check clean release install
+
+all: build
+
+build:
+ mkdir -p $(BIN_DIR)
+ CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BIN_DIR)/mitmuxd ./cmd/mitmuxd
+ CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BIN_DIR)/mitmux ./cmd/mitmux
+
+# Same checks expected before every commit in this repo - see PLAN.md.
+test:
+ go build ./...
+ go vet ./...
+ test -z "$$(gofmt -l .)"
+ go test ./...
+
+check: test
+
+clean:
+ rm -rf $(BIN_DIR) $(DIST_DIR)
+
+install:
+ go install -ldflags "$(LDFLAGS)" ./cmd/mitmuxd
+ go install -ldflags "$(LDFLAGS)" ./cmd/mitmux
+
+# Cross-compiles both binaries for every platform in PLATFORMS into
+# dist/mitmux-<os>-<arch>/.
+release:
+ @for p in $(PLATFORMS); do \
+ os=$$(echo $$p | cut -d/ -f1); \
+ arch=$$(echo $$p | cut -d/ -f2); \
+ out=$(DIST_DIR)/mitmux-$$os-$$arch; \
+ ext=""; \
+ if [ "$$os" = "windows" ]; then ext=".exe"; fi; \
+ mkdir -p $$out; \
+ echo "building $$os/$$arch..."; \
+ CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -ldflags "$(LDFLAGS)" -o $$out/mitmuxd$$ext ./cmd/mitmuxd || exit 1; \
+ CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -ldflags "$(LDFLAGS)" -o $$out/mitmux$$ext ./cmd/mitmux || exit 1; \
+ done
+ @echo "release binaries in $(DIST_DIR)/"
diff --git a/README.md b/README.md
index 4a9def0..7173984 100644
--- a/README.md
+++ b/README.md
@@ -69,20 +69,57 @@ list of what's deliberately not implemented (and why), see
## Install / build
-Requires Go 1.26.5+ (see `go.mod`).
+Requires Go 1.26.5+ (see `go.mod`). No other dependencies - the SQLite
+driver ([modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite)) is
+pure Go, so there's no C toolchain to install and nothing to link
+against, on any platform.
```sh
git clone <this repo>
cd mitmux
+make build # -> bin/mitmuxd, bin/mitmux
+```
+
+`make build` covers the common case; see the [`Makefile`](Makefile)
+itself for the rest - `make install` (via `go install`, respecting
+`GOBIN`/`GOPATH` as usual), `make release` (cross-compiles both
+binaries for every platform in `PLATFORMS` into `dist/`), `make test`
+(the same build/vet/gofmt/test checks expected before every commit -
+see `PLAN.md`). Building without `make` works identically:
+
+```sh
go build -o bin/mitmuxd ./cmd/mitmuxd
go build -o bin/mitmux ./cmd/mitmux
```
+### Platforms
+
+Linux is the primary target and the only one this has actually run on
+during development - every feature in this document was verified live
+against a real daemon and real traffic there. macOS, Windows, and
+FreeBSD all cross-compile cleanly with `CGO_ENABLED=0` and pass `go
+vet` (`make release` builds all of them), and the code itself has
+nothing Linux-specific in it - CA/history storage uses Go's own
+cross-platform `os.UserConfigDir()`, not a hardcoded XDG path - but
+they haven't been run on real hardware, so treat them as "should work,
+not yet verified" rather than a tested claim. If you try one and hit
+something, that's useful to know about.
+
+One concrete thing worth knowing on macOS specifically: its Unix
+domain socket path limit is shorter than Linux's, and the default
+control-socket location lives under `~/Library/Application
+Support/mitmux/` - a deeper path than Linux's usual
+`$XDG_RUNTIME_DIR`. A long username or home directory path could push
+past the limit; if `mitmuxd` fails to bind its control socket, pass a
+shorter `-socket /tmp/mitmux.sock` (and the matching `-socket` to
+`mitmux`) to both binaries.
+
## Quick start
1. **Start the daemon.** By default it listens on `127.0.0.1:8080` and
- stores its CA and history database under `~/.config/mitmux` (XDG
- config dir):
+ stores its CA and history database under your OS's standard config
+ directory (Linux: `~/.config/mitmux`, macOS: `~/Library/Application
+ Support/mitmux`, Windows: `%AppData%\mitmux`):
```sh
./bin/mitmuxd
@@ -124,7 +161,9 @@ go build -o bin/mitmux ./cmd/mitmux
Both binaries take flags for non-default setups - `-listen`, `-socket`,
`-ca-dir`, `-db`, `-upstream-proxy` on `mitmuxd`; `-socket` on `mitmux`.
-Run either with `-h` for the full list.
+Both also take `-version` (prints version/commit/date and exits - `dev`
+for a plain `go build`; `make build`/`make release` fill it in from
+`git describe`) and `-h` for the full list.
`-listen` takes a comma-separated list to bind more than one address
(`-listen "127.0.0.1:8080,127.0.0.1:8081"`) - one logical proxy on
diff --git a/cmd/mitmux/main.go b/cmd/mitmux/main.go
index 7ffe9b9..c9563fe 100644
--- a/cmd/mitmux/main.go
+++ b/cmd/mitmux/main.go
@@ -23,6 +23,7 @@ import (
"mitmux/internal/rules"
"mitmux/internal/scope"
"mitmux/internal/store"
+ "mitmux/internal/version"
)
func defaultSocketPath() string {
@@ -38,8 +39,14 @@ func defaultSocketPath() string {
func main() {
socketPath := flag.String("socket", "", "daemon control socket path (default: $XDG_RUNTIME_DIR/mitmux.sock, else <ca-dir>/mitmux.sock)")
+ showVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
+ if *showVersion {
+ fmt.Println(version.String("mitmux"))
+ return
+ }
+
path := *socketPath
if path == "" {
path = defaultSocketPath()
diff --git a/cmd/mitmuxd/main.go b/cmd/mitmuxd/main.go
index baaba85..0114871 100644
--- a/cmd/mitmuxd/main.go
+++ b/cmd/mitmuxd/main.go
@@ -22,6 +22,7 @@ import (
"mitmux/internal/ipc"
"mitmux/internal/proxy"
"mitmux/internal/store"
+ "mitmux/internal/version"
)
func main() {
@@ -31,8 +32,14 @@ func main() {
socketPath := flag.String("socket", "", "control socket path (default: $XDG_RUNTIME_DIR/mitmux.sock, else <ca-dir>/mitmux.sock)")
installCA := flag.Bool("install-ca", false, "generate the CA if needed, print OS-specific trust-store install steps, and exit (doesn't start the proxy)")
upstreamProxy := flag.String("upstream-proxy", "", "chain all outbound connections through this HTTP CONNECT proxy (host:port, optional http:// prefix) instead of dialing origins directly")
+ showVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
+ if *showVersion {
+ fmt.Println(version.String("mitmuxd"))
+ return
+ }
+
var listenAddrs []string
for _, a := range strings.Split(*listen, ",") {
if a = strings.TrimSpace(a); a != "" {
diff --git a/internal/version/version.go b/internal/version/version.go
new file mode 100644
index 0000000..030bd4e
--- /dev/null
+++ b/internal/version/version.go
@@ -0,0 +1,30 @@
+// Package version holds build-time version information for both
+// binaries, set via -ldflags "-X mitmux/internal/version.Version=..."
+// (see the Makefile's release target). Defaults to "dev" for a plain
+// `go build` with no ldflags, so `-version` is never blank or
+// misleading about whether a given binary is a tagged release or a
+// local build.
+package version
+
+var (
+ Version = "dev"
+ Commit = ""
+ Date = ""
+)
+
+// String returns a one-line version summary for component ("mitmux" or
+// "mitmuxd"): "mitmux dev" for an untagged build, or
+// "mitmux 1.2.3 (abc1234, 2026-01-02)" once Commit/Date are set.
+func String(component string) string {
+ s := component + " " + Version
+ if Commit != "" || Date != "" {
+ s += " ("
+ s += Commit
+ if Commit != "" && Date != "" {
+ s += ", "
+ }
+ s += Date
+ s += ")"
+ }
+ return s
+}
diff --git a/internal/version/version_test.go b/internal/version/version_test.go
new file mode 100644
index 0000000..d2d501b
--- /dev/null
+++ b/internal/version/version_test.go
@@ -0,0 +1,32 @@
+package version
+
+import "testing"
+
+func TestStringDefault(t *testing.T) {
+ orig := Version
+ Version, Commit, Date = "dev", "", ""
+ defer func() { Version = orig }()
+ if got := String("mitmux"); got != "mitmux dev" {
+ t.Errorf("String(%q) = %q, want %q", "mitmux", got, "mitmux dev")
+ }
+}
+
+func TestStringWithCommitAndDate(t *testing.T) {
+ origV, origC, origD := Version, Commit, Date
+ Version, Commit, Date = "1.2.3", "abc1234", "2026-01-02"
+ defer func() { Version, Commit, Date = origV, origC, origD }()
+ want := "mitmuxd 1.2.3 (abc1234, 2026-01-02)"
+ if got := String("mitmuxd"); got != want {
+ t.Errorf("String(%q) = %q, want %q", "mitmuxd", got, want)
+ }
+}
+
+func TestStringCommitOnly(t *testing.T) {
+ origV, origC, origD := Version, Commit, Date
+ Version, Commit, Date = "1.2.3", "abc1234", ""
+ defer func() { Version, Commit, Date = origV, origC, origD }()
+ want := "mitmux 1.2.3 (abc1234)"
+ if got := String("mitmux"); got != want {
+ t.Errorf("String(%q) = %q, want %q", "mitmux", got, want)
+ }
+}