nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.45k stars 278 forks source link

Using net.connect via tor proxy to connect to port 25 for smtp validation #4210

Closed nailaiftikhar closed 2 months ago

nailaiftikhar commented 1 year ago

I am currently working on implementing SMTP email validation in my Node.js application and want to route the connection through a Tor proxy for enhanced privacy and anonymity. I tried using net.connect with the specified localPort and localAddress set to 9050 and 127.0.0.1, respectively, to establish a connection through the Tor proxy. However, it resulted in a "port address already in use" error (Error: bind EADDRINUSE 127.0.0.1:9050).

To provide more context, I have Tor properly configured and running on my system, listening on port 9050. Additionally, my email validation code works perfectly without using the Tor proxy. Could you let me know if this is the correct way to connect an existing Tor proxy? Side Note: Using 'socks' doesn't work either and gives timeouts.

code

        const socket = net.connect({ port: 25, host: exchange, localAddress: '127.0.0.1', localPort: 9050 })
        socket.setEncoding('ascii');
        socket.setTimeout(timeout);
        socket.on('connect', () => {
           console.log( 'Socket connected')
        })
        socket.on('error', error => {
            console.log('error in creating socket', error)
            socket.emit('fail', error);
        });
prettydiff commented 1 year ago

The problem is a misunderstanding of what a localPort is. If it helps to think about it in terms of client/server that may help.

In a connection there is a local and remote port. For the sake of simplicity let's talk about an address other than loopback (127.0.0.1) because with loopback both ports are on the same IP. So consider the following scenario:

Local address 192.168.12.1 Local port: 43672 Remote address: 192.168.12.123 Remote port: 9050

Using that addressing data your node instance executes at the local address/port and connects to the remote, so port 9050 is listening on a remote address. If you attempt to connect to 192.168.12.1 on port 43672 you are attempting to connect on your local box to a port you also expect to receive data on. That will throw a EADDRINUSE exception because a port cannot be used for two separate things even if those two separate things are ends of the same socket.

In your case TOR is running on port 9050, which means your socket cannot expect to receive traffic at that port because the port is already in use by TOR. Also, you don't have to specify the local port or local address of a socket. Local port and address will be dynamically assigned to any available IP capable of completing a path from your physical interface and any open local port will be used. All you need to specify is the destination port/address to make the connection.

nailaiftikhar commented 1 year ago

Ok. Got it. But how can I connect to a remote host using an existing tor proxy at 9050 port. Is that possible via net.connect? One way is using socks and create a socket but that is giving timeout everytime.

prettydiff commented 1 year ago

You must connect to the proxy using whatever API is defined by the proxy, because the proxy will open a separate connection between itself and your destination.

nailaiftikhar commented 1 year ago

You must connect to the proxy using whatever API is defined by the proxy, because the proxy will open a separate connection between itself and your destination.

That's my question, does net.connect or net.createConnection provide any way to connect using a socks proxy? Since, using socks API gives timeout in my case, this is my code for reference:

 const torProxyOptions: SocksClientOptions = {
      proxy: {
        ipaddress: '127.0.0.1',
        port: port,   // tried from 9001 to 9099
        type: 5,
      },
      destination: {
        host: exchange,
        port: 25,
      },
      command: 'connect',
    };

    SocksClient.createConnection(torProxyOptions, (err, info) => {
      if (err) {
        console.error('Error connecting via Tor proxy:', err);
        return;
      }

      const socket = info?.socket;

      if (!socket) {
        console.error('Could not establish a socket connection through the Tor proxy.');
        return;
      }
      socket.setEncoding('ascii');
      socket.setTimeout(timeout);

      socket.on('error', (error) => {
        log('error', error);
        socket.emit('fail', error);
      });

      socket.on('timeout', () => {
        socket.emit('fail', 'Timeout');
      });

    // rest of the code regarding SMTP validation
});

This code works using net.connect without using any proxy.

preveen-stack commented 1 year ago

@nailaiftikhar can you check the proxy by another client and verify it is working properly

nailaiftikhar commented 1 year ago

@nailaiftikhar can you check the proxy by another client and verify it is working properly

It doesn't work. The only code which works is this, i.e., without using a proxy:

 const socket = net.connect({ port: 25, host: exchange })
        socket.setEncoding('ascii');
        socket.setTimeout(timeout);
        socket.on('connect', () => {
           console.log( 'Socket connected')
        })
preveen-stack commented 1 year ago

@nailaiftikhar what I meant was, is the socks proxy itself working

nailaiftikhar commented 1 year ago

@nailaiftikhar what I meant was, is the socks proxy itself working

yes, I've checked, it listens on the specified port. I get the timeout error while connecting to port 25.

preveen-stack commented 1 year ago

Can you try connecting to google.com through the proxy and see

Also try the below script in Python so that we can isolate the issue

import requests

def check_proxy_connectivity(proxy_url):
    try:
        # URL to check connectivity (replace with your desired URL)
        target_url = 'https://www.example.com'

        # Use the SOCKS proxy for the request
        proxies = {
            'http': proxy_url,
            'https': proxy_url,
        }

        # Send a test request through the proxy
        response = requests.get(target_url, proxies=proxies, timeout=10)

        # Check the response status
        if response.status_code == 200:
            print(f"Proxy {proxy_url} is working. Status code: {response.status_code}")
        else:
            print(f"Proxy {proxy_url} is not working. Status code: {response.status_code}")
    except Exception as e:
        print(f"Error while checking the proxy {proxy_url}: {e}")

def main():
    # Replace with your SOCKS proxy URL (e.g., 'socks5://127.0.0.1:9050')
    proxy_url = 'socks5://127.0.0.1:9050'

    check_proxy_connectivity(proxy_url)

if __name__ == "__main__":
    main()
nailaiftikhar commented 1 year ago

This Python code works and gives: Proxy socks5://127.0.0.1:9050 is working. Status code: 200 I think the issue is setting the destination port to 25, even this Python code gives timeout errors if I change the target_url to 'https://www.example.com:25'. Same results with JS using http and socks:

const proxyOptions = {
  host: 'localhost', 
  port: 9050,        
};

const proxyURL = `socks://${proxyOptions.host}:${proxyOptions.port}`;
const agent = new SocksProxyAgent(proxyURL);

const requestOptions = {
  hostname: 'example.com',
  agent,
  port: 25       // gives timeout error, works fine if no port specified
};

const req = http.request(requestOptions, (res) => {
  res.setEncoding('ascii');
  res.on('data', (data) => {
    console.log('Received data from server:', data);
  });
});

req.on('error', (err) => {
  console.error('Error:', err);
});

req.on('timeout', () => {
  console.error('Timeout: Connection took too long');
  req.abort();
});

req.end();
github-actions[bot] commented 3 months ago

It seems there has been no activity on this issue for a while, and it is being closed in 30 days. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.

github-actions[bot] commented 2 months ago

It seems there has been no activity on this issue for a while, and it is being closed. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.