LacticWhale / socks_dart

Socks5 server and client with ability to catch packet in both direction, chain proxies and more.
MIT License
14 stars 4 forks source link

DNS supprot #4

Closed xAffan closed 3 months ago

xAffan commented 10 months ago

socks5 client does not do dns resolution over the socks proxy check socks5h vs socks5.

LacticWhale commented 10 months ago

You're wrong, prove me otherwise.

xAffan commented 10 months ago

Run a tor proxy, connect to it. Try to connect to .onion website. Host lookup fails. This indicates a problem with DNS. The same connection succeeds if you use orbot to VPN the entire flutter app.

xAffan commented 6 months ago

here's me using the sample of tor plugin

Launching lib\main.dart on Windows in debug mode...
√  Built build\windows\x64\runner\Debug\main.exe.
Connecting to VM Service at ws://127.0.0.1:50397/ZLWv9PAmtXU=/ws
flutter: NOW: 2024-04-24 04:15:19.796316
flutter: Instance of Tor created!
Starting proxy!
flutter: Done awaiting; tor should be running
flutter: Starting tor took 261 seconds. Proxy running on port 43787
flutter: 192.42.116.199

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Failed host lookup: 'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion' (OS Error: No such host is known.

, errno = 11001)
#0      _NativeSocket.lookup.<anonymous closure> (dart:io-patch/socket_patch.dart:520:9)
<asynchronous suspension>
#1      SocksTCPClient.connect (package:socks5_proxy/src/client/socks_tcp_client.dart:66:18)
<asynchronous suspension>
#2      SocksTCPClient.assignToHttpClientWithSecureOptions.<anonymous closure> (package:socks5_proxy/src/client/socks_tcp_client.dart:46:40)
<asynchronous suspension>
#3      _ConnectionTarget.connect.<anonymous closure> (dart:_http/http_impl.dart:2490:32)
<asynchronous suspension>
#4      _HttpClient._openUrl.<anonymous closure> (dart:_http/http_impl.dart:2787:15)
<asynchronous suspension>
#5      _MyAppState.build.<anonymous closure> (package:main/main.dart:158:45)
<asynchronous suspension>

CHECK THE NEW TOR PLUGIN SAMPLE.

xAffan commented 6 months ago

You're wrong, prove me otherwise.

Hello, I believe you need to pass the hostname to the socks proxy rather than doing DNS resolution before. Not sure if it's possible?

LacticWhale commented 6 months ago

Ok I see the issue now, sorry for ignoring you. I will look into it today.

sneurlax commented 6 months ago

here's me using the sample of tor plugin ... CHECK THE NEW TOR PLUGIN SAMPLE.

I worked on this tor plugin (Foundation-Devices/tor) and made that example. I'm not sure that the arti which that package uses actually supports .onion addresses. You might want to check with an actual Tor proxy--not arti, which hasn't achieved feature-parity with legacy Tor yet.

This is why Stack Wallet's tor plugin (cypherstack/tor) explicitly does not support .onion addresses until The Tor Project officially announces that arti has achieved parity safely.

But that's not to invalidate any of what you said, just a note that if I were you, I wouldn't try my work without verifying it with an outside and verified working Tor proxy.

xAffan commented 6 months ago

here's me using the sample of tor plugin ... CHECK THE NEW TOR PLUGIN SAMPLE.

I worked on this tor plugin (Foundation-Devices/tor) and made that example. I'm not sure that the arti which that package uses actually supports .onion addresses. You might want to check with an actual Tor proxy--not arti, which hasn't achieved feature-parity with legacy Tor yet.

This is why Stack Wallet's tor plugin (cypherstack/tor) explicitly does not support .onion addresses until The Tor Project officially announces that arti has achieved parity safely.

But that's not to invalidate any of what you said, just a note that if I were you, I wouldn't try my work without verifying it with an outside and verified working Tor proxy.

When I originally opened the issue, I used the original tor proxy. Therefore, it is most likely an issue here.

nns52k commented 6 months ago

I worked on this tor plugin (Foundation-Devices/tor) and made that example. I'm not sure that the arti which that package uses actually supports .onion addresses. You might want to check with an actual Tor proxy--not arti, which hasn't achieved feature-parity with legacy Tor yet.

I asked Copilot "Does arti support TLD .onion?" and it replied:

[1]: https://blog.torproject.org/arti_119_released/ "" [2]: https://blog.torproject.org/arti_116_released/ "" [3]: https://blog.torproject.org/arti_1_2_0_released/ "" [4]: https://forum.torproject.org/t/arti-1-1-9-is-released-assembling-the-onions/9574 ""

Yes, Arti, the next-generation Tor client written in Rust, does support the .onion top-level domain (TLD). As of the Arti 1.1.6 release, Arti has working client-side onion service support¹[2]. This means that programs can use Arti to connect to onion services on the Tor network¹[2].

However, it's important to note that this feature was initially not as secure as the equivalent feature in the C tor implementation¹[2]. Therefore, it was disabled by default and had to be manually enabled¹[2].

As of the Arti 1.1.9 release, the support for onion services in Arti has been further developed²[1]. The code needed to publish onion service descriptors, keep them up-to-date with changes and introduction points, receive, decrypt, process, and answer introduction requests, and respond to them by delivering traffic to local ports is now available²[1].

In the Arti 1.2.0 release, trying out onion services was expected to be a smoother experience³[3]. Please check the latest documentation for the most up-to-date information.

Source: Conversation with Bing, 4/25/2024 (1) Arti 1.1.6 is released: Now you can connect* to Onion Services!. https://blog.torproject.org/arti_116_released/. (2) Arti 1.1.9 is released: Assembling the onions | Tor Project. https://blog.torproject.org/arti_119_released/. (3) Arti 1.2.0 is released: onion services development | Tor Project. https://blog.torproject.org/arti_1_2_0_released/. (4) Arti 1.1.9 is released: Assembling the onions. https://forum.torproject.org/t/arti-1-1-9-is-released-assembling-the-onions/9574.

nns52k commented 6 months ago

1 SocksTCPClient.connect (package:socks5_proxy/src/client/socks_tcp_client.dart:66:18)

2 SocksTCPClient.assignToHttpClientWithSecureOptions. (package:socks5_proxy/src/client/socks_tcp_client.dart:46:40)

3 _ConnectionTarget.connect. (dart:_http/http_impl.dart:2490:32)

4 _HttpClient._openUrl. (dart:_http/http_impl.dart:2787:15)

5 _MyAppState.build. (package:main/main.dart:158:45)

I got stuck in this too. SocksTCPClient.connect tries to DNS lookup an .onion domain name. It shall let Tor router do it instead of DNS lookup by itself, which is mentioned in Tor Project: FAQ.

LacticWhale commented 6 months ago

Why can't you resolve domain name before SocksTCPClient.connect? Can you write some example code so it's easier for me to understand the problem.

xAffan commented 6 months ago

Why can't you resolve domain name before SocksTCPClient.connect? Can you write some example code so it's easier for me to understand the problem.

Normal DNS servers such as 1.1.1.1/8.8.8.8 or your ISP's DNS servers do not know about any .onion hosts. Therefore, the hostname must be forwarded to the tor proxy so that the proxy itself can resolve those hosts using its own DNS servers.

LacticWhale commented 6 months ago

If you having problem with client I am unable to see there issue can be but if problem is that server can't resolve dns than:

  // Listen to all tcp and udp connections
  proxy.connections.listen((connection) async {
    print('${connection.address.address}:${connection.port} ==> ${connection.desiredAddress.address}:${connection.desiredPort}');
    // Resolve ip address manually.
    if (connection.desiredAddress.type == InternetAddressType.unix)
      connection.desiredAddress = (await InternetAddress.lookup(connection.desiredAddress.host)).first;

    // Apply default handler
    await connection.forward();
  }).onError(print);

Sorry for not understanding you but I really don't see it.

xAffan commented 6 months ago

I'll explain this. There is an onion website (for example duckduckgo) whose address is duckduckgo.onion (just an example - not real).

Now, when we attempt to convert this address to an IP address, it fails because such a domain simply does not exist according to the DNS (Domain Name Server).

This is because .onion addresses can only be resolved by tor not a normal DNS.

Therefore, we must directly forward the domain name as is, so the tor proxy itself can then correctly convert it into an IP address and establish a connection.

An option to use the socks proxy for DNS resolution can be added so normal usage will stay unaffected.

The lookup code you sent is problematic, I believe. Maybe, temporarily commenting it out for testing might get us somewhere.

nns52k commented 6 months ago

@LacticWhale Thanks for developing package `socks5_proxy'.

In Tor Project: FAQ, it basically says that the applications that use Tor proxy usually make a mistake to DNS lookup .onion domain name and fail. No DNS servers support TLD .onion. The TLD .onion is specific to Tor network.

In ~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/client/socks_tcp_client.dart, the definition of method SocksTCPClient.connect is:

  /// Connects proxy client to given [proxies] with exit point of [host]\:[port].
  static Future<SocksSocket> connect(
    List<ProxySettings> proxies,
    InternetAddress host,
    int port,
  ) async {
    final InternetAddress address;
    if(host.type == InternetAddressType.unix)
      address = (await InternetAddress.lookup(host.address))[0];
    else 
      address = host;

    final client = await SocksSocket.initialize(proxies, address, port, SocksConnectionType.connect);
    return client.socket;
  }

in which the code line address = (await InternetAddress.lookup(host.address))[0]; tries to DNS lookup. In our case of trying to access an onion server, e.g. https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/, the code definitely will fail because .onion is not a valid TLD for ordinary DNS servers.

The FAQ suggests us to leave the .onion domain name alone, and let Tor proxy deal with it.

nns52k commented 6 months ago

The lookup code you sent is problematic, I believe. Maybe, temporarily commenting it out for testing might get us somewhere.

I've tried commenting it out. It will lead to other problems. Normal website, e.g. https://icanhazip.com/ mentioned in the example of package tor-0.0.3, seems to require the DNS lookup, but I don't know why it is required.

xAffan commented 6 months ago

The lookup code you sent is problematic, I believe. Maybe, temporarily commenting it out for testing might get us somewhere.

I've tried commenting it out. It will lead to other problems. Normal website, e.g. https://icanhazip.com/ mentioned in the example of package tor-0.0.3, seems to require the DNS lookup, but I don't know why it is required.

So, in a simple sense, normal websites require DNS lookup, and won't work after forwarding it to the tor proxy? Have you verified if .onion sites work? If so, a suboptimal compromise would be to add a condition to see if the address is .onion, and forward it, if an option like forwardOnion: true is enabled?

LacticWhale commented 6 months ago

I check and it seems like that DNS lookup was absolutely necessary. Pushed a small patch 69f23b8

If it doesn't help open this issue again.

nns52k commented 6 months ago

@xAffan

So, in a simple sense, normal websites require DNS lookup, and won't work after forwarding it to the tor proxy?

I asked Copilot yesterday about the difference among SOCKS 4, SOCKS 4a and SOCKS 5.

Copilot said SOCKS 4 only accepts IPv4 address. I guess it's why most applications do DNS lookup first by themselves and then pass the IPv4 address they get from DNS servers to SOCKS 4 proxy.

SOCKS 4a accepts both IPv4 address and domain name.

SOCKS 5 accepts IPv4 address, domain name and IPv6 address. Though we are in the era of SOCKS 5, most applications still do DNS lookup themselves, in spite of the fact that a SOCKS 5 proxy, e.g. Tor proxy, is supposed to be able to deal with DNS lookup.

Have you verified if .onion sites work?

I tried the DuckDuckGo .onion mentioned above, and failed because of a RangeError being thrown. The call stack where it throws is:

ByteReader.readBytes (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/mixin/byte_reader.dart:33)
<asynchronous gap> (Unknown Source:0)
ByteReader.readUint8 (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/mixin/byte_reader.dart:18)
<asynchronous gap> (Unknown Source:0)
SocksSocket._handleCommandResponse (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/client/socks_client.dart:189)
<asynchronous gap> (Unknown Source:0)
SocksSocket.initialize (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/client/socks_client.dart:74)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.connect (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/client/socks_tcp_client.dart:70)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.assignToHttpClientWithSecureOptions.<anonymous closure> (~/.pub-cache/hosted/pub.dev/socks5_proxy-1.0.4/lib/src/client/socks_tcp_client.dart:46)
<asynchronous gap> (Unknown Source:0)
_ConnectionTarget.connect.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2490)
<asynchronous gap> (Unknown Source:0)
_HttpClient._openUrl.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2787)
<asynchronous gap> (Unknown Source:0)
IOClient.send (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/io_client.dart:117)
<asynchronous gap> (Unknown Source:0)
BaseClient._sendUnstreamed (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/base_client.dart:93)
<asynchronous gap> (Unknown Source:0)

The message of the RangeError is "_readBytes has fewer bytes than expected." It looks like package socks5_proxy would check the message or something that is about to be sent to proxy, but I'm not sure.

nns52k commented 6 months ago

@LacticWhale

I check and it seems like that DNS lookup was absolutely necessary. Pushed a small patch 69f23b8

If it doesn't help open this issue again.

Thess 3 simple functions can be used to test:

import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:tor/tor.dart';
import 'package:socks_dart/socks_client.dart'; // the socks5_proxy 1.0.5+dev.1

Future<Client> createProxyClient() async {
  final httpClient = HttpClient()
    ..badCertificateCallback = ((X509Certificate cert, String host, int port) {
      print('Issuer: ${cert.issuer}\nSubject: ${cert.subject}\nPEM: ${cert.pem}\nHost: $host\nPort: $port');
      return true;
    });

  Tor.init();
  final DateTime t1 = DateTime.now();
  await Tor.instance.start();
  print('It took ${DateTime.now().difference(t1).inSeconds} seconds to connect Tor network.');

  SocksTCPClient.assignToHttpClient(httpClient, [
      ProxySettings(InternetAddress.loopbackIPv4, Tor.instance.port),
  ]);

  return IOClient(httpClient);
}

Future<void> printIpAddressOfExitNode(Client client) async {
  final Response response = await client.get(Uri.parse('https://icanhazip.com/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

Future<void> accessHiddenDuckDuckGo(Client client) async {
  final Response response = await client.get(Uri.parse('https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

They are to be called like:

final Client client = await createProxyClient();
await printIpAddressOfExitNode(client);
await accessHiddenDuckDuckGo(client);

The patch 69f23b8 will have both functions printIpAddressOfExitNode and accessHiddenDuckDuckGo fail because of a RangeError thrown. The message of the RangeError is _readBytes has fewer bytes than expected.. The call stack when it throws is:

ByteReader.readBytes (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:33)
<asynchronous gap> (Unknown Source:0)
ByteReader.readUint8 (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:18)
<asynchronous gap> (Unknown Source:0)
SocksSocket._handleCommandResponse (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:189)
<asynchronous gap> (Unknown Source:0)
SocksSocket.initialize (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:74)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.connect (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:64)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.assignToHttpClientWithSecureOptions.<anonymous closure> (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:46)
<asynchronous gap> (Unknown Source:0)
_ConnectionTarget.connect.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2490)
<asynchronous gap> (Unknown Source:0)
_HttpClient._openUrl.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2787)
<asynchronous gap> (Unknown Source:0)
IOClient.send (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/io_client.dart:117)
<asynchronous gap> (Unknown Source:0)
BaseClient._sendUnstreamed (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/base_client.dart:93)
<asynchronous gap> (Unknown Source:0)
printIpAddressOfExitNode (~/codes/experiments/tor/project1/lib/main.dart:53)
<asynchronous gap> (Unknown Source:0)
main (~/codes/experiments/tor/project1/lib/main.dart:13)
<asynchronous gap> (Unknown Source:0)
xAffan commented 6 months ago

@LacticWhale

I check and it seems like that DNS lookup was absolutely necessary. Pushed a small patch 69f23b8

If it doesn't help open this issue again.

Thess 3 simple functions can be used to test:

import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:tor/tor.dart';
import 'package:socks_dart/socks_client.dart'; // the socks5_proxy 1.0.5+dev.1

Future<Client> createProxyClient() async {
  final httpClient = HttpClient()
    ..badCertificateCallback = ((X509Certificate cert, String host, int port) {
      print('Issuer: ${cert.issuer}\nSubject: ${cert.subject}\nPEM: ${cert.pem}\nHost: $host\nPort: $port');
      return true;
    });

  Tor.init();
  final DateTime t1 = DateTime.now();
  await Tor.instance.start();
  print('It took ${DateTime.now().difference(t1).inSeconds} seconds to connect Tor network.');

  SocksTCPClient.assignToHttpClient(httpClient, [
      ProxySettings(InternetAddress.loopbackIPv4, Tor.instance.port),
  ]);

  return IOClient(httpClient);
}

Future<void> printIpAddressOfExitNode(Client client) async {
  final Response response = await client.get(Uri.parse('https://icanhazip.com/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

Future<void> accessHiddenDuckDuckGo(Client client) async {
  final Response response = await client.get(Uri.parse('https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

They are to be called like:

final Client client = await createProxyClient();
await printIpAddressOfExitNode(client);
await accessHiddenDuckDuckGo(client);

The patch 69f23b8 will have both functions printIpAddressOfExitNode and accessHiddenDuckDuckGo fail because of a RangeError thrown. The message of the RangeError is _readBytes has fewer bytes than expected.. The call stack when it throws is:

ByteReader.readBytes (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:33)
<asynchronous gap> (Unknown Source:0)
ByteReader.readUint8 (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:18)
<asynchronous gap> (Unknown Source:0)
SocksSocket._handleCommandResponse (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:189)
<asynchronous gap> (Unknown Source:0)
SocksSocket.initialize (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:74)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.connect (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:64)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.assignToHttpClientWithSecureOptions.<anonymous closure> (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:46)
<asynchronous gap> (Unknown Source:0)
_ConnectionTarget.connect.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2490)
<asynchronous gap> (Unknown Source:0)
_HttpClient._openUrl.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2787)
<asynchronous gap> (Unknown Source:0)
IOClient.send (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/io_client.dart:117)
<asynchronous gap> (Unknown Source:0)
BaseClient._sendUnstreamed (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/base_client.dart:93)
<asynchronous gap> (Unknown Source:0)
printIpAddressOfExitNode (~/codes/experiments/tor/project1/lib/main.dart:53)
<asynchronous gap> (Unknown Source:0)
main (~/codes/experiments/tor/project1/lib/main.dart:13)
<asynchronous gap> (Unknown Source:0)

Perhaps, the issue must be reopened(?) although the host resolution error is resolved, the range error must be investigated in byte_reader.dart(?)

nns52k commented 6 months ago

@xAffan

Perhaps, the issue must be reopened(?) although the host resolution error is resolved, the range error must be investigated in byte_reader.dart(?)

Yes, please reopen it. It looks like only the person who created the issue and the author of the Git repository are able to do that. I cannot find any button in this webpage to reopen this issue.

Re-edit: Before applying the patch 69f23b8, the function printIpAddressOfExitNode above can run without any problem. The IPv4 address of the exit node will be printed on terminal. After applying the patch, the function fails.

xAffan commented 6 months ago

@LacticWhale

I check and it seems like that DNS lookup was absolutely necessary. Pushed a small patch 69f23b8

If it doesn't help open this issue again.

Thess 3 simple functions can be used to test:

import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:tor/tor.dart';
import 'package:socks_dart/socks_client.dart'; // the socks5_proxy 1.0.5+dev.1

Future<Client> createProxyClient() async {
  final httpClient = HttpClient()
    ..badCertificateCallback = ((X509Certificate cert, String host, int port) {
      print('Issuer: ${cert.issuer}\nSubject: ${cert.subject}\nPEM: ${cert.pem}\nHost: $host\nPort: $port');
      return true;
    });

  Tor.init();
  final DateTime t1 = DateTime.now();
  await Tor.instance.start();
  print('It took ${DateTime.now().difference(t1).inSeconds} seconds to connect Tor network.');

  SocksTCPClient.assignToHttpClient(httpClient, [
      ProxySettings(InternetAddress.loopbackIPv4, Tor.instance.port),
  ]);

  return IOClient(httpClient);
}

Future<void> printIpAddressOfExitNode(Client client) async {
  final Response response = await client.get(Uri.parse('https://icanhazip.com/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

Future<void> accessHiddenDuckDuckGo(Client client) async {
  final Response response = await client.get(Uri.parse('https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/'));
  print('STATUS: ${response.statusCode}\nRESPONSE: ${response.body}');
}

They are to be called like:

final Client client = await createProxyClient();
await printIpAddressOfExitNode(client);
await accessHiddenDuckDuckGo(client);

The patch 69f23b8 will have both functions printIpAddressOfExitNode and accessHiddenDuckDuckGo fail because of a RangeError thrown. The message of the RangeError is _readBytes has fewer bytes than expected.. The call stack when it throws is:

ByteReader.readBytes (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:33)
<asynchronous gap> (Unknown Source:0)
ByteReader.readUint8 (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/mixin/byte_reader.dart:18)
<asynchronous gap> (Unknown Source:0)
SocksSocket._handleCommandResponse (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:189)
<asynchronous gap> (Unknown Source:0)
SocksSocket.initialize (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_client.dart:74)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.connect (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:64)
<asynchronous gap> (Unknown Source:0)
SocksTCPClient.assignToHttpClientWithSecureOptions.<anonymous closure> (~/.pub-cache/hosted/pub.dev/socks_dart/lib/src/client/socks_tcp_client.dart:46)
<asynchronous gap> (Unknown Source:0)
_ConnectionTarget.connect.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2490)
<asynchronous gap> (Unknown Source:0)
_HttpClient._openUrl.<anonymous closure> (~/.local/packages/flutter/bin/cache/pkg/sky_engine/lib/_http/http_impl.dart:2787)
<asynchronous gap> (Unknown Source:0)
IOClient.send (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/io_client.dart:117)
<asynchronous gap> (Unknown Source:0)
BaseClient._sendUnstreamed (~/.pub-cache/hosted/pub.dev/http-1.2.1/lib/src/base_client.dart:93)
<asynchronous gap> (Unknown Source:0)
printIpAddressOfExitNode (~/codes/experiments/tor/project1/lib/main.dart:53)
<asynchronous gap> (Unknown Source:0)
main (~/codes/experiments/tor/project1/lib/main.dart:13)
<asynchronous gap> (Unknown Source:0)

Perhaps, the issue must be reopened(?) although the host resolution error is resolved, the range error must be investigated in byte_reader.dart(?)

I thought about this. Since normal websites are now also throwing a range error as indicated by @nns52k . That must mean there is some kind of oversight introduced that affects all the websites not just .onion ones. This might be an urgent issue since you can't connect to any website anymore (?)

xAffan commented 6 months ago

@xAffan

Perhaps, the issue must be reopened(?) although the host resolution error is resolved, the range error must be investigated in byte_reader.dart(?)

Yes, please reopen it. It looks like only the person who created the issue and the author of the Git repository are able to do that. I cannot find any button in this webpage to reopen this issue.

Re-edit: Before applying the patch 69f23b8, the function printIpAddressOfExitNode above can run without any problem. The IPv4 address of the exit node will be printed on terminal. After applying the patch, the function fails.

I don't find an option to reopen the issue as well. It seems only the author of the repo is able to open the issue again. I suggest you open a brand new issue with the recent findings

LacticWhale commented 6 months ago

@nns52k

Tor.init();

Have you tried to add await here. I am not able to set up dev environment.

nns52k commented 6 months ago

@nns52k

Tor.init();

Have you tried to add await here. I am not able to set up dev environment.

Yes, the result is the same.

What does "not able to set up dev environment" mean? Could you be more specific so I probably can help?

LacticWhale commented 6 months ago

Could you be more specific so I probably can help?

Time. Ok I will go look more closely at problem.

sneurlax commented 6 months ago

@nns52k @xAffan once this is patched we should PR an example of onion address lookups into the Foundation-Devices/tor example. If you don't want to do it, I will. I'm not directly responsible for that but will review it and it should be merged...

You'll notice I had to write https://github.com/Foundation-Devices/tor/blob/main/lib/socks_socket.dart (spun out into its own package as https://github.com/sneurlax/socks_socket) to get SOCKS over sockets working for eg. electrumx and fulcrum nodes. I want to make sure that class can handle onion address lookups etc., too, so we're ready for when Arti announces security parity for hidden services usage.

xAffan commented 6 months ago

@nns52k @xAffan once this is patched we should PR an example of onion address lookups into the Foundation-Devices/tor. If you don't want to do it, I will. I'm not directly responsible for that but will review it and it should be merged...

You'll notice I had to write https://github.com/Foundation-Devices/tor/blob/main/lib/socks_socket.dart (spun out into its own package as https://github.com/sneurlax/socks_socket) to get SOCKS over sockets working for eg. electrumx and fulcrum nodes. I want to make sure that class can handle onion address lookups etc., too, so we're ready for when Arti announces security parity for hidden services usage.

I will make a PR once this is resolved, no worries.

LacticWhale commented 6 months ago

@xAffan ok I tested few things.

  1. RangeError happene because SOCKS server closed conection before sending response signal which is normal behaviour and will be handled properly in next release.
  2. I run following code using ssh SOCKS5 server:
    
    import 'dart:convert';
    import 'dart:io';

import 'package:socks5_proxy/socks_client.dart';

void main() async { // Create HttpClient object final client = HttpClient();

// Assign connection factory SocksTCPClient.assignToHttpClient(client, [ ProxySettings(InternetAddress.loopbackIPv4, 27462), ]);

try { // GET request final request = await client.getUrl(Uri.parse('http://example.onion/')); final response = await request.close(); // Print response print(await utf8.decodeStream(response)); // Close client client.close(); } catch (e, stackTrace) { print(e); print(stackTrace); } finally { client.close(); } }

And in terminal I got:

debug1: channel 2: free: direct-tcpip: listening port 27462 for example.onion port 80, connect from 127.0.0.1 port 63526 to 127.0.0.1 port 27462, nchannels 3 debug1: Connection to port 27462 forwarding to socks port 0 requested. debug1: channel 2: new [dynamic-tcpip] channel 2: open failed: connect failed: Name or service not known



That means client send host as is but server wasn't able to resolve it. 

For now you can try to catch RangeError (which is not really good).

I wan't able to run tor proxy but if you could send me server logs after running my example above it whould be really helpful.
sneurlax commented 6 months ago

@LacticWhale, does the https://github.com/Foundation-Devices/tor example run for you? It should work on every platform and should run a tor proxy for you. You don't have to access it via Flutter, either, it's generally accessible at localhost:port for the whole system

LacticWhale commented 6 months ago

@sneurlax it doesn't run without flutter and it doesn't run with flutter either. Maybe I am not doing somethin wrong but it always stuck at "Starting tor..." dialog. image image

xAffan commented 6 months ago

@sneurlax it doesn't run without flutter and it doesn't run with flutter either. Maybe I am not doing somethin wrong but it always stuck at "Starting tor..." dialog. image image

It takes a long time to start (at least when i tested it for the first time). And currently there are no progress messages so it seems like it is stuck but it does work at the end

xAffan commented 6 months ago

@xAffan ok I tested few things.

  1. RangeError happene because SOCKS server closed conection before sending response signal which is normal behaviour and will be handled properly in next release.
  2. I run following code using ssh SOCKS5 server:
    
    import 'dart:convert';
    import 'dart:io';

import 'package:socks5_proxy/socks_client.dart';

void main() async { // Create HttpClient object final client = HttpClient();

// Assign connection factory SocksTCPClient.assignToHttpClient(client, [ ProxySettings(InternetAddress.loopbackIPv4, 27462), ]);

try { // GET request final request = await client.getUrl(Uri.parse('http://example.onion/')); final response = await request.close(); // Print response print(await utf8.decodeStream(response)); // Close client client.close(); } catch (e, stackTrace) { print(e); print(stackTrace); } finally { client.close(); } }

And in terminal I got:

debug1: channel 2: free: direct-tcpip: listening port 27462 for example.onion port 80, connect from 127.0.0.1 port 63526 to 127.0.0.1 port 27462, nchannels 3 debug1: Connection to port 27462 forwarding to socks port 0 requested. debug1: channel 2: new [dynamic-tcpip] channel 2: open failed: connect failed: Name or service not known



That means client send host as is but server wasn't able to resolve it. 

For now you can try to catch RangeError (which is not really good).

I wan't able to run tor proxy but if you could send me server logs after running my example above it whould be really helpful.

Is this the correct output?

$ curl -x socks5h://localhost:9050 -s https://check.torproject.org/api/ip
{"IsTor":true,"IP":"185.220.100.254"}$
$ dart run
Building package executable...
Built tor_test:tor_test.
Exception: Command handling failed. With error: serverError
#0      SocksSocket._handleCommandResponse (package:socks5_proxy/src/client/socks_client.dart:196:7)
<asynchronous suspension>
#1      SocksSocket.initialize (package:socks5_proxy/src/client/socks_client.dart:74:22)
<asynchronous suspension>
#2      SocksTCPClient.connect (package:socks5_proxy/src/client/socks_tcp_client.dart:64:20)
<asynchronous suspension>
#3      _ConnectionTarget.connect.<anonymous closure>.<anonymous closure> (dart:_http/http_impl.dart:2497:32)
<asynchronous suspension>
#4      _HttpClient._openUrl.<anonymous closure> (dart:_http/http_impl.dart:2787:15)
<asynchronous suspension>
#5      main (file:///home/user/TestD/tor_test/bin/tor_test.dart:17:17)
<asynchronous suspension>
$ cat ./bin/tor_test.dart
import 'dart:convert';
import 'dart:io';
import 'package:socks5_proxy/socks_client.dart';
void main() async {
// Create HttpClient object
final client = HttpClient();
// Assign connection factory
SocksTCPClient.assignToHttpClient(client, [
  ProxySettings(InternetAddress.loopbackIPv4, 9050),
]);
try {
// GET request
final request = await client.getUrl(Uri.parse('http://example.onion/'));
final response = await request.close();
// Print response
print(await utf8.decodeStream(response));
// Close client
client.close();
} catch (e, stackTrace) {
  print(e);
  print(stackTrace);
} finally {
  client.close();
}
}

If flutter is needed, I can't test right now

xAffan commented 6 months ago

@xAffan ok I tested few things.

  1. RangeError happene because SOCKS server closed conection before sending response signal which is normal behaviour and will be handled properly in next release.
  2. I run following code using ssh SOCKS5 server:
    
    import 'dart:convert';
    import 'dart:io';

import 'package:socks5_proxy/socks_client.dart';

void main() async { // Create HttpClient object final client = HttpClient();

// Assign connection factory SocksTCPClient.assignToHttpClient(client, [ ProxySettings(InternetAddress.loopbackIPv4, 27462), ]);

try { // GET request final request = await client.getUrl(Uri.parse('http://example.onion/')); final response = await request.close(); // Print response print(await utf8.decodeStream(response)); // Close client client.close(); } catch (e, stackTrace) { print(e); print(stackTrace); } finally { client.close(); } }

And in terminal I got:

debug1: channel 2: free: direct-tcpip: listening port 27462 for example.onion port 80, connect from 127.0.0.1 port 63526 to 127.0.0.1 port 27462, nchannels 3 debug1: Connection to port 27462 forwarding to socks port 0 requested. debug1: channel 2: new [dynamic-tcpip] channel 2: open failed: connect failed: Name or service not known



That means client send host as is but server wasn't able to resolve it. 

For now you can try to catch RangeError (which is not really good).

I wan't able to run tor proxy but if you could send me server logs after running my example above it whould be really helpful.

Is this the correct output?

$ curl -x socks5h://localhost:9050 -s https://check.torproject.org/api/ip
{"IsTor":true,"IP":"185.220.100.254"}$
$ dart run
Building package executable...
Built tor_test:tor_test.
Exception: Command handling failed. With error: serverError
#0      SocksSocket._handleCommandResponse (package:socks5_proxy/src/client/socks_client.dart:196:7)
<asynchronous suspension>
#1      SocksSocket.initialize (package:socks5_proxy/src/client/socks_client.dart:74:22)
<asynchronous suspension>
#2      SocksTCPClient.connect (package:socks5_proxy/src/client/socks_tcp_client.dart:64:20)
<asynchronous suspension>
#3      _ConnectionTarget.connect.<anonymous closure>.<anonymous closure> (dart:_http/http_impl.dart:2497:32)
<asynchronous suspension>
#4      _HttpClient._openUrl.<anonymous closure> (dart:_http/http_impl.dart:2787:15)
<asynchronous suspension>
#5      main (file:///home/user/TestD/tor_test/bin/tor_test.dart:17:17)
<asynchronous suspension>
$ cat ./bin/tor_test.dart
import 'dart:convert';
import 'dart:io';
import 'package:socks5_proxy/socks_client.dart';
void main() async {
// Create HttpClient object
final client = HttpClient();
// Assign connection factory
SocksTCPClient.assignToHttpClient(client, [
  ProxySettings(InternetAddress.loopbackIPv4, 9050),
]);
try {
// GET request
final request = await client.getUrl(Uri.parse('http://example.onion/'));
final response = await request.close();
// Print response
print(await utf8.decodeStream(response));
// Close client
client.close();
} catch (e, stackTrace) {
  print(e);
  print(stackTrace);
} finally {
  client.close();
}
}

If flutter is needed, I can't test right now

After replacing with a valid onion address. Example https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ it actually worked!

xAffan commented 6 months ago

I believe it is good.

$ dart run
Building package executable...
Built tor_test:tor_test.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
   <TITLE>Welcome to web-dal-08!</TITLE>
</HEAD>
<BODY>
<H1>Welcome to web-dal-08!</H1>
This is web-dal-08, a system run by and for the <a href="http://www.torproject.org/">Tor Project</a>.
She does stuff.
What kind of stuff and who our kind sponsors are you might learn on
<a href="http://db.torproject.org/machines.cgi?host=web-dal-08">db.torproject.org</a>.
<P>
<HR NOSHADE />
<FONT size="-1">torproject-admin</FONT>
</BODY>
</HTML>
$

Onion address used: http://check.2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/

LacticWhale commented 6 months ago

Can I close the issue now? I will add proper exception handling later.

nns52k commented 6 months ago

@sneurlax @xAffan

If flutter is needed, I can't test right now

Is it possible to remove flutter from dependency list of package tor? If "yes", CLI programs could use package tor too.

sneurlax commented 6 months ago

@sneurlax @xAffan

If flutter is needed, I can't test right now

Is it possible to remove flutter from dependency list of package tor? If "yes", CLI programs could use package tor too.

I would recommend making an issue at https://github.com/Foundation-Devices/tor asking for/requesting this feature. I'm not sure if the plugin structure requires flutter (it might)

xAffan commented 3 months ago

opened by mistake due to an issue on my local system