{"id":51029067,"url":"https://github.com/digital-shokunin/crabbyproxy","last_synced_at":"2026-06-21T22:30:29.133Z","repository":{"id":354944967,"uuid":"1226149895","full_name":"digital-shokunin/crabbyproxy","owner":"digital-shokunin","description":"Lightweight Rust SOCKS5 proxy that binds outgoing connections to a specific network interface (IP_BOUND_IF), enabling domain-based split tunneling where IP-based routing falls short (e.g., WireGuard on macOS).","archived":false,"fork":false,"pushed_at":"2026-05-01T03:33:16.000Z","size":11,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T05:13:10.756Z","etag":null,"topics":["dns-over-https","macos","network-extension","pac-file","proxy","rust","rust-lang","socks5-proxy","split-tunneling","vpn","wireguard"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/digital-shokunin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T03:06:48.000Z","updated_at":"2026-05-01T04:06:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/digital-shokunin/crabbyproxy","commit_stats":null,"previous_names":["digital-shokunin/crabbyproxy"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/digital-shokunin/crabbyproxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digital-shokunin%2Fcrabbyproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digital-shokunin%2Fcrabbyproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digital-shokunin%2Fcrabbyproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digital-shokunin%2Fcrabbyproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/digital-shokunin","download_url":"https://codeload.github.com/digital-shokunin/crabbyproxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/digital-shokunin%2Fcrabbyproxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34628453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dns-over-https","macos","network-extension","pac-file","proxy","rust","rust-lang","socks5-proxy","split-tunneling","vpn","wireguard"],"created_at":"2026-06-21T22:30:28.614Z","updated_at":"2026-06-21T22:30:29.124Z","avatar_url":"https://github.com/digital-shokunin.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# crabbyproxy 🦀\n\n\u003e Named for [Ferris](https://rustacean.net/), Rust's unofficial crab mascot.\n\nLightweight Rust SOCKS5 proxy that binds outgoing connections to a specific network interface via macOS `IP_BOUND_IF`, enabling domain-based split tunneling where IP-based routing falls short.\n\nBuilt for WireGuard on macOS, where the Network Extension intercepts all packets before the routing table — making traditional split tunneling (`AllowedIPs`, `route add`) unreliable for domain-based exclusions.\n\n## Why?\n\nWhen running a VPN for security testing, bug bounty, or general privacy, certain sites block or restrict traffic from known VPN/datacenter IP ranges (CAPTCHAs, bot checks, degraded service). For sites like YouTube or Reddit, anonymization isn't a priority — and it may actually be preferable to keep personal traffic off VPN IPs that are associated with security testing. crabbyproxy lets you selectively route specific domains through your home connection while keeping everything else tunneled.\n\n## How it works\n\n![crabbyproxy traffic flow](diagram.png)\n\n1. Browser PAC file routes target domains to the local SOCKS5 proxy\n2. Proxy resolves DNS via DoH — bypasses VPN DNS, gets geo-correct CDN IPs\n3. Proxy binds outgoing sockets to the physical interface (`IP_BOUND_IF`)\n4. macOS honors the binding even with VPN active — traffic goes direct\n5. All other traffic goes through the VPN as normal\n\n## Features\n\n- **Domain-based split tunneling** — route by domain, not IP ranges\n- **DNS-over-HTTPS** — Cloudflare, Google, and Quad9 with automatic fallback\n- **TTL-aware DNS cache** — minimal DoH queries\n- **Interface auto-detection** — finds en0/en6/en1 automatically\n- **Zero config WireGuard** — no AllowedIPs changes, no PostUp/PostDown\n- **PAC file HTTP server** — serves proxy.pac over HTTP on port 1081 (Chrome compatible)\n- **WireGuard watcher** — detects when WireGuard becomes active, injects PAC into SCDynamicStore so Chrome picks it up automatically\n- **LaunchAgent** — starts at login, auto-restarts on crash\n- **~2MB binary** — async Rust with tokio\n\n## Install\n\n### From source\n\n```bash\ngit clone https://github.com/digital-shokunin/crabbyproxy.git\ncd crabbyproxy\n./install.sh\n```\n\nThis builds the binary, installs it to `~/.local/bin/`, sets up default configs, and starts the LaunchAgent.\n\n### Manual\n\n```bash\ncargo build --release\ncp target/release/crabbyproxy ~/.local/bin/\nmkdir -p ~/.config/crabbyproxy\ncp doh.conf.default ~/.config/crabbyproxy/doh.conf\ncp proxy.pac ~/.config/crabbyproxy/proxy.pac\ncp com.digisho.crabbyproxy.plist ~/Library/LaunchAgents/\nlaunchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.digisho.crabbyproxy.plist\n```\n\n## Browser setup\n\nSet `http://127.0.0.1:1081/proxy.pac` as the automatic proxy configuration URL in every browser:\n\n- **Firefox**: Settings \u003e Network Settings \u003e Automatic proxy configuration URL\n- **Chrome/Safari**: System Settings \u003e Network \u003e Wi-Fi \u003e Details \u003e Proxies \u003e Automatic Proxy Configuration\n\nWhen WireGuard is active, crabbyproxy automatically injects the PAC URL into the system network state (SCDynamicStore) so Chrome/Safari pick it up without any manual configuration.\n\n## Configuration\n\nAll settings live in `~/.config/crabbyproxy/config.toml`:\n\n```toml\n[doh]\nservers = [\n    \"https://1.1.1.1/dns-query\",      # Cloudflare\n    \"https://8.8.8.8/dns-query\",      # Google\n    \"https://9.9.9.9:5053/dns-query\", # Quad9\n]\n\n[proxy]\nsocks_port = 1080\npac_port = 1081\ndomains = [\n    \"*.youtube.com\",\n    \"youtube.com\",\n    \"*.example.com\",  # add your domains here\n]\n```\n\nThe PAC file is generated in memory from the `domains` list — no separate `proxy.pac` needed.\n\nRestart after changes: `launchctl kickstart -k gui/$(id -u)/com.digisho.crabbyproxy`\n\n## Why not just use AllowedIPs?\n\nWireGuard's `AllowedIPs` is IP-based, not domain-based. Services like YouTube use thousands of dynamic CDN IPs across dozens of subnets. Excluding them all creates hundreds of CIDR ranges that can break the tunnel. The macOS WireGuard app's Network Extension also intercepts packets before the routing table, making `route add` commands ineffective.\n\ncrabbyproxy operates at the application layer (browser proxy) instead of the network layer, sidestepping these limitations entirely.\n\n## Uninstall\n\n```bash\nlaunchctl bootout gui/$(id -u)/com.digisho.crabbyproxy\nrm ~/.local/bin/crabbyproxy\nrm ~/Library/LaunchAgents/com.digisho.crabbyproxy.plist\nrm -rf ~/.config/crabbyproxy\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigital-shokunin%2Fcrabbyproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdigital-shokunin%2Fcrabbyproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdigital-shokunin%2Fcrabbyproxy/lists"}