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

Socks proxy support #33

Open
Chris2011 opened this issue Dec 2, 2021 · 6 comments
Open

Socks proxy support #33

Chris2011 opened this issue Dec 2, 2021 · 6 comments

Comments

@Chris2011
Copy link

For the WebSocket npm package (ws) in node, it is possible to connect to a proxy. For example, if I'm running a TOR server, I can use the node package socks-proxy-agent (https://www.npmjs.com/package/socks-proxy-agent) to create such agent and hand over the option to the WebSocket constructor. Afaik, websockets for deno doesn't support such proxies. It would be nice, if we can have this for the deno package too.

@Chris2011
Copy link
Author

Here is my node.js example:

import SocksProxyAgent from 'socks-proxy-agent';
import WebSocket from 'ws';

// SOCKS proxy to connect to
const proxy: string = process.env.socks_proxy || 'socks://127.0.0.1:9050';
console.log('using proxy server %j', proxy);

// WebSocket endpoint for the proxy to connect to
const endpoint: string = process.argv[2] || 'ws://echo.websocket.org';
console.log('attempting to connect to WebSocket %j', endpoint);

// create an instance of the `SocksProxyAgent` class with the proxy server information
const agent: unknown = SocksProxyAgent(proxy);

// initiate the WebSocket connection
const socket: WebSocket = new WebSocket(endpoint, { agent: agent } as any);

socket.on('open', function () {
  console.log('"open" event!');
  socket.send('hello world');
});

socket.on('message', function (data: unknown, flags: unknown) {
  console.log('"message" event! ', data, flags);
  socket.close();
});

@Mutefish0
Copy link

👍

@Mutefish0
Copy link

here is my workaround

Node.js child process:

// node.js
const WebSocket = require("ws");
const HttpsProxyAgent = require("https-proxy-agent");
const net = require("net");
const url = require("url");
const _socket = new net.Socket();

const endpoint = process.argv[2];

if (!endpoint.startsWith("wss://")) {
  throw new Error(`Invalid ws endpoint: ${endpoint}`);
}

_socket.connect({ port: 9123, keepAlive: true }, () => {
  let socket;
  const proxy =
    process.env.all_proxy || process.env.http_proxy || process.env.https_proxy;
  if (proxy) {
    const options = url.parse(proxy);
    const agent = new HttpsProxyAgent(options);
    socket = new WebSocket(endpoint, { agent: agent });
  } else {
    socket = new WebSocket(endpoint);
  }
  socket.on("open", function () {
    console.log("open:", endpoint);
    _socket.on("data", function (chunk) {
      const msg = chunk.toString();
      socket.send(msg);
    });
    _socket.write("onopen");
  });
  socket.on("message", function (data) {
    _socket.write(`||${data}`);
  });
  socket.on("error", function (e) {
    console.log(e);
    _socket.end();
    throw new Error(e);
  });
});

Deno main process

// mod.ts
const decoder = new TextDecoder();
const encoder = new TextEncoder();

class WebSocketNode {
  private closed = false;
  public onopen = () => {};
  public onerror = (e: Error) => {};
  public onmessage = (e: { data: string }) => {};

  private conn?: Deno.Conn;

  constructor(endpoint: string) {
    const cmd = [
      "node",
      new URL("node.js", import.meta.url).pathname,
      endpoint,
    ];
    this.listen();
    Deno.run({ cmd });
  }

  private async listen() {
    const listener = Deno.listen({ port: 9123 });
    console.log("listening on 0.0.0.0:9123");
    for await (const conn of listener) {
      this.conn = conn;
      while (!this.closed) {
        const buffer = new Uint8Array(1024 * 1024 * 10);
        const len = (await conn.read(buffer)) || 0;
        if (len > 0) {
          const msg = decoder.decode(buffer.slice(0, len));
          if (msg === "onopen") {
            this.onopen();
          } else {
            const msgs = msg.split("||").slice(1);
            for (const m of msgs) {
              this.onmessage({ data: m });
            }
          }
        }
      }
    }
  }

  public send(data: string) {
    if (this.conn) {
      this.conn.write(encoder.encode(data));
    }
  }
}

export default WebSocketNode;

Usage:

import WebSocketNode from './mod.ts';
const ws = new WebSocketNode("wss://...");
ws.onmessage = (e) => console.log(e.data)

@Chris2011
Copy link
Author

So your socks5 proxy is running locally on 9123, right? I will test this out, thx. I just tried this lib, seems pretty new: https://github.com/rclarey/socks5 but it is not working with tor. Jut got generic socks error. Will let the maintainer know.

@Mutefish0
Copy link

So your socks5 proxy is running locally on 9123, right? I will test this out, thx. I just tried this lib, seems pretty new: https://github.com/rclarey/socks5 but it is not working with tor. Jut got generic socks error. Will let the maintainer know.

The environment variable all_proxy, https_proxy , http_proxy specified the socks5 proxy .

Deno main process communicates with node.js child process using port 9123.

@Chris2011
Copy link
Author

Ahh I see now. Thx :). Really just a workaround, but also nice.

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

No branches or pull requests

2 participants