diff --git a/example/lib/main.dart b/example/lib/main.dart index 77a70d0..254e385 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,16 +3,17 @@ // // SPDX-License-Identifier: MIT -// Example app deps, not necessarily needed for tor usage. +// Flutter dependencies not necessarily needed for tor usage: import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; -// Imports needed for tor usage: -import 'package:socks5_proxy/socks_client.dart'; // Just for example; can use any socks5 proxy package, pick your favorite. -import 'package:tor/tor.dart'; -import 'package:tor/socks_socket.dart'; // For socket connections +// Example application dependencies you can replace with any that works for you: +import 'package:socks5_proxy/socks_client.dart'; +import 'package:tor/socks_socket.dart'; +// The only real import needed for basic usage: +import 'package:tor/tor.dart'; // This would go at the top, but dart autoformatter doesn't like it there. void main() { runApp(const MyApp()); @@ -44,6 +45,8 @@ class _MyAppState extends State { final hostController = TextEditingController(text: 'https://icanhazip.com/'); // https://check.torproject.org is another good option. + String? exitNodeAddress; + Future startTor() async { await Tor.init(); @@ -56,6 +59,24 @@ class _MyAppState extends State { }); print('Done awaiting; tor should be running'); + + // Fetch the exit node address. + try { + String? address = await Tor.instance.getExitNode(); + // getExitNode above should return like: [1.2.3.4:5 ed25519:Q6+... $7...] + setState(() { + if (address != null && address!.contains(":")) { + // Strip just the IP out of the above. + address = address?.split(":")[0].substring(1); + } + exitNodeAddress = address; + }); + } catch (e) { + print('Error getting exit node address: $e'); + setState(() { + exitNodeAddress = 'Error retrieving exit node address'; + }); + } } @override @@ -123,6 +144,14 @@ class _MyAppState extends State { }, child: const Text("Stop"), ), + // Display the exit node address. + if (exitNodeAddress != null) ...[ + spacerSmall, + Text( + 'Exit Node: $exitNodeAddress', + style: const TextStyle(fontSize: 16), + ), + ], ], ), Row( diff --git a/example/pubspec.lock b/example/pubspec.lock index 3479fa2..b39cfcc 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -278,7 +278,7 @@ packages: path: ".." relative: true source: path - version: "0.0.7" + version: "0.0.8" vector_math: dependency: transitive description: diff --git a/ffigen.yaml b/ffigen.yaml index 62108b0..3b7d098 100644 --- a/ffigen.yaml +++ b/ffigen.yaml @@ -8,7 +8,7 @@ description: | Bindings for `tor.h`. Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. -output: 'lib/tor_bindings_generated.dart' +output: 'lib/generated_bindings.dart' headers: entry-points: - 'rust/target/tor.h' diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index b5b15a5..97ca4d6 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -2,12 +2,20 @@ // // SPDX-License-Identifier: MIT +// ignore_for_file: always_specify_types +// ignore_for_file: camel_case_types +// ignore_for_file: non_constant_identifier_names + // AUTO GENERATED FILE, DO NOT EDIT. // // Generated by `package:ffigen`. // ignore_for_file: type=lint import 'dart:ffi' as ffi; +/// Bindings for `tor.h`. +/// +/// Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +/// class NativeLibrary { /// Holds the symbol lookup function. final ffi.Pointer Function(String symbolName) @@ -87,6 +95,39 @@ class NativeLibrary { late final _tor_proxy_stop = _tor_proxy_stopPtr.asFunction)>(); + /// Get the exit node's identity (e.g., nickname or ID) for the given client. + ffi.Pointer tor_get_exit_node( + ffi.Pointer client, + ) { + return _tor_get_exit_node( + client, + ); + } + + late final _tor_get_exit_nodePtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('tor_get_exit_node'); + late final _tor_get_exit_node = _tor_get_exit_nodePtr + .asFunction Function(ffi.Pointer)>(); + + /// Free a C string allocated by this library. + /// + /// Used to free memory allocated by functions like `tor_get_exit_node`. + void tor_free_string( + ffi.Pointer s, + ) { + return _tor_free_string( + s, + ); + } + + late final _tor_free_stringPtr = + _lookup)>>( + 'tor_free_string'); + late final _tor_free_string = + _tor_free_stringPtr.asFunction)>(); + void tor_hello() { return _tor_hello(); } @@ -135,141 +176,3 @@ final class Tor extends ffi.Struct { external ffi.Pointer proxy; } - -const int true1 = 1; - -const int false1 = 0; - -const int INT8_MIN = -128; - -const int INT16_MIN = -32768; - -const int INT32_MIN = -2147483648; - -const int INT64_MIN = -9223372036854775808; - -const int INT8_MAX = 127; - -const int INT16_MAX = 32767; - -const int INT32_MAX = 2147483647; - -const int INT64_MAX = 9223372036854775807; - -const int UINT8_MAX = 255; - -const int UINT16_MAX = 65535; - -const int UINT32_MAX = 4294967295; - -const int UINT64_MAX = -1; - -const int INT_LEAST8_MIN = -128; - -const int INT_LEAST16_MIN = -32768; - -const int INT_LEAST32_MIN = -2147483648; - -const int INT_LEAST64_MIN = -9223372036854775808; - -const int INT_LEAST8_MAX = 127; - -const int INT_LEAST16_MAX = 32767; - -const int INT_LEAST32_MAX = 2147483647; - -const int INT_LEAST64_MAX = 9223372036854775807; - -const int UINT_LEAST8_MAX = 255; - -const int UINT_LEAST16_MAX = 65535; - -const int UINT_LEAST32_MAX = 4294967295; - -const int UINT_LEAST64_MAX = -1; - -const int INT_FAST8_MIN = -128; - -const int INT_FAST16_MIN = -9223372036854775808; - -const int INT_FAST32_MIN = -9223372036854775808; - -const int INT_FAST64_MIN = -9223372036854775808; - -const int INT_FAST8_MAX = 127; - -const int INT_FAST16_MAX = 9223372036854775807; - -const int INT_FAST32_MAX = 9223372036854775807; - -const int INT_FAST64_MAX = 9223372036854775807; - -const int UINT_FAST8_MAX = 255; - -const int UINT_FAST16_MAX = -1; - -const int UINT_FAST32_MAX = -1; - -const int UINT_FAST64_MAX = -1; - -const int INTPTR_MIN = -9223372036854775808; - -const int INTPTR_MAX = 9223372036854775807; - -const int UINTPTR_MAX = -1; - -const int INTMAX_MIN = -9223372036854775808; - -const int INTMAX_MAX = 9223372036854775807; - -const int UINTMAX_MAX = -1; - -const int PTRDIFF_MIN = -9223372036854775808; - -const int PTRDIFF_MAX = 9223372036854775807; - -const int SIG_ATOMIC_MIN = -2147483648; - -const int SIG_ATOMIC_MAX = 2147483647; - -const int SIZE_MAX = -1; - -const int WCHAR_MIN = -2147483648; - -const int WCHAR_MAX = 2147483647; - -const int WINT_MIN = 0; - -const int WINT_MAX = 4294967295; - -const int NULL = 0; - -const int WNOHANG = 1; - -const int WUNTRACED = 2; - -const int WSTOPPED = 2; - -const int WEXITED = 4; - -const int WCONTINUED = 8; - -const int WNOWAIT = 16777216; - -const int RAND_MAX = 2147483647; - -const int EXIT_FAILURE = 1; - -const int EXIT_SUCCESS = 0; - -const int LITTLE_ENDIAN = 1234; - -const int BIG_ENDIAN = 4321; - -const int PDP_ENDIAN = 3412; - -const int BYTE_ORDER = 1234; - -const int FD_SETSIZE = 1024; - -const int NFDBITS = 64; diff --git a/lib/tor.dart b/lib/tor.dart index 5960118..cf1c54a 100644 --- a/lib/tor.dart +++ b/lib/tor.dart @@ -261,6 +261,27 @@ class Tor { })); } + /// Gets the current exit node. + Future getExitNode() async { + if (_clientPtr == nullptr || !started || !bootstrapped) { + throw ClientNotActive(); + } + + final lib = rust.NativeLibrary(_lib); + Pointer addressPtr = lib.tor_get_exit_node(_clientPtr); + + if (addressPtr == nullptr) { + String rustError = + lib.tor_last_error_message().cast().toDartString(); + throw Exception("Failed to get exit node: $rustError"); + } + + String address = addressPtr.cast().toDartString(); + lib.tor_free_string(addressPtr); + + return address; + } + static throwRustException(rust.NativeLibrary lib) { String rustError = lib.tor_last_error_message().cast().toDartString();