Flutter:dart:io在不使用SSL(TLS)认证的情况下建立套接字连接

vfhzx4xs  于 2022-11-14  发布在  Flutter
关注(0)|答案(1)|浏览(444)

我正在构建一个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();
  }
}
j9per5c4

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.

相关问题