{"id":34121940,"url":"https://github.com/syndicatefoundation/singproxy","last_synced_at":"2026-01-31T14:00:57.276Z","repository":{"id":317731567,"uuid":"1068618794","full_name":"SyNdicateFoundation/singproxy","owner":"SyNdicateFoundation","description":"A high-level Go library designed to simplify connecting through various proxy protocols.","archived":false,"fork":false,"pushed_at":"2025-11-13T12:47:25.000Z","size":111,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-17T07:50:53.697Z","etag":null,"topics":["golang","high-level","library","network","networking","protocol","proxy","sing-box"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SyNdicateFoundation.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":"2025-10-02T16:48:44.000Z","updated_at":"2025-11-13T12:47:29.000Z","dependencies_parsed_at":"2025-10-02T18:37:50.139Z","dependency_job_id":null,"html_url":"https://github.com/SyNdicateFoundation/singproxy","commit_stats":null,"previous_names":["syndicatefoundation/signproxy"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/SyNdicateFoundation/singproxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SyNdicateFoundation%2Fsingproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SyNdicateFoundation%2Fsingproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SyNdicateFoundation%2Fsingproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SyNdicateFoundation%2Fsingproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SyNdicateFoundation","download_url":"https://codeload.github.com/SyNdicateFoundation/singproxy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SyNdicateFoundation%2Fsingproxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28944789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T13:02:32.153Z","status":"ssl_error","status_checked_at":"2026-01-31T13:00:07.528Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["golang","high-level","library","network","networking","protocol","proxy","sing-box"],"created_at":"2025-12-14T21:56:32.126Z","updated_at":"2026-01-31T14:00:57.270Z","avatar_url":"https://github.com/SyNdicateFoundation.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sing-Proxy: A Robust Go Proxy Client Library\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/SyNdicateFoundation/singproxy)](https://goreportcard.com/report/github.com/SyNdicateFoundation/singproxy)\n\nSing-Proxy is a high-level Go library designed to simplify connecting through various proxy protocols. Built as a\nwrapper around the powerful `sagernet/sing-box` core, its primary feature is its exceptional ability to parse and handle\na vast number of non-standard, malformed, and \"dirty\" proxy URLs found in the wild.\n\nIf you need to consume proxy lists from public Telegram channels, subscription services, or other non-standard sources,\nSing-Proxy is built to handle the mess for you.\n\n## Features\n\n- **Unified `Proxy` Interface**: A single, simple API for Shadowsocks, VLESS, VMess, Trojan, and more.\n- **Powered by `sing-box`**: Leverages the robust, performant, and up-to-date networking core of `sing-box`.\n- **Resilient URL Parsing**: Intelligently cleans and fixes common errors in proxy URLs *before* parsing, dramatically\n  increasing success rates with public proxy lists.\n- **Wide Protocol Support**:\n    - VLESS (with REALITY, gRPC, WebSocket, HTTP Upgrade)\n    - VMess\n    - Trojan\n    - Shadowsocks (including `encryption=none` variants and SIP003 formats)\n    - Hysteria/Hysteria2\n    - WireGuard\n    - SOCKS5/SOCKS4\n    - HTTP/HTTPS/HTTP2\n    - TUIC\n    - SSH\n    - AnyTLS\n    - NaiveProxy\n    - ShadowTLS\n- **Concurrency-Ready**: Includes a `FromURLs` helper to parse large lists of proxies in parallel.\n\n## Installation\n\n```sh\ngo get github.com/SyNdicateFoundation/singproxy\n```\n\nUse following tags for building you binary\n\n```\n-tags=with_utls,with_gvisor,with_quic,with_dhcp,with_acme,with_clash_api,with_wireguard\n```\n\n## Basic Usage\n\nThe library exposes a straightforward API. You provide a proxy URL, and you get back an object that satisfies the\n`Proxy` interface, which has a `DialContext` method you can use in any standard Go networking code.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/SyNdicateFoundation/singproxy\"\n)\n\nfunc main() {\n\t// Example VLESS URL with a REALITY configuration and a name in the fragment.\n\tproxyURL := \"vless://a-uuid@example.com:443?security=reality\u0026sni=sni.example.com\u0026fp=chrome\u0026pbk=YOUR_REALITY_KEY\u0026sid=abcdef1234#MyVlessProxy\"\n\ttimeout := 8 * time.Second\n\n\t// 1. Parse the URL using the factory function.\n\tproxy, err := singproxy.FromURL(timeout, proxyURL)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to parse proxy URL: %v\", err))\n\t}\n\n\t// The String() method returns the cleaned name from the URL fragment.\n\tfmt.Printf(\"Successfully parsed proxy: %s\\n\", proxy.String()) // Prints \"vless://a-uuid@example.com:443?security=reality\u0026sni=sni.example.com\u0026fp=chrome\u0026pbk=YOUR_REALITY_KEY\u0026sid=abcdef1234\"\n\n\t// 2. Create an HTTP client that uses the proxy's custom dialer.\n\thttpClient := \u0026http.Client{\n\t\tTimeout: 15 * time.Second,\n\t\tTransport: \u0026http.Transport{\n\t\t\tDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\t\t\ttcpAddr, err := net.ResolveTCPAddr(network, addr)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\t// Use the proxy's DialContext method to establish the connection.\n\t\t\t\treturn proxy.DialContext(ctx, network, tcpAddr)\n\t\t\t},\n\t\t},\n\t}\n\n\t// 3. Make a request to a test endpoint through the proxy.\n\tfmt.Println(\"Making request to httpbin.org/get...\")\n\tresp, err := httpClient.Get(\"https://httpbin.org/get\")\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"Request failed through proxy: %v\", err))\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, _ := io.ReadAll(resp.Body)\n\tfmt.Printf(\"Status: %s\\n\", resp.Status)\n\tfmt.Printf(\"Response Body (first 100 bytes): %.100s...\\n\", string(body))\n}\n```\n\n## Example: A Simple Concurrent Proxy Tester\n\nThis complete example demonstrates how to parse multiple URLs at once and test their connectivity concurrently.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/SyNdicateFoundation/singproxy\"\n)\n\n// TestResult holds the outcome of a single proxy test.\ntype TestResult struct {\n\tProxyName string\n\tLatency   time.Duration\n\tSuccess   bool\n\tError     error\n}\n\nfunc main() {\n\tproxyURLs := []string{\n\t\t\"direct\", // A direct connection for baseline comparison.\n\t\t\"vless://a-uuid@example.com:443?security=tls\u0026sni=example.com#VLESS-Example\",\n\t\t\"ss://YWVzLTI1Ni1nY206cGFzc3dvcmQ=@example.com:8080#Shadowsocks-Example\",\n\t\t\"trojan://password@example.com:443?sni=example.com#Trojan-Example\",\n\t\t\"this-is-an-invalid-url\", // An invalid URL to show error handling.\n\t\t\"hysteria2://--\u003einvalid-user@example.com:4567#Malformed-Hysteria2\", // Will be cleaned and parsed.\n\t}\n\n\tfmt.Printf(\"Parsing %d proxy URLs...\\n\", len(proxyURLs))\n\ttimeout := 8 * time.Second\n\n\t// Use FromURLs to parse all proxies concurrently. It returns valid proxies and any errors.\n\tproxies, errs := singproxy.FromURLs(timeout, proxyURLs...)\n\n\t// Print any parsing errors encountered.\n\tif len(errs) \u003e 0 {\n\t\tfmt.Printf(\"\\nEncountered %d parsing errors:\\n\", len(errs))\n\t\tfor _, err := range errs {\n\t\t\tfmt.Printf(\" - %v\\n\", err)\n\t\t}\n\t}\n\n\tfmt.Printf(\"\\nSuccessfully parsed %d proxies. Starting connection tests...\\n\\n\", len(proxies))\n\n\tvar wg sync.WaitGroup\n\tresults := make(chan TestResult, len(proxies))\n\n\t// Test each valid proxy in its own goroutine.\n\tfor _, p := range proxies {\n\t\twg.Add(1)\n\t\tgo testProxy(p, results, \u0026wg)\n\t}\n\n\t// Wait for all tests to complete.\n\twg.Wait()\n\tclose(results)\n\n\t// Print the collected results.\n\tfor result := range results {\n\t\tif result.Success {\n\t\t\tfmt.Printf(\"[SUCCESS] Proxy: %-30s | Latency: %s\\n\", result.ProxyName, result.Latency)\n\t\t} else {\n\t\t\tfmt.Printf(\"[FAILURE] Proxy: %-30s | Error: %v\\n\", result.ProxyName, result.Error)\n\t\t}\n\t}\n}\n\n// testProxy attempts to make an HTTP GET request through the given proxy and sends the result to a channel.\nfunc testProxy(p singproxy.Proxy, results chan\u003c- TestResult, wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\n\tresult := TestResult{ProxyName: p.String()}\n\tstartTime := time.Now()\n\n\thttpClient := \u0026http.Client{\n\t\tTimeout: 10 * time.Second, // Timeout for the entire HTTP request.\n\t\tTransport: \u0026http.Transport{\n\t\t\t// Use the proxy's custom dialer.\n\t\t\tDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\t\t\ttcpAddr, err := net.ResolveTCPAddr(network, addr)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn p.DialContext(ctx, network, tcpAddr)\n\t\t\t},\n\t\t\t// Disable keep-alives for more accurate, isolated latency measurement.\n\t\t\tDisableKeepAlives: true,\n\t\t},\n\t}\n\n\t// Make the test request.\n\tresp, err := httpClient.Get(\"https://httpbin.org/get\")\n\tif err != nil {\n\t\tresult.Success = false\n\t\tresult.Error = err\n\t\tresults \u003c- result\n\t\treturn\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusOK {\n\t\tresult.Success = true\n\t\tresult.Latency = time.Since(startTime)\n\t\t// Drain the body to properly measure the time for the full response.\n\t\t_, _ = io.Copy(io.Discard, resp.Body)\n\t} else {\n\t\tresult.Success = false\n\t\tresult.Error = fmt.Errorf(\"bad status: %s\", resp.Status)\n\t}\n\n\tresults \u003c- result\n}\n```\n\n## How The Robust Parsing Works\n\nMany proxy providers and aggregators generate URLs that don't strictly adhere to RFC standards. They often contain extra\nmetadata, comments, or invalid characters that cause standard Go parsers like `net/url.Parse` to fail.\n\nSing-Proxy addresses this with a multi-layered cleaning process in its `FromURL` function:\n\n1. **Isolate Name**: The URL fragment (`#...`) is immediately separated to preserve the proxy's intended name.\n2. **General Cleaning**: Removes common junk query parameters like `ps`, `remarks`, `tag`, etc.\n3. **Protocol-Specific Cleaning**: Before parsing, it applies a set of \"brute-force\" rules tailored to each protocol's\n   common mistakes:\n    * **VMess**: Strips all non-Base64 characters from the payload.\n    * **Hysteria2/Trojan**: Escapes invalid characters found in `userinfo` (like `--\u003e`, `^`, `🤠`).\n    * **Shadowsocks**: Corrects malformed structures like `ss://user@host:port@comment`.\n    * **VLESS**: Cleans junk data appended to hostnames (e.g., `...:port---Telegram---`).\n4. **Standard Parsing**: Only after these cleaning steps is the URL passed to Go's standard parser.\n5. **Post-Parsing Fallbacks**: Within the individual protocol parsers, it applies fallbacks for common logical errors,\n   such as using a default cipher when a Shadowsocks method is missing or handling non-standard transport names like\n   `xhttp`.\n\n## Supported Protocols\n\nThe library supports the following URL schemes:\n\n- **VMess** (`vless://`)\n- **HTTP** / **HTTPS** / **HTTP2** (`http://`, `https://`, `http2://`)\n- **VLESS** (`vless://`)\n- **Trojan** (`trojan://`, `trojan-go://`)\n- **Shadowsocks** (`ss://`)\n- **TUIC** (`tuic://`)\n- **Hysteria** (`hysteria://`)\n- **Hysteria2** (`hysteria2://`)\n- **SSH** (`ssh://`)\n- **SOCKS5** / **SOCKS4** (`socks5://`, `socks4://`)\n- **WireGuard** (`wireguard://`)\n- **Direct** (`direct`)\n- **Tor** (`tor://`)\n- **AnyTLS** (`anytls://`, `atls://`)\n- **ShadowTLS** (`shadowtls://`)\n- **NaiveProxy** (`naive://`, `naive+https://`)\n\n## License\n\nThis project is licensed under the MIT License.\n\n## Credits\n\n- [sing-box](https://github.com/SagerNet/sing-box) core library\n- [TGParse](https://github.com/Surfboardv2ray/TGParse) used proxies for test propose\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyndicatefoundation%2Fsingproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsyndicatefoundation%2Fsingproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyndicatefoundation%2Fsingproxy/lists"}