我正在构建一个flutter项目,我想在其中向一个.onion tor地址(REST API)发出GET请求。我找到了一个很好的库:(https://pub.dev/packages/utopic_tor_onion_proxy),它允许您这样做,我使用dart:io库来建立套接字连接。我可以成功地向如下地址发出GET请求:https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion(鸭子鸭子)。
但是当打开一个指向我自己的.onion地址的套接字时,代码失败了。这是因为我没有有效的TLS证书。是否可以在不使用TLS证书的情况下与dart:io库建立套接字连接?
代码im用于建立套接字连接(默认来自utopic_tor_onion_proxy库):
import 'dart:io';
if (uri.scheme == 'https') {
_socket = await SecureSocket.secure(
_socket!,
host: uri.authority,
);
我希望有这样的选项:
allowInsecureConnection = true,
同样的事情在Python这样的语言中也很容易实现,例如:
import requests
session = requests.session()
session.proxies = {'https': 'socks5h://localhost:9150'}
r = session.get(url, headers=headers, verify=False)
其中,verify=False可解决问题。
对于CURL,可以通过添加--insecure
但我找不到一种方法来做Flutter。
下面是我使用的代码:
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:utopic_tor_onion_proxy/utopic_tor_onion_proxy.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? _torLocalPort;
String? _error;
String? _responseString;
Socket? _socket;
Future<void> _startTor() async {
String? port;
try {
port = (await UtopicTorOnionProxy.startTor()).toString();
} on Exception catch (e) {
print(e);
_error = 'Failed to get port';
}
if (!mounted) return;
setState(() {
_torLocalPort = port;
});
}
Future<void> _stopTor() async {
try {
if (await (UtopicTorOnionProxy.stopTor() as FutureOr<bool>)) {
if (!mounted) return;
setState(() {
_torLocalPort = null;
});
}
} on PlatformException catch (e) {
print(e.message ?? '');
}
}
Future<void> _sendGetRequest(Uri uri) async {
if (mounted) {
setState(() {
_responseString = null;
});
}
_socket?.destroy();
_socket = await Socket.connect(
InternetAddress.loopbackIPv4,
int.tryParse(_torLocalPort!)!,
timeout: Duration(seconds: 5),
);
_socket!.setOption(SocketOption.tcpNoDelay, true);
_socksConnectionRequest(uri, _socket!);
List<int> responseIntList = [];
void onSocketDone() {
print('socket done');
if (mounted) {
setState(() {
_responseString = String.fromCharCodes(responseIntList);
});
}
}
_socket!.listen((event) async {
if (event.length == 8 && event[0] == 0x00 && event[1] == 0x5B) {
print('Connection open');
if (uri.scheme == 'https') {
_socket = await SecureSocket.secure(
_socket!,
host: uri.authority,
);
_socket!.listen((event) {
responseIntList.addAll(event);
}).onDone(onSocketDone);
}
var requestString = 'GET ${uri.path} HTTP/1.1\r\n'
'Host: ${uri.authority}\r\n\r\n';
_socket!.write(requestString);
return;
}
responseIntList.addAll(event);
}).onDone(onSocketDone);
}
void _socksConnectionRequest(Uri uri, Socket socket) {
var uriPortBytes = [(uri.port >> 8) & 0xFF, uri.port & 0xFF];
var uriAuthorityAscii = ascii.encode(uri.authority);
socket.add([
0x04, // SOCKS version
0x01, // request establish a TCP/IP stream connection
...uriPortBytes, // 2 bytes destination port
0x00, // 4 bytes of destination ip
0x00, // if socks4a and destination ip equals 0.0.0.NonZero
0x00, // then we can pass destination domen after first 0x00 byte
0x01,
0x00,
...uriAuthorityAscii, // destination domen
0x00,
]);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Tor Onion Proxy example'),
),
body: LayoutBuilder(
builder: (context, constrains) {
return Scrollbar(
child: SingleChildScrollView(
child: Container(
constraints: BoxConstraints(minHeight: constrains.maxHeight),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 20),
Text(
'Tor running on: ${_torLocalPort ?? _error ?? 'Unknown'}'),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Wrap(
runSpacing: 20,
spacing: 20,
children: <Widget>[
OutlinedButton(
child: Text('Start Tor Onion Proxy'),
onPressed:
_torLocalPort == null ? _startTor : null,
),
OutlinedButton(
child: Text('Stop Tor Onion Proxy'),
onPressed:
_torLocalPort != null ? _stopTor : null,
),
OutlinedButton(
child:
Text('Send request to check.torproject.org'),
onPressed: _torLocalPort != null
? () => _sendGetRequest(
Uri.https('xxxxxxx.onion:port', '/REST_CALL/'))
: null,
),
],
),
),
if (_responseString != null)
Padding(
padding: const EdgeInsets.all(16.0),
child: Text('Response: \n\n$_responseString'),
),
],
),
),
),
);
},
),
),
);
}
@override
void dispose() {
_socket!.close();
super.dispose();
}
}
1条答案
按热度按时间j9per5c41#
我让它工作了。问题是我用的是
xxxxxxx.onion:port
。“:端口”是问题所在。假设调用是xxxxxxx.onion:1111。在
void _socksConnectionRequest(Uri uri, Socket socket)
函数中,有一个uri.port和一个uri. authority。uri.port将是'1111',但uri.authority将是xxxxxxx.onion:1111,因此您在函数中有两个端口。您可以通过替换以下内容来修复此问题:var uriAuthorityAscii = ascii.encode(uri.authority);
与var uriAuthorityAscii = ascii.encode(uri.authority.substring(0, uri.authority.length - 5));
在_socksConnectionRequest函数中。这将使uri. authority = 'xxxxxxx.onion'。注意,我在这里做了-5,因为我们的端口是:1111,所以它有5个字符。如果你的端口是:111,你必须减去4。如果你有可变的端口长度,你总是可以用一个函数来替换它。在
_socket = await SecureSocket.secure
函数中仍然需要onBadCertificate: (_) => true
。它解决了CERTIFICATE_VERIFY_FAILED: self signed certificate(handshake.cc:393)) error.