{"id":29105169,"url":"https://github.com/nashaofu/rusocks","last_synced_at":"2025-07-20T19:34:42.440Z","repository":{"id":261080749,"uuid":"881944543","full_name":"nashaofu/rusocks","owner":"nashaofu","description":"A socks4(a)/5 server","archived":false,"fork":false,"pushed_at":"2024-11-10T03:38:55.000Z","size":48,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-29T01:07:53.445Z","etag":null,"topics":["socks","socks4","socks4a","socks5"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/rusocks","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nashaofu.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":"2024-11-01T14:47:39.000Z","updated_at":"2024-11-10T03:38:56.000Z","dependencies_parsed_at":"2024-11-04T16:20:45.098Z","dependency_job_id":"73837d9d-24c4-4e5e-ad3e-efc11d297001","html_url":"https://github.com/nashaofu/rusocks","commit_stats":null,"previous_names":["nashaofu/rusocks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nashaofu/rusocks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nashaofu%2Frusocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nashaofu%2Frusocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nashaofu%2Frusocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nashaofu%2Frusocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nashaofu","download_url":"https://codeload.github.com/nashaofu/rusocks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nashaofu%2Frusocks/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266187670,"owners_count":23890012,"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":["socks","socks4","socks4a","socks5"],"created_at":"2025-06-29T01:07:51.223Z","updated_at":"2025-07-20T19:34:42.418Z","avatar_url":"https://github.com/nashaofu.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rusocks\n\nA socks4(a)/5 server\n\n## features:\n\n- socks4/4a protocol\n\n  - [x] connect\n  - [x] bind\n\n- socks5 protocol\n\n  - [x] no authentication\n  - [x] username/password\n\n- socks5 command\n\n  - [x] connect\n  - [x] bind\n  - [ ] udp associate\n\n## example\n\n```rust\nuse std::net::SocketAddr;\n\nuse async_trait::async_trait;\nuse rusocks::{\n    address::Address,\n    error::Error,\n    socks4::{reply::Socks4Reply, request::Socks4Request, Socks4Handler},\n    socks5::{method::Socks5Method, reply::Socks5Reply, request::Socks5Request, Socks5Handler},\n    Socks,\n};\nuse tokio::{\n    io::{self, AsyncReadExt, AsyncWriteExt},\n    net::{TcpListener, TcpStream},\n    select, time,\n};\n\n#[tokio::main]\nasync fn main() {\n    // curl -x socks4://127.0.0.1:1080 http://127.0.0.1:8080\n    // curl -x socks5://127.0.0.1:1080 http://127.0.0.1:8080\n    let listener = TcpListener::bind(\"127.0.0.1:1080\").await.unwrap();\n\n    while let Ok((mut stream, _)) = listener.accept().await {\n        tokio::spawn(async move {\n            let peer_addr = stream.peer_addr().unwrap();\n            let local_addr = stream.local_addr().unwrap();\n\n            let handler = Handler {};\n            let mut socks = Socks::from_stream(\u0026mut stream, peer_addr, local_addr, handler)\n                .await\n                .unwrap();\n\n            match socks.accept(\u0026mut stream).await {\n                Ok(_) =\u003e {\n                    println!(\"success\");\n                }\n                Err(e) =\u003e {\n                    println!(\"error: {}\", e);\n                }\n            }\n        });\n    }\n}\n\nstruct Handler {}\n\n#[async_trait]\nimpl Socks4Handler for Handler {\n    type ConnectStream = TcpStream;\n\n    async fn connect(\u0026self, address: \u0026Address) -\u003e Result\u003c(Self::ConnectStream, SocketAddr), Error\u003e {\n        let stream = TcpStream::connect((address.domain(), address.port())).await?;\n        let bind_addr = stream.local_addr()?;\n\n        Ok((stream, bind_addr))\n    }\n\n    async fn bind\u003cS\u003e(\n        \u0026self,\n        request: \u0026mut Socks4Request\u003cS\u003e,\n        bind_addr: \u0026Address,\n    ) -\u003e Result\u003c(), Error\u003e\n    where\n        S: AsyncReadExt + AsyncWriteExt + Unpin + Send,\n    {\n        let listener = TcpListener::bind((bind_addr.domain(), bind_addr.port())).await?;\n        let bind_addr = listener.local_addr()?.clone();\n        request.reply(Socks4Reply::Granted, bind_addr).await?;\n\n        let (mut connect, peer_addr) = listener.accept().await?;\n        // 异步处理连接\n        println!(\"Accepted connection from {:?}\", peer_addr);\n        io::copy_bidirectional(\u0026mut request.stream, \u0026mut connect)\n            .await\n            .unwrap();\n\n        Ok(())\n    }\n}\n\n#[async_trait]\nimpl Socks5Handler for Handler {\n    type ConnectStream = TcpStream;\n\n    async fn negotiate_method(\u0026self, _methods: \u0026[Socks5Method]) -\u003e Result\u003cSocks5Method, Error\u003e {\n        Ok(Socks5Method::None)\n    }\n\n    async fn auth_by_user_pass(\u0026self, username: \u0026str, password: \u0026str) -\u003e Result\u003cbool, Error\u003e {\n        println!(\"username: {}, password: {}\", username, password);\n        Ok(false)\n    }\n\n    async fn connect(\u0026self, address: \u0026Address) -\u003e Result\u003c(Self::ConnectStream, SocketAddr), Error\u003e {\n        let stream = TcpStream::connect((address.domain(), address.port())).await?;\n        let bind_addr = stream.local_addr()?;\n\n        Ok((stream, bind_addr))\n    }\n\n    async fn bind\u003cS\u003e(\n        \u0026self,\n        request: \u0026mut Socks5Request\u003cS\u003e,\n        bind_addr: \u0026Address,\n    ) -\u003e Result\u003c(), Error\u003e\n    where\n        S: AsyncReadExt + AsyncWriteExt + Unpin + Send,\n    {\n        let listener = TcpListener::bind((bind_addr.domain(), bind_addr.port())).await?;\n        let bind_addr = listener.local_addr()?.clone();\n\n        request.reply(Socks5Reply::Succeeded, bind_addr).await?;\n\n        select! {\n            // 超时关闭\n            _ = time::sleep(time::Duration::from_secs(20)) =\u003e {\n                println!(\"Shutdown signal received. Stopping the listener...\");\n                return Ok(());\n            }\n            Ok((mut connect, peer_addr)) = listener.accept() =\u003e {\n                println!(\"Accepted connection from {:?}\", peer_addr);\n                request.reply(Socks5Reply::Succeeded, peer_addr).await?;\n                io::copy_bidirectional(\u0026mut request.stream, \u0026mut connect).await?;\n            }\n        }\n\n        Ok(())\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnashaofu%2Frusocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnashaofu%2Frusocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnashaofu%2Frusocks/lists"}