{"id":20325092,"url":"https://github.com/mphe/udp-wan-proxy","last_synced_at":"2025-10-18T00:38:19.962Z","repository":{"id":196590337,"uuid":"696464415","full_name":"mphe/udp-wan-proxy","owner":"mphe","description":"A cross-platform UDP proxy for WAN emulation with sub-millisecond performance.","archived":false,"fork":false,"pushed_at":"2023-11-18T23:14:29.000Z","size":256,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-04T10:29:38.384Z","etag":null,"topics":["emulation","go","proxy","udp","wan"],"latest_commit_sha":null,"homepage":"","language":"Go","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/mphe.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}},"created_at":"2023-09-25T19:48:22.000Z","updated_at":"2024-10-22T14:00:25.000Z","dependencies_parsed_at":"2024-06-19T17:45:18.132Z","dependency_job_id":null,"html_url":"https://github.com/mphe/udp-wan-proxy","commit_stats":null,"previous_names":["mphe/udp-wan-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mphe/udp-wan-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fudp-wan-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fudp-wan-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fudp-wan-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fudp-wan-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mphe","download_url":"https://codeload.github.com/mphe/udp-wan-proxy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mphe%2Fudp-wan-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279444997,"owners_count":26171410,"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","status":"online","status_checked_at":"2025-10-17T02:00:07.504Z","response_time":56,"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":["emulation","go","proxy","udp","wan"],"created_at":"2024-11-14T19:38:41.294Z","updated_at":"2025-10-18T00:38:19.922Z","avatar_url":"https://github.com/mphe.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UDP-WAN-Proxy\n\nA cross-platform UDP proxy for WAN emulation with sub-millisecond performance.\n\nThe proxy listens for packets on a given port, emulates WAN conditions like delay, jitter or packet loss, and relays them to another given port.\n\n\n## Building\n\nFrom the project root, either run `make` or `go build -o udp-wan-proxy ./src`.\n\n\n## WAN Emulation Features\n\n**Delay**: Delays all packets by a given time value.\n\n**Jitter**: Randomly delays packets according to a given maximum jitter value.\n\n**Packet loss**: Randomly drop packets according to a given probability. This is implemented in two ways: naive and burst error packet loss.\n\nWith naive packet loss, each packet will be randomly dropped according to a given probability.\n\nBurst error packet loss can be used to model more realistic behavior, as packet loss usually occurs in bursts in real world scenarios.\nIt involves two probabilities $P_{err}$ for transitioning to an error state and $P_{return}$ for leaving the error state.\nThe application starts in normal, non-error state.\nFor every packet received, the application uniformly samples $P_{err}$ and transitions to the error state or remains in normal state accordingly.\nWhile in error state, $P_{return}$ is sampled to transition back to normal state or remaining in error state.\nEvery packet received while the application is in error state will be dropped.\n\n\u003ccenter\u003e\u003cimg src=\"img/burst_pl.png\" width=500px/\u003e\u003c/center\u003e\n\n\n## Usage\n\nSee `udp-wan-proxy -h` to get a list of supported arguments.\n\nThe following shows some examples for a proxy listening on port 5004 and relaying traffic to port 6004.\n\n```sh\n# 500 ms delay + 50 ms jitter\n./udp-wan-proxy -l 5004 -r 6004 -d 500 -j 50\n\n# 1% packet loss\n./udp-wan-proxy -l 5004 -r 6004 --loss 0.01\n# or\n./udp-wan-proxy -l 5004 -r 6004 --loss-start 0.01 --loss-stop 0.99\n\n# Burst error packet loss with 0.1% probability of entering error-state and 50% probability of leaving it.\n./udp-wan-proxy -l 5004 -r 6004 --loss-start 0.001 --loss-stop 0.5\n\n# Log traffic and performance statistics to stats.csv\n./udp-wan-proxy -l 5004 -r 6004 --csv stats.csv\n```\n\n\n## Architecture\n\n\u003ccenter\u003e\u003cimg src=\"img/udp_proxy_arch.png\" width=700px/\u003e\u003c/center\u003e\n\nThe proxy consists of a sender and listener thread that run in parallel.\nThe listener receives incoming packets and adds them to a queue.\nThe sender takes packets from the queue and relays them to the target port.\n\nWhen the listener receives a packet, the configured packet loss distribution is sampled and the packed is dropped or retained accordingly.\nIf the packet is retained, a new timestamp is computed, based on the given delay and jitter, determining when the packet should be dispatched again.\nThe dispatch timestamp and the packet will be put into separate queues. The packet queue is a regular FIFO queue, while the time queue is a priority queue.\n\nThe sender thread takes the most recent timestamp from the time queue, waits until the given point in time is reached, then fetches the next packet from the packet queue and sends it to the target port.\nIf a new packet and timestamp arrives while the thread is waiting, the sleep gets interrupted, the new time is fetched and the loop restarts.\n\nWhen dealing with jitter, the computed dispatch timestamps can easily overlap each other, causing large amounts of unwanted packet reordering.\nBy using distinct queues for packets and timestamps, it can be guaranteed that packets are processed in the same order as they arrive, while timestamps are automatically sorted by their due date, maintaining the computed jitter and the original traffic characteristics, e.g. burst/non-burst phases.\n\n\n## Performance\n\nThe proxy provides sub-millisecond performance, but could be optimized further.\n\nThe following shows a performance evaluation regarding computation delay and CPU usage.\nTwo scenarios were tested: a 5-10 MBit/s video stream and a 4 byte UDP message sent every 0.5 seconds.\nLateness depicts the mean time difference between the scheduled time of sending a packet and the actual time of dispatch.\nThe negative CPU usage likely occurs due to CPU frequency scaling or other scheduling reasons.\n\n\u003ccenter\u003e\u003cimg src=\"img/processing_delay.png\" width=600px/\u003e\u003c/center\u003e\n\nThe most influential factor for performance turned out to be the sleep function, as it can yield up to 1 ms inaccuracy.\nFor this reason, an iterative sleep method has been implemented that sleeps repeatedly for smaller amounts, thus providing better accuracy.\nThe following plot shows the average dispatch lateness and CPU usage in regard to different sleep methods and intervals.\nNaive sleep corresponds to the default sleep function.\n\nAs 250-500 ns seemed to provide the best tradeoff between lateness and CPU usage, the default has been set to 300 ns.\nThis value can still be changed using the `-s` flag.\n\n\u003ccenter\u003e\u003cimg src=\"img/sleep_performance.png\" width=700px/\u003e\u003c/center\u003e\n\n\n## Video corruption\n\nVideo corruption, or data corruption in general, usually occurs with high resolution/quality streams\nwhere the data rate is larger than the maximum OS socket buffer size, hence causing packet loss and\ndata corruption.\n\nThe proxy internally already sets the application socket buffer size to 20 MB, which should suffice in most cases.\n\nTo increase the system's maximum socket buffer size to 20 MB, run:\n```sh\n$ echo 20971520 | sudo tee /proc/sys/net/core/rmem_max\n```\n\nTo make this setting permanent, open `/etc/sysctl.conf` or create a file\n`/etc/sysctl.d/50-socketsize.conf` and add the following content.\n\n```sh\n# Increase maximum socket buffer size to 20MB\nnet.core.rmem_max = 20971520\n```\n\nThen run `sudo sysctl --system` to load the new config.\n\n\n## To-Do\n\n- Bandwidth emulation\n- Packet reordering\n- Configurable socket buffer size\n\n\n## Contributing\n\nContributions are welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmphe%2Fudp-wan-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmphe%2Fudp-wan-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmphe%2Fudp-wan-proxy/lists"}