mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-03-15 04:23:17 +08:00
外部代理设置,抓包可以同时访问外网,退出时自动还原成外部代理
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
import 'package:network_proxy/network/util/host_filter.dart';
|
||||
import 'package:network_proxy/network/util/logger.dart';
|
||||
import 'package:network_proxy/network/util/request_rewrite.dart';
|
||||
@@ -13,8 +14,8 @@ class Configuration {
|
||||
//是否启用https抓包
|
||||
bool enableSsl = false;
|
||||
|
||||
//是否启用桌面抓包
|
||||
bool enableDesktop = true;
|
||||
//是否设置系统代理
|
||||
bool enableSystemProxy = true;
|
||||
|
||||
//是否引导
|
||||
bool guide = false;
|
||||
@@ -94,7 +95,7 @@ class Configuration {
|
||||
logger.i('加载配置文件 [$file]');
|
||||
port = config['port'] ?? port;
|
||||
enableSsl = config['enableSsl'] == true;
|
||||
enableDesktop = config['enableDesktop'] ?? true;
|
||||
enableSystemProxy = config['enableSystemProxy'] ?? (config['enableDesktop'] ?? true);
|
||||
guide = config['guide'] ?? false;
|
||||
upgradeNotice = config['upgradeNotice'] ?? true;
|
||||
if (config['externalProxy'] != null) {
|
||||
@@ -140,33 +141,10 @@ class Configuration {
|
||||
'upgradeNotice': upgradeNotice,
|
||||
'port': port,
|
||||
'enableSsl': enableSsl,
|
||||
'enableDesktop': enableDesktop,
|
||||
'enableSystemProxy': enableSystemProxy,
|
||||
'externalProxy': externalProxy?.toJson(),
|
||||
'whitelist': HostFilter.whitelist.toJson(),
|
||||
'blacklist': HostFilter.blacklist.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 代理信息
|
||||
class ProxyInfo {
|
||||
bool enable = false;
|
||||
String host = '127.0.0.1';
|
||||
int? port;
|
||||
|
||||
ProxyInfo();
|
||||
|
||||
ProxyInfo.fromJson(Map<String, dynamic> json) {
|
||||
enable = json['enable'] == true;
|
||||
host = json['host'];
|
||||
port = json['port'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'enable': enable,
|
||||
'host': host,
|
||||
'port': port,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
|
||||
import '../channel.dart';
|
||||
import '../handler.dart';
|
||||
import '../http/codec.dart';
|
||||
import '../network.dart';
|
||||
import '../util/logger.dart';
|
||||
import '../util/system_proxy.dart';
|
||||
|
||||
@@ -58,8 +58,8 @@ class ProxyServer {
|
||||
return server.bind(port).then((serverSocket) {
|
||||
logger.i("listen on $port");
|
||||
this.server = server;
|
||||
if (configuration.enableDesktop) {
|
||||
SystemProxy.setSystemProxy(port, enableSsl);
|
||||
if (configuration.enableSystemProxy) {
|
||||
setSystemProxyEnable(true);
|
||||
}
|
||||
return server;
|
||||
});
|
||||
@@ -68,17 +68,24 @@ class ProxyServer {
|
||||
/// 停止代理服务
|
||||
Future<Server?> stop() async {
|
||||
logger.i("stop on $port");
|
||||
if (configuration.enableDesktop) {
|
||||
if (Platform.isMacOS) {
|
||||
await SystemProxy.setProxyEnableMacOS(false, enableSsl);
|
||||
} else if (Platform.isWindows) {
|
||||
await SystemProxy.setProxyEnableWindows(false);
|
||||
}
|
||||
if (configuration.enableSystemProxy) {
|
||||
await setSystemProxyEnable(false);
|
||||
}
|
||||
await server?.stop();
|
||||
return server;
|
||||
}
|
||||
|
||||
/// 设置系统代理
|
||||
setSystemProxyEnable(bool enable) async {
|
||||
//关闭系统代理 恢复成外部代理地址
|
||||
if (!enable && configuration.externalProxy?.enabled == true) {
|
||||
await SystemProxy.setSystemProxy(configuration.externalProxy!.port!, enableSsl);
|
||||
return;
|
||||
}
|
||||
|
||||
await SystemProxy.setSystemProxyEnable(port, enable, enableSsl);
|
||||
}
|
||||
|
||||
/// 重启代理服务
|
||||
restart() {
|
||||
stop().then((value) => start());
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
import 'package:network_proxy/network/http/codec.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
import 'package:network_proxy/network/util/attribute_keys.dart';
|
||||
import 'package:network_proxy/network/util/crts.dart';
|
||||
import 'package:network_proxy/network/util/host_filter.dart';
|
||||
import 'package:network_proxy/network/util/logger.dart';
|
||||
|
||||
import 'handler.dart';
|
||||
@@ -59,13 +57,23 @@ class Channel {
|
||||
|
||||
Socket get socket => _socket;
|
||||
|
||||
set secureSocket(SecureSocket secureSocket) => _socket = secureSocket;
|
||||
set secureSocket(SecureSocket secureSocket) {
|
||||
_socket = secureSocket;
|
||||
pipeline.listen(this);
|
||||
}
|
||||
|
||||
Future<void> write(Object obj) async {
|
||||
if (isClosed) {
|
||||
logger.w("channel is closed $obj");
|
||||
return;
|
||||
}
|
||||
|
||||
//只能有一个写入
|
||||
int retry = 0;
|
||||
while (isWriting && retry++ < 30) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
|
||||
isWriting = true;
|
||||
try {
|
||||
var data = pipeline._encoder.encode(obj);
|
||||
@@ -93,8 +101,8 @@ class Channel {
|
||||
while (isWriting && retry++ < 10) {
|
||||
await Future.delayed(const Duration(milliseconds: 150));
|
||||
}
|
||||
_socket.destroy();
|
||||
isOpen = false;
|
||||
_socket.destroy();
|
||||
}
|
||||
|
||||
///返回此channel是否打开
|
||||
@@ -120,12 +128,12 @@ class Channel {
|
||||
class ChannelPipeline extends ChannelHandler<Uint8List> {
|
||||
late Decoder _decoder;
|
||||
late Encoder _encoder;
|
||||
late ChannelHandler _handler;
|
||||
late ChannelHandler handler;
|
||||
|
||||
handle(Decoder decoder, Encoder encoder, ChannelHandler handler) {
|
||||
_encoder = encoder;
|
||||
_decoder = decoder;
|
||||
_handler = handler;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
void listen(Channel channel) {
|
||||
@@ -136,7 +144,7 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
|
||||
|
||||
@override
|
||||
void channelActive(Channel channel) {
|
||||
_handler.channelActive(channel);
|
||||
handler.channelActive(channel);
|
||||
}
|
||||
|
||||
/// 转发请求
|
||||
@@ -152,7 +160,7 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
|
||||
HostAndPort? remote = channel.getAttribute(AttributeKeys.remote);
|
||||
if (remote != null && channel.getAttribute(channel.id) != null) {
|
||||
relay(channel, channel.getAttribute(channel.id));
|
||||
_handler.channelRead(channel, msg);
|
||||
handler.channelRead(channel, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -178,20 +186,20 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
|
||||
if (data is HttpResponse) {
|
||||
data.remoteAddress = '${channel.remoteAddress.host}:${channel.remotePort}';
|
||||
}
|
||||
_handler.channelRead(channel, data!);
|
||||
handler.channelRead(channel, data!);
|
||||
} catch (error, trace) {
|
||||
exceptionCaught(channel, error, trace: trace);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
exceptionCaught(Channel channel, dynamic cause, {StackTrace? trace}) {
|
||||
_handler.exceptionCaught(channel, cause, trace: trace);
|
||||
exceptionCaught(Channel channel, dynamic error, {StackTrace? trace}) {
|
||||
handler.exceptionCaught(channel, error, trace: trace);
|
||||
}
|
||||
|
||||
@override
|
||||
channelInactive(Channel channel) {
|
||||
_handler.channelInactive(channel);
|
||||
handler.channelInactive(channel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,122 +218,3 @@ class RawCodec extends Codec<Object> {
|
||||
abstract interface class ChannelInitializer {
|
||||
void initChannel(Channel channel);
|
||||
}
|
||||
|
||||
class Network {
|
||||
late Function _channelInitializer;
|
||||
String? remoteHost;
|
||||
Configuration? configuration;
|
||||
|
||||
Network initChannel(void Function(Channel channel) initializer) {
|
||||
_channelInitializer = initializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
Channel listen(Socket socket) {
|
||||
var channel = Channel(socket);
|
||||
_channelInitializer.call(channel);
|
||||
channel.pipeline.channelActive(channel);
|
||||
socket.listen((data) => _onEvent(data, channel),
|
||||
onError: (error, StackTrace trace) => channel.pipeline.exceptionCaught(channel, error, trace: trace),
|
||||
onDone: () => channel.pipeline.channelInactive(channel));
|
||||
return channel;
|
||||
}
|
||||
|
||||
_onEvent(Uint8List data, Channel channel) async {
|
||||
if (remoteHost != null) {
|
||||
channel.putAttribute(AttributeKeys.remote, HostAndPort.of(remoteHost!));
|
||||
}
|
||||
|
||||
//代理信息
|
||||
if (configuration?.externalProxy?.enable == true) {
|
||||
channel.putAttribute(AttributeKeys.proxyInfo, configuration!.externalProxy!);
|
||||
}
|
||||
|
||||
HostAndPort? hostAndPort = channel.getAttribute(AttributeKeys.host);
|
||||
|
||||
//黑名单 或 没开启https 直接转发
|
||||
if (HostFilter.filter(hostAndPort?.host) || (hostAndPort?.isSsl() == true && configuration?.enableSsl == false)) {
|
||||
relay(channel, channel.getAttribute(channel.id));
|
||||
channel.pipeline.channelRead(channel, data);
|
||||
return;
|
||||
}
|
||||
|
||||
//ssl握手
|
||||
if (hostAndPort?.isSsl() == true) {
|
||||
ssl(channel, hostAndPort!, data);
|
||||
return;
|
||||
}
|
||||
|
||||
channel.pipeline.channelRead(channel, data);
|
||||
}
|
||||
|
||||
void ssl(Channel channel, HostAndPort hostAndPort, Uint8List data) async {
|
||||
try {
|
||||
//客户端ssl握手
|
||||
Channel remoteChannel = channel.getAttribute(channel.id);
|
||||
remoteChannel.secureSocket =
|
||||
await SecureSocket.secure(remoteChannel.socket, onBadCertificate: (certificate) => true);
|
||||
|
||||
remoteChannel.pipeline.listen(remoteChannel);
|
||||
|
||||
//ssl自签证书
|
||||
var certificate = await CertificateManager.getCertificateContext(hostAndPort.host);
|
||||
|
||||
SecureSocket secureSocket = await SecureSocket.secureServer(channel.socket, certificate, bufferedData: data);
|
||||
channel.secureSocket = secureSocket;
|
||||
channel.pipeline.listen(channel);
|
||||
} catch (error, trace) {
|
||||
channel.pipeline._handler.exceptionCaught(channel, error, trace: trace);
|
||||
}
|
||||
}
|
||||
|
||||
/// 转发请求
|
||||
void relay(Channel clientChannel, Channel remoteChannel) {
|
||||
var rawCodec = RawCodec();
|
||||
clientChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(remoteChannel));
|
||||
remoteChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(clientChannel));
|
||||
}
|
||||
}
|
||||
|
||||
class Server extends Network {
|
||||
late ServerSocket serverSocket;
|
||||
bool isRunning = false;
|
||||
|
||||
Server(Configuration configuration) {
|
||||
super.configuration = configuration;
|
||||
}
|
||||
|
||||
Future<ServerSocket> bind(int port) async {
|
||||
serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, port);
|
||||
serverSocket.listen((socket) {
|
||||
listen(socket);
|
||||
});
|
||||
isRunning = true;
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
Future<ServerSocket> stop() async {
|
||||
if (!isRunning) return serverSocket;
|
||||
isRunning = false;
|
||||
await serverSocket.close();
|
||||
return serverSocket;
|
||||
}
|
||||
}
|
||||
|
||||
class Client extends Network {
|
||||
Future<Channel> connect(HostAndPort hostAndPort) async {
|
||||
String host = hostAndPort.host;
|
||||
//说明支持ipv6
|
||||
if (host.startsWith("[") && host.endsWith(']')) {
|
||||
host = host.substring(host.lastIndexOf(":") + 1, host.length - 1);
|
||||
}
|
||||
|
||||
return Socket.connect(host, hostAndPort.port, timeout: const Duration(seconds: 3)).then((socket) => listen(socket));
|
||||
}
|
||||
|
||||
/// ssl连接
|
||||
Future<Channel> secureConnect(HostAndPort hostAndPort) async {
|
||||
return SecureSocket.connect(hostAndPort.host, hostAndPort.port,
|
||||
timeout: const Duration(seconds: 3), onBadCertificate: (certificate) => true).then((socket) => listen(socket));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
import 'package:network_proxy/network/http/http_headers.dart';
|
||||
@@ -86,11 +85,13 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
|
||||
/// 转发请求
|
||||
Future<void> forward(Channel channel, HttpRequest httpRequest) async {
|
||||
//获取远程连接
|
||||
var remoteChannel = await _getRemoteChannel(channel, httpRequest);
|
||||
|
||||
|
||||
//实现抓包代理转发
|
||||
if (httpRequest.method != HttpMethod.connect) {
|
||||
// log.i("[${channel.id}] ${httpRequest.requestUrl}");
|
||||
// log.i("[${channel.id}] ${httpRequest.method.name} ${httpRequest.requestUrl}");
|
||||
|
||||
var replaceBody = requestRewrites?.findRequestReplaceWith(httpRequest.path());
|
||||
if (replaceBody?.isNotEmpty == true) {
|
||||
@@ -100,7 +101,6 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
if (!HostFilter.filter(httpRequest.hostAndPort?.host)) {
|
||||
listener?.onRequest(channel, httpRequest);
|
||||
}
|
||||
//实现抓包代理转发
|
||||
await remoteChannel.write(httpRequest);
|
||||
}
|
||||
}
|
||||
@@ -139,27 +139,23 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
|
||||
//远程转发
|
||||
HostAndPort? remote = clientChannel.getAttribute(AttributeKeys.remote);
|
||||
if (remote != null) {
|
||||
var proxyChannel = await HttpClients.rawConnect(remote, proxyHandler);
|
||||
//外部代理
|
||||
ProxyInfo? proxyInfo = clientChannel.getAttribute(AttributeKeys.proxyInfo);
|
||||
|
||||
if (remote != null || proxyInfo != null) {
|
||||
HostAndPort connectHost = remote ?? HostAndPort.host(proxyInfo!.host, proxyInfo.port!);
|
||||
var proxyChannel = await HttpClients.startConnect(connectHost, proxyHandler);
|
||||
clientChannel.putAttribute(clientId, proxyChannel);
|
||||
proxyChannel.write(httpRequest);
|
||||
return proxyChannel;
|
||||
}
|
||||
|
||||
//https代理
|
||||
ProxyInfo? proxyInfo = clientChannel.getAttribute(AttributeKeys.proxyInfo);
|
||||
if (proxyInfo != null) {
|
||||
var proxyChannel = await HttpClients.rawConnect(HostAndPort.host(proxyInfo.host, proxyInfo.port!), proxyHandler);
|
||||
clientChannel.putAttribute(clientId, proxyChannel);
|
||||
await proxyChannel.write(httpRequest);
|
||||
return proxyChannel;
|
||||
}
|
||||
|
||||
var proxyChannel = await HttpClients.rawConnect(hostAndPort, proxyHandler);
|
||||
var proxyChannel = await HttpClients.startConnect(hostAndPort, proxyHandler);
|
||||
clientChannel.putAttribute(clientId, proxyChannel);
|
||||
//https代理新建连接请求
|
||||
if (httpRequest.method == HttpMethod.connect) {
|
||||
await clientChannel.write(HttpResponse(httpRequest.protocolVersion, HttpStatus.ok));
|
||||
await clientChannel
|
||||
.write(HttpResponse(httpRequest.protocolVersion, HttpStatus.ok.reason('Connection established')));
|
||||
}
|
||||
|
||||
return proxyChannel;
|
||||
@@ -168,6 +164,7 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
|
||||
/// http响应代理
|
||||
class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
|
||||
//客户端的连接
|
||||
final Channel clientChannel;
|
||||
|
||||
EventListener? listener;
|
||||
@@ -176,10 +173,10 @@ class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
|
||||
HttpResponseProxyHandler(this.clientChannel, {this.listener, this.requestRewrites});
|
||||
|
||||
@override
|
||||
void channelRead(Channel channel, HttpResponse msg) {
|
||||
void channelRead(Channel channel, HttpResponse msg) async {
|
||||
msg.request = clientChannel.getAttribute(AttributeKeys.request);
|
||||
msg.request?.response = msg;
|
||||
// log.i("[${clientChannel.id}] Response ${msg.bodyAsString}");
|
||||
// log.i("[${clientChannel.id}] Response ${msg}");
|
||||
|
||||
var replaceBody = requestRewrites?.findResponseReplaceWith(msg.request?.path());
|
||||
if (replaceBody?.isNotEmpty == true) {
|
||||
@@ -189,8 +186,9 @@ class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
|
||||
if (!HostFilter.filter(msg.request?.hostAndPort?.host)) {
|
||||
listener?.onResponse(clientChannel, msg);
|
||||
}
|
||||
|
||||
//发送给客户端
|
||||
clientChannel.write(msg);
|
||||
await clientChannel.write(msg);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -21,8 +21,8 @@ class HostAndPort {
|
||||
|
||||
HostAndPort(this.scheme, this.host, this.port);
|
||||
|
||||
factory HostAndPort.host(String host, int port) {
|
||||
return HostAndPort(port == 443 ? httpsScheme : httpScheme, host, port);
|
||||
factory HostAndPort.host(String host, int port, {String? scheme}) {
|
||||
return HostAndPort(scheme ?? (port == 443 ? httpsScheme : httpScheme), host, port);
|
||||
}
|
||||
|
||||
bool isSsl() {
|
||||
@@ -75,3 +75,33 @@ class HostAndPort {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
/// 代理信息
|
||||
class ProxyInfo {
|
||||
bool enabled = false;
|
||||
String host = '127.0.0.1';
|
||||
int? port;
|
||||
|
||||
ProxyInfo();
|
||||
|
||||
ProxyInfo.of(this.host, this.port) : enabled = true;
|
||||
|
||||
ProxyInfo.fromJson(Map<String, dynamic> json) {
|
||||
enabled = json['enabled'] == true;
|
||||
host = json['host'];
|
||||
port = json['port'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'enabled': enabled,
|
||||
'host': host,
|
||||
'port': port,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{enabled: $enabled, host: $host, port: $port}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ abstract interface class Encoder<T> {
|
||||
/// 编解码器
|
||||
abstract class Codec<T> implements Decoder<T>, Encoder<T> {
|
||||
static const int defaultMaxInitialLineLength = 10240;
|
||||
static const int maxBodyLength = 1024000;
|
||||
static const int maxBodyLength = 4096000;
|
||||
}
|
||||
|
||||
/// http编解码
|
||||
|
||||
@@ -261,7 +261,12 @@ class HttpStatus {
|
||||
}
|
||||
|
||||
final int code;
|
||||
final String reasonPhrase;
|
||||
String reasonPhrase;
|
||||
|
||||
HttpStatus reason(String reasonPhrase) {
|
||||
this.reasonPhrase = reasonPhrase;
|
||||
return this;
|
||||
}
|
||||
|
||||
HttpStatus(this.code, this.reasonPhrase);
|
||||
|
||||
|
||||
@@ -3,19 +3,53 @@ import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
import 'package:network_proxy/network/network.dart';
|
||||
|
||||
import 'channel.dart';
|
||||
import 'http/codec.dart';
|
||||
|
||||
class HttpClients {
|
||||
/// 建立连接
|
||||
static Future<Channel> rawConnect(HostAndPort hostAndPort, ChannelHandler handler) async {
|
||||
static Future<Channel> startConnect(HostAndPort hostAndPort, ChannelHandler handler) async {
|
||||
var client = Client()
|
||||
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), handler));
|
||||
|
||||
return client.connect(hostAndPort);
|
||||
}
|
||||
|
||||
///代理建立连接
|
||||
static Future<Channel> proxyConnect(HostAndPort hostAndPort, ChannelHandler handler, {ProxyInfo? proxyInfo}) async {
|
||||
var client = Client()
|
||||
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), handler));
|
||||
|
||||
HostAndPort connectHost = proxyInfo == null ? hostAndPort : HostAndPort.host(proxyInfo.host, proxyInfo.port!);
|
||||
var channel = await client.connect(connectHost);
|
||||
|
||||
if (proxyInfo == null || !hostAndPort.isSsl()) {
|
||||
return channel;
|
||||
}
|
||||
|
||||
//代理 发送connect请求
|
||||
var httpResponseHandler = HttpResponseHandler();
|
||||
channel.pipeline.handler = httpResponseHandler;
|
||||
|
||||
HttpRequest proxyRequest = HttpRequest(HttpMethod.connect, '${hostAndPort.host}:${hostAndPort.port}');
|
||||
proxyRequest.headers.set(HttpHeaders.hostHeader, '${hostAndPort.host}:${hostAndPort.port}');
|
||||
|
||||
await channel.write(proxyRequest);
|
||||
var response = await httpResponseHandler.getResponse(const Duration(seconds: 3));
|
||||
|
||||
channel.pipeline.handler = handler;
|
||||
|
||||
if (!response.status.isSuccessful()) {
|
||||
final error = "$hostAndPort Proxy failed to establish tunnel "
|
||||
"(${response.status.code} ${response..status.reasonPhrase})";
|
||||
throw Exception(error);
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/// 建立连接
|
||||
static Future<Channel> connect(Uri uri, ChannelHandler handler) async {
|
||||
Client client = Client()
|
||||
@@ -52,20 +86,14 @@ class HttpClients {
|
||||
{Duration timeout = const Duration(seconds: 3)}) async {
|
||||
var httpResponseHandler = HttpResponseHandler();
|
||||
|
||||
bool isHttps = request.uri.startsWith("https://");
|
||||
var client = Client()
|
||||
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), httpResponseHandler));
|
||||
HostAndPort hostPort = HostAndPort.of(request.uri);
|
||||
|
||||
Channel channel = await client.connect(HostAndPort.host(proxyHost, port));
|
||||
Channel channel = await proxyConnect(proxyInfo: ProxyInfo.of(proxyHost, port), hostPort, httpResponseHandler);
|
||||
|
||||
if (isHttps) {
|
||||
HttpRequest proxyRequest = HttpRequest(HttpMethod.connect, request.uri);
|
||||
await channel.write(proxyRequest);
|
||||
await httpResponseHandler.getResponse(timeout);
|
||||
if (hostPort.isSsl()) {
|
||||
channel.secureSocket = await SecureSocket.secure(channel.socket, onBadCertificate: (certificate) => true);
|
||||
}
|
||||
|
||||
httpResponseHandler.resetResponse();
|
||||
await channel.write(request);
|
||||
return httpResponseHandler.getResponse(timeout).whenComplete(() => channel.close());
|
||||
}
|
||||
@@ -76,7 +104,7 @@ class HttpResponseHandler extends ChannelHandler<HttpResponse> {
|
||||
|
||||
@override
|
||||
void channelRead(Channel channel, HttpResponse msg) {
|
||||
// log.i("[${channel.id}] Response ${msg.bodyAsString}");
|
||||
// log.i("[${channel.id}] Response $msg");
|
||||
_completer.complete(msg);
|
||||
}
|
||||
|
||||
|
||||
138
lib/network/network.dart
Normal file
138
lib/network/network.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
import 'package:network_proxy/network/channel.dart';
|
||||
import 'package:network_proxy/network/handler.dart';
|
||||
import 'package:network_proxy/network/util/attribute_keys.dart';
|
||||
import 'package:network_proxy/network/util/crts.dart';
|
||||
import 'package:network_proxy/network/util/host_filter.dart';
|
||||
|
||||
import 'host_port.dart';
|
||||
|
||||
class Network {
|
||||
late Function _channelInitializer;
|
||||
String? remoteHost;
|
||||
Configuration? configuration;
|
||||
StreamSubscription? subscription;
|
||||
|
||||
Network initChannel(void Function(Channel channel) initializer) {
|
||||
_channelInitializer = initializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
Channel listen(Socket socket) {
|
||||
var channel = Channel(socket);
|
||||
_channelInitializer.call(channel);
|
||||
channel.pipeline.channelActive(channel);
|
||||
subscription = socket.listen((data) => _onEvent(data, channel),
|
||||
onError: (error, StackTrace trace) => channel.pipeline.exceptionCaught(channel, error, trace: trace),
|
||||
onDone: () => channel.pipeline.channelInactive(channel));
|
||||
return channel;
|
||||
}
|
||||
|
||||
_onEvent(Uint8List data, Channel channel) async {
|
||||
if (remoteHost != null) {
|
||||
channel.putAttribute(AttributeKeys.remote, HostAndPort.of(remoteHost!));
|
||||
}
|
||||
|
||||
//代理信息
|
||||
if (configuration?.externalProxy?.enabled == true) {
|
||||
channel.putAttribute(AttributeKeys.proxyInfo, configuration!.externalProxy!);
|
||||
}
|
||||
|
||||
HostAndPort? hostAndPort = channel.getAttribute(AttributeKeys.host);
|
||||
|
||||
//黑名单 或 没开启https 直接转发
|
||||
if (HostFilter.filter(hostAndPort?.host) || (hostAndPort?.isSsl() == true && configuration?.enableSsl == false)) {
|
||||
relay(channel, channel.getAttribute(channel.id));
|
||||
channel.pipeline.channelRead(channel, data);
|
||||
return;
|
||||
}
|
||||
|
||||
//ssl握手
|
||||
if (hostAndPort?.isSsl() == true) {
|
||||
ssl(channel, hostAndPort!, data);
|
||||
return;
|
||||
}
|
||||
|
||||
channel.pipeline.channelRead(channel, data);
|
||||
}
|
||||
|
||||
void ssl(Channel channel, HostAndPort hostAndPort, Uint8List data) async {
|
||||
try {
|
||||
Channel remoteChannel = channel.getAttribute(channel.id);
|
||||
|
||||
remoteChannel.secureSocket = await SecureSocket.secure(remoteChannel.socket,
|
||||
host: hostAndPort.host, onBadCertificate: (certificate) => true);
|
||||
|
||||
//ssl自签证书
|
||||
var certificate = await CertificateManager.getCertificateContext(hostAndPort.host);
|
||||
//服务端等待客户端ssl握手
|
||||
channel.secureSocket = await SecureSocket.secureServer(channel.socket, certificate, bufferedData: data);
|
||||
} catch (error, trace) {
|
||||
if (error is HandshakeException) {
|
||||
channel.socket.destroy();
|
||||
subscription?.pause();
|
||||
await subscription?.cancel();
|
||||
}
|
||||
channel.pipeline.exceptionCaught(channel, error, trace: trace);
|
||||
}
|
||||
}
|
||||
|
||||
/// 转发请求
|
||||
void relay(Channel clientChannel, Channel remoteChannel) {
|
||||
var rawCodec = RawCodec();
|
||||
clientChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(remoteChannel));
|
||||
remoteChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(clientChannel));
|
||||
}
|
||||
}
|
||||
|
||||
class Server extends Network {
|
||||
late ServerSocket serverSocket;
|
||||
bool isRunning = false;
|
||||
|
||||
Server(Configuration configuration) {
|
||||
super.configuration = configuration;
|
||||
}
|
||||
|
||||
Future<ServerSocket> bind(int port) async {
|
||||
serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, port);
|
||||
serverSocket.listen((socket) {
|
||||
listen(socket);
|
||||
});
|
||||
isRunning = true;
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
Future<ServerSocket> stop() async {
|
||||
if (!isRunning) return serverSocket;
|
||||
isRunning = false;
|
||||
await serverSocket.close();
|
||||
return serverSocket;
|
||||
}
|
||||
}
|
||||
|
||||
class Client extends Network {
|
||||
Future<Channel> connect(HostAndPort hostAndPort) async {
|
||||
String host = hostAndPort.host;
|
||||
//说明支持ipv6
|
||||
if (host.startsWith("[") && host.endsWith(']')) {
|
||||
host = host.substring(host.lastIndexOf(":") + 1, host.length - 1);
|
||||
}
|
||||
|
||||
return Socket.connect(host, hostAndPort.port).then((socket) {
|
||||
if (socket.address.type != InternetAddressType.unix) {
|
||||
socket.setOption(SocketOption.tcpNoDelay, true);
|
||||
}
|
||||
return listen(socket);
|
||||
});
|
||||
}
|
||||
|
||||
/// ssl连接
|
||||
Future<Channel> secureConnect(HostAndPort hostAndPort) async {
|
||||
return SecureSocket.connect(hostAndPort.host, hostAndPort.port,
|
||||
timeout: const Duration(seconds: 3), onBadCertificate: (certificate) => true).then((socket) => listen(socket));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'package:logger/logger.dart';
|
||||
final logger = Logger(
|
||||
printer: PrettyPrinter(
|
||||
methodCount: 0,
|
||||
errorMethodCount: 8,
|
||||
errorMethodCount: 15,
|
||||
lineLength: 120,
|
||||
colors: true,
|
||||
printEmojis: false,
|
||||
|
||||
@@ -7,23 +7,26 @@ class SystemProxy {
|
||||
static String? _hardwarePort;
|
||||
|
||||
/// 设置系统代理
|
||||
static void setSystemProxy(int port, bool sslSetting) async {
|
||||
static Future<void> setSystemProxy(int port, bool sslSetting) async {
|
||||
if (Platform.isMacOS) {
|
||||
_setProxyServerMacOS(port, sslSetting);
|
||||
await _setProxyServerMacOS(port, sslSetting);
|
||||
} else if (Platform.isWindows) {
|
||||
_setProxyServerWindows(port, sslSetting);
|
||||
await _setProxyServerWindows(port);
|
||||
}
|
||||
}
|
||||
|
||||
static void setSystemProxyEnable(int port, bool enable, bool sslSetting) async {
|
||||
/// 设置系统代理 @param sslSetting 是否设置https代理只在mac中有效
|
||||
static Future<void> setSystemProxyEnable(int port, bool enable, bool sslSetting) async {
|
||||
//启用系统代理
|
||||
if (enable) {
|
||||
setSystemProxy(port, sslSetting);
|
||||
await setSystemProxy(port, sslSetting);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform.isMacOS) {
|
||||
setProxyEnableMacOS(enable, sslSetting);
|
||||
await setProxyEnableMacOS(enable, sslSetting);
|
||||
} else if (Platform.isWindows) {
|
||||
setProxyEnableWindows(enable);
|
||||
await setProxyEnableWindows(enable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +37,7 @@ class SystemProxy {
|
||||
_concatCommands([
|
||||
'networksetup -setwebproxy $_hardwarePort 127.0.0.1 $port',
|
||||
sslSetting == true ? 'networksetup -setsecurewebproxy $_hardwarePort 127.0.0.1 $port' : '',
|
||||
'networksetup -setproxybypassdomains $_hardwarePort 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 127.0.0.1 localhost *.local timestamp.apple.com sequoia.apple.com seed-sequoia.siri.apple.com *.google.com',
|
||||
'networksetup -setproxybypassdomains $_hardwarePort 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12 127.0.0.1 localhost *.local timestamp.apple.com',
|
||||
])
|
||||
]);
|
||||
print('set proxyServer, name: $_hardwarePort, exitCode: ${results.exitCode}, stdout: ${results.stdout}');
|
||||
@@ -79,10 +82,12 @@ class SystemProxy {
|
||||
return results.stdout.toString().split(", ")[0];
|
||||
}
|
||||
|
||||
static Future<bool> _setProxyServerWindows(int proxyPort, bool sslSetting) async {
|
||||
ProxyManager manager = ProxyManager();
|
||||
await manager.setAsSystemProxy(ProxyTypes.http, "127.0.0.1", proxyPort);
|
||||
static Future<bool> _setProxyServerWindows(int proxyPort) async {
|
||||
print("setSystemProxy $proxyPort");
|
||||
|
||||
ProxyManager manager = ProxyManager();
|
||||
await manager.setAsSystemProxy(ProxyTypes.https, "127.0.0.1", proxyPort);
|
||||
print("setSystemProxy end");
|
||||
var results = await Process.run('reg', [
|
||||
'add',
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
|
||||
|
||||
@@ -161,18 +161,6 @@ class X509Generate {
|
||||
return outer;
|
||||
}
|
||||
|
||||
///
|
||||
/// Converts the hex string to bytes
|
||||
///
|
||||
static Uint8List _stringAsBytes(String s) {
|
||||
var list = StringUtils.chunk(s, 2);
|
||||
var bytes = <int>[];
|
||||
for (var e in list) {
|
||||
bytes.add(int.parse(e, radix: 16));
|
||||
}
|
||||
return Uint8List.fromList(bytes);
|
||||
}
|
||||
|
||||
static String _getDigestFromOi(String oi) {
|
||||
switch (oi) {
|
||||
case 'ecdsaWithSHA1':
|
||||
|
||||
@@ -38,7 +38,7 @@ class DomainWidgetState extends State<DomainWidget> {
|
||||
changeState() {
|
||||
if (!changing) {
|
||||
changing = true;
|
||||
Future.delayed(const Duration(milliseconds: 1500), () {
|
||||
Future.delayed(const Duration(milliseconds: 1000), () {
|
||||
setState(() {
|
||||
changing = false;
|
||||
});
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
|
||||
class ExternalProxyDialog extends StatefulWidget {
|
||||
final Configuration configuration;
|
||||
@@ -20,7 +23,10 @@ class _ExternalProxyDialogState extends State<ExternalProxyDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
externalProxy = widget.configuration.externalProxy ?? ProxyInfo();
|
||||
externalProxy = ProxyInfo();
|
||||
if (widget.configuration.externalProxy != null) {
|
||||
externalProxy = ProxyInfo.fromJson(widget.configuration.externalProxy!.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -35,31 +41,26 @@ class _ExternalProxyDialogState extends State<ExternalProxyDialog> {
|
||||
},
|
||||
child: const Text("取消")),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
if (!formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
widget.configuration.externalProxy = externalProxy;
|
||||
widget.configuration.flushConfig();
|
||||
if (externalProxy.enable) {
|
||||
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
submit();
|
||||
},
|
||||
child: const Text("确定"))
|
||||
],
|
||||
content: Form(
|
||||
key: formKey,
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
const Text("注意:请将科学上网网站加入域名过滤黑名单。", style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500)),
|
||||
const Text("如发现访问失败的外网请将加入域名过滤黑名单。", style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500)),
|
||||
const SizedBox(height: 10),
|
||||
Row(children: [
|
||||
const Text("是否启用:"),
|
||||
Expanded(
|
||||
child: Switch(
|
||||
value: externalProxy.enable,
|
||||
value: externalProxy.enabled,
|
||||
onChanged: (val) {
|
||||
setState(() => externalProxy.enable = val);
|
||||
setState(() => externalProxy.enabled = val);
|
||||
},
|
||||
))
|
||||
]),
|
||||
@@ -88,4 +89,43 @@ class _ExternalProxyDialogState extends State<ExternalProxyDialog> {
|
||||
]),
|
||||
])));
|
||||
}
|
||||
|
||||
submit() async {
|
||||
bool setting = true;
|
||||
if (externalProxy.enabled) {
|
||||
try {
|
||||
var socket = await Socket.connect(externalProxy.host, externalProxy.port!, timeout: const Duration(seconds: 1));
|
||||
socket.destroy();
|
||||
} on SocketException catch (_) {
|
||||
setting = false;
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: const Text("外部代理连接失败"),
|
||||
content: const Text('网络不通所有接口将会访问失败,是否继续设置外部代理。', style: TextStyle(fontSize: 12)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text("取消")),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
setting = true;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text("确定"))
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (setting) {
|
||||
widget.configuration.externalProxy = externalProxy;
|
||||
widget.configuration.flushConfig();
|
||||
}
|
||||
|
||||
if (context.mounted) Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:network_proxy/network/bin/configuration.dart';
|
||||
import 'package:network_proxy/network/bin/server.dart';
|
||||
import 'package:network_proxy/network/util/system_proxy.dart';
|
||||
import 'package:network_proxy/ui/desktop/toolbar/setting/external_proxy.dart';
|
||||
import 'package:network_proxy/ui/desktop/toolbar/setting/request_rewrite.dart';
|
||||
import 'package:network_proxy/ui/desktop/toolbar/setting/theme.dart';
|
||||
@@ -27,7 +26,7 @@ class _SettingState extends State<Setting> {
|
||||
@override
|
||||
void initState() {
|
||||
configuration = widget.proxyServer.configuration;
|
||||
enableDesktopListenable = ValueNotifier<bool>(configuration.enableDesktop);
|
||||
enableDesktopListenable = ValueNotifier<bool>(configuration.enableSystemProxy);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -100,10 +99,10 @@ class _SettingState extends State<Setting> {
|
||||
title: const Text("设置为系统代理"),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
dense: true,
|
||||
value: configuration.enableDesktop,
|
||||
value: configuration.enableSystemProxy,
|
||||
onChanged: (val) {
|
||||
SystemProxy.setSystemProxyEnable(widget.proxyServer.port, val, widget.proxyServer.enableSsl);
|
||||
configuration.enableDesktop = val;
|
||||
widget.proxyServer.setSystemProxyEnable(val);
|
||||
configuration.enableSystemProxy = val;
|
||||
enableDesktopListenable.value = !enableDesktopListenable.value;
|
||||
configuration.flushConfig();
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_toastr/flutter_toastr.dart';
|
||||
import 'package:network_proxy/network/bin/server.dart';
|
||||
import 'package:network_proxy/utils/platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class SocketLaunch extends StatefulWidget {
|
||||
@@ -31,6 +32,9 @@ class _SocketLaunchState extends State<SocketLaunch> with WindowListener, Widget
|
||||
if (widget.startup) {
|
||||
start();
|
||||
}
|
||||
if (Platforms.isDesktop()) {
|
||||
windowManager.setPreventClose(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -42,8 +46,8 @@ class _SocketLaunchState extends State<SocketLaunch> with WindowListener, Widget
|
||||
|
||||
@override
|
||||
void onWindowClose() async {
|
||||
print("onWindowClose");
|
||||
await widget.proxyServer.stop();
|
||||
print("onWindowClose");
|
||||
started = false;
|
||||
windowManager.destroy();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import 'dart:io';
|
||||
|
||||
void main() {
|
||||
NetworkInterface.list(type: InternetAddressType.IPv4).then((interfaces) => interfaces.forEach((interface) {
|
||||
print(interface.name);
|
||||
for (var address in interface.addresses) {
|
||||
print(" ${address.address}");
|
||||
print(" ${address.host}");
|
||||
print(" ${address.type}");
|
||||
}
|
||||
}));
|
||||
NetworkInterface.list(type: InternetAddressType.IPv4).then((interfaces) {
|
||||
for (var interface in interfaces) {
|
||||
print(interface.name);
|
||||
for (var address in interface.addresses) {
|
||||
print(" ${address.address}");
|
||||
print(" ${address.host}");
|
||||
print(" ${address.type}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String? ip;
|
||||
|
||||
12
pubspec.lock
12
pubspec.lock
@@ -316,10 +316,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
||||
sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.1.0"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -396,18 +396,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: ed3fcea4f789ed95913328e629c0c53e69e80e08b6c24542f1b3576046c614e8
|
||||
sha256: "6cec740fa0943a826951223e76218df002804adb588235a8910dc3d6b0654e11"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "7.0.2"
|
||||
version: "7.1.0"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981"
|
||||
sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "3.3.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
||||
@@ -24,7 +24,7 @@ dependencies:
|
||||
qrscan: ^0.3.3
|
||||
flutter_barcode_scanner: ^2.0.0
|
||||
flutter_toastr: ^1.0.3
|
||||
share_plus: ^7.0.2
|
||||
share_plus: ^7.1.0
|
||||
brotli: ^0.6.0
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
15
test/http_test.dart
Normal file
15
test/http_test.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'dart:io';
|
||||
|
||||
main() async {
|
||||
// await socketTest();
|
||||
await webTest();
|
||||
}
|
||||
|
||||
webTest() async {
|
||||
var httpClient = HttpClient();
|
||||
httpClient.findProxy = (uri) => "PROXY 127.0.0.1:7890";
|
||||
// httpClient.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
|
||||
var httpClientRequest = await httpClient.getUrl(Uri.parse("https://www.v2ex.com"));
|
||||
var response = await httpClientRequest.close();
|
||||
print(response.headers);
|
||||
}
|
||||
@@ -1,27 +1,61 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:network_proxy/network/http/codec.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
|
||||
main() async {
|
||||
var connect = await Socket.connect("127.0.0.1", 7890);
|
||||
var httpRequest = HttpRequest(HttpMethod.connect, "https://www.baidu.com");
|
||||
var codec = HttpRequestCodec();
|
||||
connect.add(codec.encode(httpRequest));
|
||||
|
||||
|
||||
await connect.flush();
|
||||
var first = await connect.first;
|
||||
print(String.fromCharCodes(first));
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
httpRequest = HttpRequest(HttpMethod.get, "https://www.baidu.com");
|
||||
codec = HttpRequestCodec();
|
||||
connect.add(codec.encode(httpRequest));
|
||||
// var httpClient = HttpClient();
|
||||
// httpClient .findProxy = (uri) => "PROXY 127.0.0.1:7890";
|
||||
// httpClient.getUrl(Uri.parse("https://www.youtube.com:443"));
|
||||
SecurityContext.defaultContext.allowLegacyUnsafeRenegotiation = true;
|
||||
await SecureSocket.secure(connect);
|
||||
await socketTest();
|
||||
}
|
||||
|
||||
socketTest() async {
|
||||
var task = await Socket.startConnect("127.0.0.1", 7890);
|
||||
var socket = await task.socket;
|
||||
if (socket.address.type != InternetAddressType.unix) {
|
||||
socket.setOption(SocketOption.tcpNoDelay, true);
|
||||
}
|
||||
|
||||
Completer<bool> completer = Completer<bool>();
|
||||
StreamSubscription? subscription;
|
||||
subscription = socket.listen((event) {
|
||||
subscription!.pause();
|
||||
print(String.fromCharCodes(event));
|
||||
completer.complete(true);
|
||||
});
|
||||
|
||||
String host = 'www.v2ex.com:443';
|
||||
|
||||
var httpRequest = HttpRequest(HttpMethod.connect, host);
|
||||
httpRequest.headers.set('user-agent', 'Dart/3.0 (dart:io)');
|
||||
httpRequest.headers.set('accept-encoding', 'gzip');
|
||||
httpRequest.headers.set(HttpHeaders.hostHeader, host);
|
||||
|
||||
var codec = HttpRequestCodec();
|
||||
print(String.fromCharCodes(codec.encode(httpRequest)));
|
||||
socket.add(codec.encode(httpRequest));
|
||||
await socket.flush();
|
||||
|
||||
// subscription.resume();
|
||||
|
||||
await completer.future;
|
||||
// await Future.delayed(const Duration(milliseconds: 1600));
|
||||
|
||||
var secureSocket = await SecureSocket.secure(socket, host: 'www.v2ex.com', onBadCertificate: (certificate) => true);
|
||||
print("secureSocket");
|
||||
// await subscription.cancel();
|
||||
|
||||
completer = Completer<bool>();
|
||||
subscription = secureSocket.listen((event) {
|
||||
subscription?.pause();
|
||||
print(String.fromCharCodes(event));
|
||||
completer.complete(true);
|
||||
subscription?.resume();
|
||||
});
|
||||
|
||||
httpRequest = HttpRequest(HttpMethod.get, "/");
|
||||
httpRequest.headers.set(HttpHeaders.hostHeader, host);
|
||||
|
||||
secureSocket.add(codec.encode(httpRequest));
|
||||
await secureSocket.flush();
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user