{"id":27945030,"url":"https://github.com/cinit/udpfwd","last_synced_at":"2025-05-07T12:55:38.328Z","repository":{"id":204081113,"uuid":"710244045","full_name":"cinit/udpfwd","owner":"cinit","description":"Cloudflare-WARP WireGuard Relay","archived":false,"fork":false,"pushed_at":"2024-01-29T13:18:10.000Z","size":64,"stargazers_count":11,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-07T12:55:32.523Z","etag":null,"topics":["cloudflare","warp","wgcf","wireguard"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cinit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-10-26T10:03:13.000Z","updated_at":"2025-03-25T16:10:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"09ceaefc-e2a3-41f3-a0ac-3e9b136735ff","html_url":"https://github.com/cinit/udpfwd","commit_stats":null,"previous_names":["cinit/udpfwd"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinit%2Fudpfwd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinit%2Fudpfwd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinit%2Fudpfwd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinit%2Fudpfwd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cinit","download_url":"https://codeload.github.com/cinit/udpfwd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252882790,"owners_count":21819155,"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":["cloudflare","warp","wgcf","wireguard"],"created_at":"2025-05-07T12:55:37.719Z","updated_at":"2025-05-07T12:55:38.315Z","avatar_url":"https://github.com/cinit.png","language":"C++","readme":"# WARP-WireGuard Relay\n\n## Introduction\n\n[Cloudflare WARP](https://1.1.1.1/) adopts ECMP (Equal-Cost Multi-Path routing) as a load-balancing strategy to\nachieve high availability and high throughput. However, the ECMP strategy is not suitable for all scenarios. For\nexample, in the case of a single TCP connection, the ECMP strategy will cause the connection to be interrupted when the\nnetwork path changes, resulting in a poor user experience when you switch from Wi-Fi to a cellular network and vice\nversa.\n\nAlthough [this blog](https://blog.cloudflare.com/warp-technical-challenges/) says that Cloudflare has implemented a\nstrategy to avoid this problem, where servers in Cloudflare's data centers will act as a relay to ensure that the\ncorrect WireGuard packets will be forwarded to the correct server which owns the WireGuard session if a client id is\ncorrectly set in the reserved field of the WireGuard packet. However, as far as I have tested, this strategy does not\nwork. Therefore, I wrote this project to implement a WireGuard relay server to make my WARP connection more stable.\n\nThese ECMP routers in Cloudflare data center use a combination of (Source IP, Source Port, Destination IP, and\nDestination Port) to match a packet to a server. Since the destination IP and port for Cloudflare's WARP are always the\nsame, the relay server only needs to keep the source IP and source port stable to ensure that the packets from the same\nclient will be forwarded to the same server. In the case of a VPS, the source IP is stable, so the relay server only\nneeds to keep the source port stable for each client/session.\n\n## Implementation\n\nThis project works as a WireGuard relay server. It receives WireGuard packets from clients and forwards them to the\nserver. When receiving a packet from the client, the relay server will check the client ID (aka, the reserved field of\nthe WireGuard packet) to determine which session the packet belongs to. If the client ID is not set, the relay server\njust drops the packet, because both the sender and receiver field in a WireGuard packet are random and if an ephemeral\nkey expires, the handshake procedure starts again and the sender and receiver fields are reset to random values.\nTherefore, I don't think I can use the sender and receiver fields to determine which session the packet belongs to.\nIf the client ID is set, the relay server will check if the client ID is in the session table. If the client ID is in\nthe session table, the relay server updates the ip:port mapping in the session table and forwards the packet to the\nserver. If the client ID is not in the session table, the relay server will create a new session and pick a random port\nto forward the packet to the server. When receiving a packet from the server, the relay server will check the\ndestination port to determine which session the packet belongs to. If the destination port is in the session table, the\nrelay server will forward the packet to the client. If a session is inactive for more than 10 minutes, the relay server\nwill delete the session.\n\nThe relay server will neither try to decrypt the WireGuard packets nor try to modify the WireGuard packets. It just\nforwards the packets as they are. Therefore, the relay server does not need to know the public/private key pair of the\nclient or the server, nor does it need to know the pre-shared key. It's simply a UDP relay server.\n\n## Usage\n\n### Build\n\nThis project uses CMake as the build system. To build this project, you just need to run the following commands:\n\n```shell\nmkdir build \u0026\u0026 cd build\ncmake ..\nmake\n```\n\n### Run\n\nThrow the artifact udpfwd binary to your VPS, and run it with the following command:\n\n```shell\n./udpfwd -r [::]:2408 162.159.192.1:2408\n```\n\nIt doesn't need any privilege to run. Run it without any argument to see the usage.\n\nDon't forget to add a firewall rule to allow UDP traffic to the port you specified.\n\n## Note\n\nThis project is only compatible with WireGuard with a none-zero reserved field. If you want to forward other UDP\ntraffic,\nsee the usage for more details.\n\nIt's probably not a good idea to use this project on your VPS, because almost all VPS use IP addresses that are intended\nfor data centers, and these IP addresses are typically considered as \"bad/risky\". Therefore, it's very likely that you\nwill encounter a lot of CAPTCHAs (Cloudflare Turnstile) when you access websites through your relay server.\n\nEven the following command will trigger CAPTCHA:\n\n```shell\n# This is a public IP-echoing service.\ncurl ip.sb\n```\n\nIt fails with a 403 response:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en-US\"\u003e\n\u003chead\u003e\u003ctitle\u003eJust a moment...\u003c/title\u003e\n    \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"\u003e\n    \u003cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\"\u003e\n    \u003cmeta name=\"robots\" content=\"noindex,nofollow\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1\"\u003e\n    \u003clink href=\"/cdn-cgi/styles/challenges.css\" rel=\"stylesheet\"\u003e\n\u003c/head\u003e\n\u003cbody class=\"no-js\"\u003e\n\u003cdiv class=\"main-wrapper\" role=\"main\"\u003e\n    \u003cdiv class=\"main-content\"\u003e\n        \u003cnoscript\u003e\n            \u003cdiv id=\"challenge-error-title\"\u003e\n                \u003cdiv class=\"h2\"\u003e\u003cspan class=\"icon-wrapper\"\u003e\u003cdiv class=\"heading-icon warning-icon\"\u003e\u003c/div\u003e\u003c/span\u003e\u003cspan\n                        id=\"challenge-error-text\"\u003eEnable JavaScript and cookies to continue\u003c/span\u003e\u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/noscript\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n\u003cscript\u003e(function () {\n    window._cf_chl_opt = {\n        cvId: '2',\n        cZone: \"ip.sb\",\n        cType: 'managed',\n        cNounce: 'REDACTED',\n        cRay: 'REDACTED',\n        cHash: 'REDACTED',\n        // more...\n        cUPMDTk: \"\\/?__cf_chl_tk=REDACTED\"\n    };\n    var cpo = document.createElement('script');\n    cpo.src = '/cdn-cgi/challenge-platform/h/b/orchestrate/chl_page/v1?ray=REDACTED';\n    window._cf_chl_opt.cOgUHash = location.hash === '' \u0026\u0026 location.href.indexOf('#') !== -1 ? '#' : location.hash;\n    window._cf_chl_opt.cOgUQuery = location.search === '' \u0026\u0026 location.href.slice(0, location.href.length - window._cf_chl_opt.cOgUHash.length).indexOf('?') !== -1 ? '?' : location.search;\n    if (window.history \u0026\u0026 window.history.replaceState) {\n        var ogU = location.pathname + window._cf_chl_opt.cOgUQuery + window._cf_chl_opt.cOgUHash;\n        history.replaceState(null, null, \"\\/?__cf_chl_rt_tk=REDACTED\" + window._cf_chl_opt.cOgUHash);\n        cpo.onload = function () {\n            history.replaceState(null, null, ogU);\n        }\n    }\n    document.getElementsByTagName('head')[0].appendChild(cpo);\n}());\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nYou don't want to solve CAPTCHA every time you access a website, do you?\n\n## Disclaimer\n\nThis project is just a Proof of Concept. It's neither production-ready nor well-tested. Use it at your own risk.\n\nThis project is not affiliated with Cloudflare in any way.\n\nThe software is provided \"AS IS\" without any warranty, express or implied, including but not limited to the warranties\nof merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or Cloudflare,\nInc. be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising\nfrom, out of or in connection with the software or the use or other dealings in the software.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcinit%2Fudpfwd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcinit%2Fudpfwd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcinit%2Fudpfwd/lists"}