mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-05-09 00:34:17 +08:00
安卓抓flutter请求
This commit is contained in:
@@ -3,16 +3,21 @@ import 'package:flutter/services.dart';
|
||||
class Vpn {
|
||||
static const MethodChannel proxyVpnChannel = MethodChannel('com.proxy/proxyVpn');
|
||||
|
||||
static bool isVpnStarted = false; //vpn是否已经启动
|
||||
|
||||
static startVpn(String host, int port, [List<String>? appList]) {
|
||||
proxyVpnChannel.invokeMethod("startVpn", {"proxyHost": host, "proxyPort": port, "allowApps": appList});
|
||||
isVpnStarted = true;
|
||||
}
|
||||
|
||||
static stopVpn() {
|
||||
proxyVpnChannel.invokeMethod("stopVpn");
|
||||
isVpnStarted = false;
|
||||
}
|
||||
|
||||
//重启vpn
|
||||
static restartVpn(String host, int port, [List<String>? appList]) {
|
||||
proxyVpnChannel.invokeMethod("restartVpn", {"proxyHost": host, "proxyPort": port, "allowApps": appList});
|
||||
isVpnStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class ProxyServer {
|
||||
channel.pipeline.handle(
|
||||
HttpRequestCodec(),
|
||||
HttpResponseCodec(),
|
||||
HttpChannelHandler(
|
||||
HttpProxyChannelHandler(
|
||||
listener: CombinedEventListener(listeners), requestRewrites: configuration.requestRewrites));
|
||||
});
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ class Channel {
|
||||
pipeline.listen(this);
|
||||
}
|
||||
|
||||
///是否是ssl链接
|
||||
bool get isSsl => _socket is SecureSocket;
|
||||
|
||||
Future<void> write(Object obj) async {
|
||||
if (isClosed) {
|
||||
logger.w("[$id] channel is closed");
|
||||
@@ -214,7 +217,7 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
|
||||
buffer.clear();
|
||||
|
||||
if (data is HttpRequest) {
|
||||
data.hostAndPort = channel.getAttribute(AttributeKeys.host) ?? getHostAndPort(data);
|
||||
data.hostAndPort = channel.getAttribute(AttributeKeys.host) ?? getHostAndPort(data, ssl: channel.isSsl);
|
||||
if (data.headers.host != null && data.headers.host?.contains(":") == false) {
|
||||
data.hostAndPort?.host = data.headers.host!;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,11 @@ abstract class EventListener {
|
||||
}
|
||||
|
||||
/// http请求处理器
|
||||
class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
class HttpProxyChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
EventListener? listener;
|
||||
RequestRewrites? requestRewrites;
|
||||
|
||||
HttpChannelHandler({this.listener, this.requestRewrites});
|
||||
HttpProxyChannelHandler({this.listener, this.requestRewrites});
|
||||
|
||||
@override
|
||||
void channelRead(Channel channel, HttpRequest msg) async {
|
||||
@@ -202,7 +202,7 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
return remoteChannel;
|
||||
}
|
||||
|
||||
var hostAndPort = getHostAndPort(httpRequest);
|
||||
var hostAndPort = httpRequest.hostAndPort ?? getHostAndPort(httpRequest);
|
||||
clientChannel.putAttribute(AttributeKeys.host, hostAndPort);
|
||||
|
||||
var proxyHandler = HttpResponseProxyHandler(clientChannel, listener: listener, requestRewrites: requestRewrites);
|
||||
@@ -226,6 +226,9 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
|
||||
if (httpRequest.method == HttpMethod.connect) {
|
||||
await clientChannel.write(
|
||||
HttpResponse(HttpStatus.ok.reason('Connection established'), protocolVersion: httpRequest.protocolVersion));
|
||||
} else if (clientChannel.isSsl) {
|
||||
proxyChannel.secureSocket = await SecureSocket.secure(proxyChannel.socket,
|
||||
host: hostAndPort.host, onBadCertificate: (certificate) => true);
|
||||
}
|
||||
return proxyChannel;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@ import 'package:network_proxy/network/http/http.dart';
|
||||
import 'package:network_proxy/network/http/http_headers.dart';
|
||||
|
||||
/// 获取主机和端口
|
||||
HostAndPort getHostAndPort(HttpRequest request) {
|
||||
HostAndPort getHostAndPort(HttpRequest request, {bool? ssl}) {
|
||||
String requestUri = request.uri;
|
||||
//有些请求直接是路径 /xxx, 从header取host
|
||||
if (request.uri.startsWith("/")) {
|
||||
requestUri = request.headers.get(HttpHeaders.HOST)!;
|
||||
}
|
||||
|
||||
return HostAndPort.of(requestUri);
|
||||
return HostAndPort.of(requestUri, ssl: ssl);
|
||||
}
|
||||
|
||||
class HostAndPort {
|
||||
|
||||
@@ -24,6 +24,7 @@ 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 'package:network_proxy/network/util/tls.dart';
|
||||
import 'package:network_proxy/utils/platform.dart';
|
||||
|
||||
import 'host_port.dart';
|
||||
@@ -70,12 +71,11 @@ class Network {
|
||||
}
|
||||
|
||||
//ssl握手
|
||||
if (hostAndPort?.isSsl() == true || (data.length > 3 && data.first == 0x16 && data[1] == 0x03 && data[2] == 0x01)) {
|
||||
if (hostAndPort?.isSsl() == true || (data.length > 2 && data.first == 0x16 && data[1] == 0x03)) {
|
||||
if (hostAndPort?.scheme == HostAndPort.httpScheme) {
|
||||
hostAndPort?.scheme = HostAndPort.httpsScheme;
|
||||
}
|
||||
|
||||
ssl(channel, hostAndPort!, data);
|
||||
ssl(channel, hostAndPort, data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,16 +83,18 @@ class Network {
|
||||
}
|
||||
|
||||
/// ssl握手
|
||||
void ssl(Channel channel, HostAndPort hostAndPort, Uint8List data) async {
|
||||
void ssl(Channel channel, HostAndPort? hostAndPort, Uint8List data) async {
|
||||
try {
|
||||
Channel? remoteChannel = channel.getAttribute(channel.id);
|
||||
if (remoteChannel != null) {
|
||||
remoteChannel.secureSocket = await SecureSocket.secure(remoteChannel.socket,
|
||||
host: hostAndPort.host, onBadCertificate: (certificate) => true);
|
||||
host: hostAndPort?.host, onBadCertificate: (certificate) => true);
|
||||
}
|
||||
String? host = hostAndPort?.host;
|
||||
host ??= TLS.getDomain(data);
|
||||
|
||||
//ssl自签证书
|
||||
var certificate = await CertificateManager.getCertificateContext(hostAndPort.host);
|
||||
var certificate = await CertificateManager.getCertificateContext(host!);
|
||||
//服务端等待客户端ssl握手
|
||||
channel.secureSocket = await SecureSocket.secureServer(channel.socket, certificate, bufferedData: data);
|
||||
} catch (error, trace) {
|
||||
|
||||
52
lib/network/util/tls.dart
Normal file
52
lib/network/util/tls.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
class TLS {
|
||||
///从TLS Client Hello 解析域名
|
||||
static String? getDomain(Uint8List data) {
|
||||
try {
|
||||
int sessionLength = data[43];
|
||||
int pos = 44 + sessionLength;
|
||||
if (data.length < pos + 2) return null;
|
||||
|
||||
int cipherSuitesLength = data.buffer.asByteData().getUint16(pos);
|
||||
pos += 2 + cipherSuitesLength;
|
||||
if (data.length < pos + 1) return null;
|
||||
|
||||
int compressionMethodsLength = data[pos];
|
||||
pos += 1 + compressionMethodsLength;
|
||||
if (data.length < pos + 2) return null;
|
||||
|
||||
int extensionsLength = data.buffer.asByteData().getUint16(pos);
|
||||
pos += 2;
|
||||
if (data.length < pos + extensionsLength) return null;
|
||||
|
||||
int end = pos + extensionsLength;
|
||||
while (pos + 4 <= end) {
|
||||
int extensionType = data.buffer.asByteData().getUint16(pos);
|
||||
int extensionLength = data.buffer.asByteData().getUint16(pos + 2);
|
||||
pos += 4;
|
||||
|
||||
if (extensionType == 0 /* server_name */) {
|
||||
if (pos + 5 > end) return null;
|
||||
int serverNameListLength = data.buffer.asByteData().getUint16(pos);
|
||||
pos += 2;
|
||||
if (pos + serverNameListLength > end) return null;
|
||||
|
||||
int serverNameType = data[pos];
|
||||
int serverNameLength = data.buffer.asByteData().getUint16(pos + 1);
|
||||
pos += 3;
|
||||
if (serverNameType != 0 /* host_name */) return null;
|
||||
if (pos + serverNameLength > end) return null;
|
||||
|
||||
return String.fromCharCodes(data.sublist(pos, pos + serverNameLength));
|
||||
} else {
|
||||
pos += extensionLength;
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Ignore errors, just return null
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ class MobileHistory extends StatefulWidget {
|
||||
final ProxyServer proxyServer;
|
||||
final GlobalKey<RequestListState> requestStateKey;
|
||||
|
||||
const MobileHistory({Key? key, required this.proxyServer, required this.requestStateKey}) : super(key: key);
|
||||
const MobileHistory({super.key, required this.proxyServer, required this.requestStateKey});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
@@ -92,7 +92,7 @@ class _MobileHistoryState extends State<MobileHistory> {
|
||||
|
||||
//导入har
|
||||
import(HistoryStorage storage) async {
|
||||
const XTypeGroup typeGroup = XTypeGroup(label: 'Har', extensions: <String>['har']);
|
||||
const XTypeGroup typeGroup = XTypeGroup(label: 'har', extensions: <String>['har'], uniformTypeIdentifiers: ["public.item"]);
|
||||
final XFile? file = await openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
|
||||
if (file == null) {
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_toastr/flutter_toastr.dart';
|
||||
import 'package:network_proxy/native/vpn.dart';
|
||||
import 'package:network_proxy/network/bin/server.dart';
|
||||
import 'package:network_proxy/network/host_port.dart';
|
||||
import 'package:network_proxy/network/http/http.dart';
|
||||
@@ -123,11 +124,12 @@ class RequestEditorState extends State<MobileRequestEditor> with SingleTickerPro
|
||||
var headers = requestKey.currentState?.getHeaders();
|
||||
var requestBody = requestKey.currentState?.getBody();
|
||||
|
||||
HttpRequest request = HttpRequest(HttpMethod.valueOf(currentState.requestMethod), Uri.encodeFull(currentState.requestUrl));
|
||||
HttpRequest request =
|
||||
HttpRequest(HttpMethod.valueOf(currentState.requestMethod), Uri.encodeFull(currentState.requestUrl));
|
||||
request.headers.addAll(headers);
|
||||
request.body = requestBody == null ? null : utf8.encode(requestBody);
|
||||
|
||||
var proxyInfo = widget.proxyServer?.isRunning == true ? ProxyInfo.of("127.0.0.1", widget.proxyServer!.port) : null;
|
||||
var proxyInfo = Vpn.isVpnStarted ? ProxyInfo.of("127.0.0.1", widget.proxyServer!.port) : null;
|
||||
HttpClients.proxyRequest(proxyInfo: proxyInfo, request).then((response) {
|
||||
FlutterToastr.show('请求成功', context);
|
||||
this.response = response;
|
||||
|
||||
Reference in New Issue
Block a user