Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

question: how can one forward to another tcp proxy? As in chain proxies? #15

Open
GlenDC opened this issue May 3, 2022 · 4 comments
Open

Comments

@GlenDC
Copy link

GlenDC commented May 3, 2022

From the documentation or examples it is not clear what the intended approach with this library is when one would want to forward from a fast-socks5 proxy to another proxy?

I'll keep digging myself once i find time, and if I find it myself I'll post it here.
But if someone knows the answer from the top of their head, that would be even better :)

@GlenDC
Copy link
Author

GlenDC commented May 5, 2022

Found how I can do it myself, here is how I did it:

async fn handle_socket<T>(socket: Socks5Socket<T>, _request_timeout: u64)
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    // upgrade socket to SOCKS5 proxy
    let mut socks5_socket = match socket.upgrade_to_socks5().await {
        Err(e) => {
            error!("upgrade incoming socket to socks5: {:#}", e);
            return;
        },
        Ok(socket) => socket,
    };

    // get resolved target addr
    if let Err(e) = socks5_socket.resolve_dns().await {
        error!("resolve target dns for incoming socket: {:#}", e);
        return;
    }
    let target_addr = match socks5_socket.target_addr() {
        Some(addr) => addr,
        None => {
            error!("no target address found for incoming socket");
            return;
        },
    };
    let mut socket_addrs_it = match target_addr.to_socket_addrs() {
        Err(e) =>  {
            error!("no socket addresses found for target addr of incoming socket: {:#}", e);
            return;
        },
        Ok(it) => it,
    };
    let socket_addr = match socket_addrs_it.next() {
        None =>  {
            error!("target of incoming socket unreachable");
            return;
        },
        Some(addr) => addr,
    };

    let stream_config = client::Config::default();

    // connect to downstream proxy
    let mut stream = match Socks5Stream::connect_with_password(
        "127.0.0.1:1338",
        socket_addr.ip().to_string(),
        socket_addr.port(),
        String::from("john"),
        String::from("foo"),
        stream_config,
    ).await {
        Err(e) =>  {
            error!("connect to downstream proxy for incoming socket: {:#}", e);
            return;
        },
        Ok(stream) => stream,
    };

    // copy data between our incoming client and the used downstream proxy
    match tokio::io::copy_bidirectional(&mut stream, &mut socks5_socket).await {
        Ok(res) => info!("socket transfer closed ({}, {})", res.0, res.1),
        Err(err) => if err.kind() == ErrorKind::NotConnected {
            info!("socket transfer closed by client")
        } else {
            error!("socket transfer error: {:?}", err)
        },
    };
}

Does this make sense, or am I making it more difficult than it is?
If you're interested I could make a PR to add an example to add it as another server example, cannot imagine that I'm the only one who would like the ability to be able to go through yet another proxy, in order to establish a gateway / router in front of actual proxies on location.

@GlenDC
Copy link
Author

GlenDC commented May 5, 2022

This code was only put in a function at the end of my struggles, so I was still logging everywhere instead of handling these errors more neatly as a single error log where I call it. I now refactored it a bit so that makes the logic already seem a lot simpler:

async fn handle_socket<T>(socket: Socks5Socket<T>, _request_timeout: u64) -> Result<()>
where
    T: AsyncRead + AsyncWrite + Unpin {
    // upgrade socket to SOCKS5 proxy
    let mut socks5_socket = socket.upgrade_to_socks5().await.context("upgrade incoming socket to socks5")?;

    // get resolved target addr
    socks5_socket.resolve_dns().await.context("resolve target dns for incoming socket")?;
    let socket_addr = socks5_socket
        .target_addr()
        .context("find target address for incoming socket")?
        .to_socket_addrs()
        .context("convert target address of incoming socket to socket addresses")?
        .next()
        .context("reach out to target of incoming socket")?;

    let stream_config = client::Config::default();

    // connect to downstream proxy
    let mut stream = Socks5Stream::connect_with_password(
        "127.0.0.1:1338",
        socket_addr.ip().to_string(),
        socket_addr.port(),
        String::from("john"),
        String::from("foo"),
        stream_config,
    ).await.context("connect to downstream proxy for incoming socket")?;

    // copy data between our incoming client and the used downstream proxy
    match tokio::io::copy_bidirectional(&mut stream, &mut socks5_socket).await {
        Ok(res) => {
            info!("socket transfer closed ({}, {})", res.0, res.1);
            Ok(())
        },
        Err(err) => if err.kind() == ErrorKind::NotConnected {
            info!("socket transfer closed by client");
            Ok(())
        } else {
            Err(SocksError::Other(anyhow!("socket transfer error: {:#}", err)))
        },
    }
}

Same position though, what is your opinion on this kind of gateway concept, is that a good use case of this library, or am I shoe-horning a solution here?

GlenDC pushed a commit to GlenDC/fast-socks5 that referenced this issue May 5, 2022
@GlenDC
Copy link
Author

GlenDC commented May 6, 2022

My example won't work. This is related to #21 I believe.
Within the upgrade_to_socks5 logic we already request and process it.
As such the first actual usage of the proxy is already going via the router directly to the target.

In order for a streamer like this to work we would need to also expose the authentication (and other setup part) from the actual request part.

This way we even have access to the unresolved target address (see #19). So that's another issue resolved.
Seems the building blocks are all there, it's just that the library doesn't expose it yet.

@GlenDC
Copy link
Author

GlenDC commented May 8, 2022

New attempt is made to have this shown in an example: #24

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant