{"id":13576543,"url":"https://github.com/cloudflare/mmproxy","last_synced_at":"2025-04-09T05:10:25.093Z","repository":{"id":31924403,"uuid":"129813334","full_name":"cloudflare/mmproxy","owner":"cloudflare","description":"mmproxy, the magical PROXY protocol gateway","archived":false,"fork":false,"pushed_at":"2024-09-25T22:37:35.000Z","size":34,"stargazers_count":468,"open_issues_count":17,"forks_count":55,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-04-02T04:03:31.872Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudflare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-BSD-CloudFlare","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}},"created_at":"2018-04-16T22:26:02.000Z","updated_at":"2025-03-21T00:02:55.000Z","dependencies_parsed_at":"2024-01-07T22:44:58.695Z","dependency_job_id":"57475d34-ad79-429a-a390-2cac5b349fb1","html_url":"https://github.com/cloudflare/mmproxy","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fmmproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fmmproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fmmproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fmmproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudflare","download_url":"https://codeload.github.com/cloudflare/mmproxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980837,"owners_count":21027808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-08-01T15:01:11.258Z","updated_at":"2025-04-09T05:10:25.075Z","avatar_url":"https://github.com/cloudflare.png","language":"C","funding_links":[],"categories":["C","\u003ca id=\"d03d494700077f6a65092985c06bf8e8\"\u003e\u003c/a\u003e工具","Networking \u0026 Performance"],"sub_categories":["\u003ca id=\"0ff94312f3ab4898f5996725133ea9d1\"\u003e\u003c/a\u003e未分类","Tunneling \u0026 Proxies"],"readme":"MMPROXY\n-------\n\nmmproxy is a lightweight TCP proxy that serves exactly one purpose:\nto smooth the transition of TCP servers to use proxy-protocol.\n\nUsually, introducing TCP level load balancing introduces a significant\nproblem - the client source IP gets lost. From the application point\nof view the inbound TCP connection is originated by load-balancer, not\nthe real client.\n\nProxy-protocol is an invention from Haproxy, that aims to solve this:\n\n  - https://www.haproxy.com/blog/haproxy/proxy-protocol/\n\nProxy-protocol defines an exchange in which the first bytes\ntransmitted from the load balancer will describe the Client Source\nIP. This is great, but applications must explicitly support\nproxy-protocol to use it.\n\nFor many mature applications introducing proxy-protocol support is\nhard. \"mmproxy\" is a workaround to help in this case.\n\nmmproxy sits near the application, receives the proxy-protocol enabled\nconnections from the load balancer, spoofs the client IP addresses,\nand sends traffic directly to the application. From application point\nof view the traffic look identically like it would have originated\nfrom the remote client.\n\n\nNomenclature\n------------\n\nIn normal case the TCP client directly connects to application:\n\n    Client --\u003e Application\n\nHere, application can use Client IP directly, without any\nproblem. Introducing proxy-protocol TCP load balancer breaks it\nthough. In such architecture application must support proxy-protocol:\n\n    Client --\u003e PP-enabled Load Balancer --\u003e PP-enabled Application\n\nmmproxy can remove the need of supporting proxy-protocol directly on\nthe TCP application:\n\n    Client --\u003e PP-enabled Load Balancer --\u003e mmproxy --\u003e Application\n\nIt's worth emphasizing that the traffic in last link (mmproxy --\u003e\nApplication) will be source IP spoofed and MUST be delivered over\nloopback.  In effect - mmproxy MUST run on the same machine as the\napplication.\n\nRequirements\n------------\n\nmmproxy requires:\n\n  - To be run on the very server which runs the\n    application. Communication between mmproxy and the application\n    must happen over loopback interface.\n  - Root permissions. Alternatively - `CAP_NET_ADMIN` capability.\n  - Linux Kernel at least 2.6.28.\n  - Relatively unsophisticated iptables / routing setup.\n\nHow mmproxy works?\n------------------\n\nmmproxy uses two tricks to perform the source IP spoofing. First, it\nuses an obscure Linux `IP_TRANSPARENT` socket option.  Originally was\ndesigned to help building transparent proxies with Linux. We reuse\nthis feature to spoof source IPs. With it we can create sockets that\nwill send from arbitrary IP addresses.\n\nSecond, we must fix the outbound routing. By default Linux will route\nthe response packets to the default route (internet). To work around\nwe deploy a custom routing table, which forces the return traffic to\nbe routed to loopback.\n\n1) If traffic is forwarded to the \"lo\" interface (127.0.0.1 / ::1 for example):\n\n       # 1. Route packets from lo address and lo interface to table 100\n       ip -4 rule add from 127.0.0.1/8 iif lo table 100\n       ip -6 rule add from ::1/128 iif lo table 100\n\n       # 2. In routing table=100 treat all IP addresses as bound to\n       # loopback, and pass them to network stack for processing:\n       ip route add local 0.0.0.0/0 dev lo table 100\n       ip -6 route add local ::/0 dev lo table 100\n\n2) Or, if traffic is forwarded to any other interface:\n\n       # 1. Check if you have a default route for ipv4 / ipv6\n       # if you don't have any default route response will be dropped before #4 \u0026 #5\n\n       # 2. Enable route_localnet on your default interface\n       # substitute \"eth0\" in the path below, if needed\n       echo 1 \u003e /proc/sys/net/ipv4/conf/eth0/route_localnet\n\n       # 3. Save conntrack CONNMARK on packets sent with MARK 123.\n       iptables -t mangle -I PREROUTING -m mark --mark 123 -m comment --comment mmproxy -j CONNMARK --save-mark\n       ip6tables -t mangle -I PREROUTING -m mark --mark 123 -m comment --comment mmproxy -j CONNMARK --save-mark\n\n       # 4. Restore MARK on packets belonging to connections with conntrack CONNMARK 123.\n       iptables -t mangle -I OUTPUT -m connmark --mark 123 -m comment --comment mmproxy -j CONNMARK --restore-mark\n       ip6tables -t mangle -I OUTPUT -m connmark --mark 123 -m comment --comment mmproxy -j CONNMARK --restore-mark\n\n       # 5. Route packets with MARK 123 to routing table 100\n       ip rule add fwmark 123 lookup 100\n       ip -6 rule add fwmark 123 lookup 100\n\n       # 6. In routing table=100 treat all IP addresses as bound to\n       # loopback, and pass them to network stack for processing:\n       ip route add local 0.0.0.0/0 dev lo table 100\n       ip -6 route add local ::/0 dev lo table 100\n\n\nDevelopment\n-----------\n\n\n    git clone https://github.com/cloudflare/mmproxy.git\n    cd mmproxy\n    git submodule update --init\n    make\n\n\nUsage\n-----\n\nHelp message:\n\n```\n./mmproxy  --help\nUsage:\n\n    mmproxy [ options ] --allowed-subnets FILE -l LISTEN_ADDR -4 TARGET_V4_ADDR -6 TARGET_V6_ADDR\n\nmmproxy binds to given TCP LISTEN_ADDR (default [::]:8080) and accepts\ninbound TCP connections. The inbound connections MUST have a proxy-protocol\nversion 1 header, and MUST be originated from set of given source IP's.\nThe traffic will be magically spoofed to look like it came from real client IP.\n LISTEN_ADDR      Address to bind to. In form like [::]:8080\n TARGET_ADDR      Address to forward traffic to. In form like [::]:80\n --allowed-subnets FILE Load allowed IP subnets from given file.\n --mark MARK      Set specific MARK on outbound packets. Needed to play with iptables.\n --table TABLE    Use specific routing table number in printed suggestion\n. --quiet          Don't print the iptables, routing and system tuning suggestions.\n --verbose        Print detailed logs on stdout.\n\nThis runs mmproxy on port 2222, unpacks the proxy-protocol header\nand forwards the traffic to 127.0.0.1:22 on TCP:\n\n    echo -en \"0.0.0.0/0\\n::/0\\n\" \u003e allowed-networks.txt\n    mmproxy --allowed-networks allowed-networks.txt -l 0.0.0.0:2222 -4 127.0.0.1:22 -6 [::1]:22\n```\n\nExample run:\n```\n$ curl -s https://www.cloudflare.com/ips-v4 https://www.cloudflare.com/ips-v6 \u003e networks.txt\n$ sudo mmproxy -a networks.txt -l 0.0.0.0:2222 -4 127.0.0.1:22 -6 '[::1]:22'\n[ ] Remember to set the reverse routing rules correctly:\niptables -t mangle -I PREROUTING -m mark --mark 123 -m comment --comment mmproxy -j CONNMARK --save-mark        # [+] VERIFIED\niptables -t mangle -I OUTPUT -m connmark --mark 123 -m comment --comment mmproxy -j CONNMARK --restore-mark     # [+] VERIFIED\nip6tables -t mangle -I PREROUTING -m mark --mark 123 -m comment --comment mmproxy -j CONNMARK --save-mark       # [+] VERIFIED\nip6tables -t mangle -I OUTPUT -m connmark --mark 123 -m comment --comment mmproxy -j CONNMARK --restore-mark    # [+] VERIFIED\nip rule add fwmark 123 lookup 100               # [+] VERIFIED\nip route add local 0.0.0.0/0 dev lo table 100   # [+] VERIFIED\nip -6 rule add fwmark 123 lookup 100            # [+] VERIFIED\nip -6 route add local ::/0 dev lo table 100     # [+] VERIFIED\n[+] OK. Routing to 127.0.0.1 points to a local machine.\n[+] OK. Target server 127.0.0.1:22 is up and reachable using conventional connection.\n[+] OK. Target server 127.0.0.1:22 is up and reachable using spoofed connection.\n[+] OK. Routing to ::1 points to a local machine.\n[+] OK. Target server [::1]:22 is up and reachable using conventional connection.\n[+] OK. Target server [::1]:22 is up and reachable using spoofed connection.\n[+] Listening on 0.0.0.0:2222\n```\n\nThen you can locally test it with:\n\n```\n$ echo -en \"PROXY TCP4 1.2.3.4 1.2.3.4 11 11\\r\\nHello World!\" | nc -q3 -v 127.0.0.1 2222\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fmmproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudflare%2Fmmproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fmmproxy/lists"}