扫码连接终端

This commit is contained in:
wanghongen
2023-07-09 04:16:15 +08:00
parent 75534d9004
commit 3a67c43f32
28 changed files with 723 additions and 157 deletions

View File

@@ -27,7 +27,7 @@ class ProxyServer {
EventListener? listener;
RequestRewrites requestRewrites = RequestRewrites();
List<Function> _initializedListeners = [];
final List<Function> _initializedListeners = [];
ProxyServer({this.listener});

View File

@@ -42,9 +42,7 @@ class Channel {
final int remotePort;
Channel(this._socket)
: _id = DateTime
.now()
.millisecondsSinceEpoch + Random().nextInt(999999),
: _id = DateTime.now().millisecondsSinceEpoch + Random().nextInt(999999),
remoteAddress = _socket.remoteAddress,
remotePort = _socket.remotePort;
@@ -56,6 +54,10 @@ class Channel {
set secureSocket(SecureSocket secureSocket) => _socket = secureSocket;
Future<void> write(Object obj) async {
if (isClosed) {
return;
}
var data = pipeline._encoder.encode(obj);
_socket.add(data);
await _socket.flush();
@@ -115,9 +117,23 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
_handler.channelActive(channel);
}
/// 转发请求
void relay(Channel clientChannel, Channel remoteChannel) {
var rawCodec = RawCodec();
clientChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(remoteChannel));
remoteChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(clientChannel));
}
@override
void channelRead(Channel channel, Uint8List msg) {
try {
HostAndPort? remote = channel.getAttribute(AttributeKeys.remote);
if (remote != null && channel.getAttribute(channel.id) != null) {
relay(channel, channel.getAttribute(channel.id));
_handler.channelRead(channel, msg);
return;
}
var data = _decoder.decode(msg);
if (data == null) {
return;
@@ -199,11 +215,11 @@ class HostAndPort {
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is HostAndPort &&
runtimeType == other.runtimeType &&
scheme == other.scheme &&
host == other.host &&
port == other.port;
other is HostAndPort &&
runtimeType == other.runtimeType &&
scheme == other.scheme &&
host == other.host &&
port == other.port;
@override
int get hashCode => scheme.hashCode ^ host.hashCode ^ port.hashCode;
@@ -250,6 +266,7 @@ abstract interface class ChannelInitializer {
class Network {
late Function _channelInitializer;
bool enableSsl = false;
String? remoteHost;
Network initChannel(void Function(Channel channel) initializer) {
_channelInitializer = initializer;
@@ -268,6 +285,11 @@ class Network {
_onEvent(Uint8List data, Channel channel) async {
HostAndPort? hostAndPort = channel.getAttribute(AttributeKeys.host);
if (remoteHost != null) {
channel.putAttribute(AttributeKeys.remote, HostAndPort.of(remoteHost!));
}
//黑名单 直接转发
if (HostFilter.filter(hostAndPort?.host) || (hostAndPort?.isSsl() == true && !enableSsl)) {
relay(channel, channel.getAttribute(channel.id));
@@ -288,8 +310,9 @@ class Network {
try {
//客户端ssl
Channel remoteChannel = channel.getAttribute(channel.id);
remoteChannel.secureSocket =
await SecureSocket.secure(remoteChannel.socket, onBadCertificate: (certificate) => true);
await SecureSocket.secure(remoteChannel.socket, onBadCertificate: (certificate) => true);
remoteChannel.pipeline.listen(remoteChannel);
//服务端ssl
@@ -326,13 +349,14 @@ class Server extends Network {
Future<ServerSocket> stop() async {
if (!isRunning) return serverSocket;
isRunning = false;
return serverSocket.close();
await serverSocket.close();
return serverSocket;
}
}
class Client extends Network {
Future<Channel> connect(HostAndPort hostAndPort) async {
return Socket.connect(hostAndPort.host, hostAndPort.port, timeout: const Duration(seconds: 5))
return Socket.connect(hostAndPort.host, hostAndPort.port, timeout: const Duration(seconds: 3))
.then((socket) => listen(socket));
}
}

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -5,7 +6,9 @@ import 'package:network_proxy/network/http/http.dart';
import 'package:network_proxy/network/http/http_headers.dart';
import 'package:network_proxy/network/util/attribute_keys.dart';
import 'package:network_proxy/network/util/file_read.dart';
import 'package:network_proxy/network/util/host_filter.dart';
import 'package:network_proxy/network/util/request_rewrite.dart';
import 'package:network_proxy/utils/ip.dart';
import 'channel.dart';
import 'http/codec.dart';
@@ -35,6 +38,33 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
@override
void channelRead(Channel channel, HttpRequest msg) async {
channel.putAttribute(AttributeKeys.request, msg);
if (msg.path == '/config' && (await localIp()) == msg.hostAndPort?.host) {
var response = HttpResponse(msg.protocolVersion, HttpStatus.ok);
var body = {
"requestRewrites": requestRewrites?.toJson(),
'whitelist': HostFilter.whitelist.toJson(),
'blacklist': HostFilter.blacklist.toJson(),
};
response.body = utf8.encode(json.encode(body));
channel.writeAndClose(response);
return;
}
if ((await localIp()) == msg.hostAndPort?.host) {
var response = HttpResponse(msg.protocolVersion, HttpStatus.ok);
response.body = utf8.encode('pong');
response.headers.set("os", Platform.operatingSystem);
response.headers.set("hostname", Platform.isAndroid ? Platform.operatingSystem : Platform.localHostname);
channel.writeAndClose(response);
return;
}
if (msg.uri == 'http://proxy.pin/ssl' || msg.requestUrl == 'http://127.0.0.1:${channel.socket.port}/ssl') {
_crtDownload(channel, msg);
return;
}
forward(channel, msg).catchError((error, trace) {
channel.close();
if (error is SocketException &&
@@ -54,19 +84,11 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
/// 转发请求
Future<void> forward(Channel channel, HttpRequest httpRequest) async {
channel.putAttribute(AttributeKeys.request, httpRequest);
if (httpRequest.uri == 'http://proxy.pin/ssl' ||
httpRequest.requestUrl == 'http://127.0.0.1:${channel.socket.port}/ssl') {
_crtDownload(channel, httpRequest);
return;
}
var remoteChannel = await _getRemoteChannel(channel, httpRequest);
//实现抓包代理转发
if (httpRequest.method != HttpMethod.connect) {
// log.i("[${channel.id}] ${httpRequest.requestUrl}");
log.i("[${channel.id}] ${httpRequest.requestUrl}");
var replaceBody = requestRewrites?.findRequestReplaceWith(httpRequest.path);
if (replaceBody?.isNotEmpty == true) {
@@ -110,6 +132,15 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
clientChannel.putAttribute(AttributeKeys.host, hostAndPort);
var proxyHandler = HttpResponseProxyHandler(clientChannel, listener: listener, requestRewrites: requestRewrites);
HostAndPort? remote = clientChannel.getAttribute(AttributeKeys.remote);
if (remote != null) {
var proxyChannel = await HttpClients.connect(remote, proxyHandler);
clientChannel.putAttribute(clientId, proxyChannel);
proxyChannel.write(httpRequest);
return proxyChannel;
}
var proxyChannel = await HttpClients.connect(hostAndPort, proxyHandler);
clientChannel.putAttribute(clientId, proxyChannel);
@@ -134,7 +165,7 @@ class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
@override
void channelRead(Channel channel, HttpResponse msg) {
msg.request = clientChannel.getAttribute(AttributeKeys.request);
msg.request?.response= msg;
msg.request?.response = msg;
// log.i("[${clientChannel.id}] Response ${msg.bodyAsString}");
var replaceBody = requestRewrites?.findResponseReplaceWith(msg.request?.path);
@@ -172,10 +203,39 @@ class RelayHandler extends ChannelHandler<Object> {
class HttpClients {
/// 建立连接
static Future<Channel> connect(HostAndPort hostAndPort, ChannelHandler<HttpResponse> handler) async {
static Future<Channel> connect(HostAndPort hostAndPort, ChannelHandler handler) async {
var client = Client()
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), handler));
return client.connect(hostAndPort);
}
static Future<HttpResponse> get(String url, {Duration duration = const Duration(seconds: 3)}) async {
var httpResponseHandler = HttpResponseHandler();
var client = Client()
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), httpResponseHandler));
Channel channel = await client.connect(HostAndPort.of(url));
HttpRequest msg = HttpRequest(HttpMethod.get, url);
await channel.write(msg);
return httpResponseHandler.getResponse(duration).whenComplete(() => channel.close());
}
}
class HttpResponseHandler extends ChannelHandler<HttpResponse> {
final Completer<HttpResponse> _completer = Completer<HttpResponse>();
@override
void channelRead(Channel channel, HttpResponse msg) {
log.i("[${channel.id}] Response ${msg.bodyAsString}");
_completer.complete(msg);
channel.close();
}
Future<HttpResponse> getResponse(Duration duration) {
return _completer.future.timeout(duration);
}
}

View File

@@ -155,7 +155,7 @@ class HttpRequestCodec extends HttpCodec<HttpRequest> {
@override
HttpRequest createMessage(List<String> reqLine) {
HttpMethod httpMethod = HttpMethod.valueOf(reqLine[0]);
return HttpRequest(httpMethod, reqLine[1], reqLine[2]);
return HttpRequest(httpMethod, reqLine[1], protocolVersion: reqLine[2]);
}
@override

View File

@@ -58,7 +58,7 @@ class HttpRequest extends HttpMessage {
String? remoteDomain;
HttpResponse? response;
HttpRequest(this.method, this.uri, String protocolVersion) : super(protocolVersion);
HttpRequest(this.method, this.uri, {String protocolVersion = "HTTP/1.1"}) : super(protocolVersion);
@override
String toString() {

View File

@@ -2,6 +2,7 @@
/// 2023/5/23
interface class AttributeKeys {
static const String host = "HOST";
static const String uri= "URI";
static const String request= "REQUEST";
static const String uri = "URI";
static const String request = "REQUEST";
static const String remote = "REMOTE";
}