NetCapture v2.1.82021972349版本的 MD5 值为:dfbd8054127041af5d65fa43eaf2e1d0
以下内容为反编译后的 CaptureVpnService.java 源代码,内容仅作参考
package com.minhui.vpn.service;
import android.content.Intent;
import android.net.VpnService;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.minhui.vpn.ProxyConfig;
import com.minhui.vpn.VpnServiceHelper;
import com.minhui.vpn.desktop.DesktopManager;
import com.minhui.vpn.http.HttpRequestHeaderParser;
import com.minhui.vpn.log.VPNLog;
import com.minhui.vpn.nat.ConversationManager;
import com.minhui.vpn.nat.NatSession;
import com.minhui.vpn.nat.NatSessionManager;
import com.minhui.vpn.parser.CommonMethods;
import com.minhui.vpn.ping.SSLJudge;
import com.minhui.vpn.processparse.DefaultAppManager;
import com.minhui.vpn.proxy.TcpProxyServer;
import com.minhui.vpn.tcpip.IPHeader;
import com.minhui.vpn.tcpip.TCPHeader;
import com.minhui.vpn.tunnel.UDPServer;
import com.minhui.vpn.udpip.Packet;
import com.minhui.vpn.utils.ThreadProxy;
import com.minhui.vpn.utils.TimeFormatUtil;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.ConcurrentLinkedQueue;
import kotlin.UShort;
public class CaptureVpnService extends VpnService implements Runnable {
private static final int FOR_GROUND_ID = 101;
private static int ID = 0;
private static int LOCAL_IP = 0;
private static final boolean LOG_DEBUG = false;
public static final int MUTE_SIZE = 5120;
private static final String TAG = "CaptureVpnService";
private static final String VPN_ROUTE = "0.0.0.0";
public static String lastVpnStartTimeFormat;
public static long vpnStartTime;
Handler handler;
private FileInputStream in;
private FileChannel inputChannel;
private boolean isRunning = false;
private TcpProxyServer mTcpProxyServer;
private ParcelFileDescriptor mVPNInterface;
private FileOutputStream mVPNOutputStream;
private Thread mVPNThread;
private ConcurrentLinkedQueue<ByteBuffer> outputQueue;
private String selectPackage;
private UDPServer udpServer;
private static final String GOOGLE_DNS_FIRST = "8.8.8.8";
private static final String GOOGLE_DNS_SECOND = "8.8.4.4";
private static final String AMERICA = "208.67.222.222";
private static final String CHINA_DNS_FIRST = "114.114.114.114";
public static final String[] DNS_IPS = {GOOGLE_DNS_FIRST, GOOGLE_DNS_SECOND, AMERICA, CHINA_DNS_FIRST};
private void log(String str, String str2) {
}
public CaptureVpnService() {
ID++;
this.handler = new Handler(Looper.getMainLooper());
log(TAG, "New VPNService \n" + ID);
}
public static boolean isDNSIP(String str) {
for (String str2 : DNS_IPS) {
if (str2.equals(str)) {
return true;
}
}
return false;
}
@Override
public void onCreate() {
log(TAG, "VPNService created.\n" + ID);
VpnServiceHelper.onVpnServiceCreated(this);
Thread thread = new Thread(this, "VPNServiceThread");
this.mVPNThread = thread;
thread.start();
setVpnRunningStatus(true);
ConversationManager.getInstance().init(getApplicationContext());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int i, int i2) {
return super.onStartCommand(intent, i, i2);
}
@Override
public void onDestroy() {
VPNLog.i("VPNService(%s) destroyed " + ID);
Thread thread = this.mVPNThread;
if (thread != null) {
thread.interrupt();
}
VpnServiceHelper.onVpnServiceDestroy();
super.onDestroy();
}
private void runVPN() throws Exception {
this.mVPNInterface = establishVPN();
startStream();
}
private void startStream() throws Exception {
this.mVPNOutputStream = new FileOutputStream(this.mVPNInterface.getFileDescriptor());
FileInputStream fileInputStream = new FileInputStream(this.mVPNInterface.getFileDescriptor());
this.in = fileInputStream;
this.inputChannel = fileInputStream.getChannel();
final ByteBuffer byteBuffer = null;
boolean z = true;
while (this.isRunning) {
if (z) {
byteBuffer = ByteBuffer.allocate(MUTE_SIZE);
} else {
byteBuffer.clear();
}
boolean z2 = false;
if (this.inputChannel.read(byteBuffer) <= 0) {
z = false;
} else {
if (this.mTcpProxyServer.stopped) {
this.in.close();
throw new Exception("LocalServer stopped.");
}
byteBuffer.flip();
ThreadProxy.getInstance().execute(new Runnable() {
@Override
public void run() {
try {
CaptureVpnService.this.onIPPacketReceived(byteBuffer);
} catch (Exception e) {
e.printStackTrace();
}
}
});
z = true;
}
ByteBuffer poll = this.outputQueue.poll();
if (poll != null) {
this.mVPNOutputStream.write(poll.array(), 0, poll.limit());
z2 = true;
}
if (!z && !z2) {
Thread.sleep(10L);
}
}
this.in.close();
disconnectVPN();
}
void onIPPacketReceived(ByteBuffer byteBuffer) throws IOException {
byte protocol = new IPHeader(byteBuffer.array(), 0).getProtocol();
if (protocol == 6) {
onTcpPacketReceived(byteBuffer);
} else {
if (protocol != 17) {
return;
}
onUdpPacketReceived(byteBuffer);
}
}
private void onUdpPacketReceived(ByteBuffer byteBuffer) throws UnknownHostException {
IPHeader iPHeader = new IPHeader(byteBuffer.array(), 0);
Packet packet = new Packet(byteBuffer);
short s = packet.udpHeader.sourcePort;
short s2 = packet.udpHeader.destinationPort;
NatSession session = NatSessionManager.getSession(s);
if (session == null || session.remoteIP != iPHeader.getDestinationIP() || session.remotePort != s2) {
session = NatSessionManager.createSession(s, iPHeader.getSourceIP(), iPHeader.getDestinationIP(), s2, NatSession.UDP);
session.vpnStartTime = vpnStartTime;
}
session.lastRefreshTime = System.currentTimeMillis();
session.tcpOrUdpPacketSent++;
this.udpServer.processUDPPacket(packet, s);
}
private void onTcpPacketReceived(ByteBuffer byteBuffer) throws IOException {
IPHeader iPHeader = new IPHeader(byteBuffer.array(), 0);
TCPHeader tCPHeader = new TCPHeader(byteBuffer.array(), 20);
tCPHeader.mOffset = iPHeader.getHeaderLength();
if (tCPHeader.getSourcePort() == this.mTcpProxyServer.port) {
NatSession session = NatSessionManager.getSession(tCPHeader.getDestinationPort());
if (session != null) {
iPHeader.setSourceIP(iPHeader.getDestinationIP());
tCPHeader.setSourcePort(session.remotePort);
iPHeader.setDestinationIP(LOCAL_IP);
CommonMethods.ComputeTCPChecksum(iPHeader, tCPHeader);
byteBuffer.position(byteBuffer.limit());
this.outputQueue.offer(byteBuffer);
session.tcpOrUdpReceiveByteNum += byteBuffer.limit();
log(TAG + (session.getLocalPort() & UShort.MAX_VALUE), "process tcp packet from net " + tCPHeader);
session.tcpOrUdpReceivePacketNum = session.tcpOrUdpReceivePacketNum + 1;
session.lastRefreshTime = System.currentTimeMillis();
if (tCPHeader.isFinish()) {
refreshFinishState(session, 2);
return;
}
return;
}
log(TAG, "NoSession: \n" + iPHeader.toString() + tCPHeader.toString());
return;
}
short sourcePort = tCPHeader.getSourcePort();
NatSession session2 = NatSessionManager.getSession(sourcePort);
if (session2 == null || session2.remoteIP != iPHeader.getDestinationIP() || session2.remotePort != tCPHeader.getDestinationPort()) {
session2 = NatSessionManager.createSession(sourcePort, iPHeader.getSourceIP(), iPHeader.getDestinationIP(), tCPHeader.getDestinationPort(), NatSession.TCP);
session2.vpnStartTime = vpnStartTime;
}
String str = TAG + (65535 & session2.getLocalPort());
log(str, "process tcp packet to net " + tCPHeader);
session2.tcpOrUdpPacketSent = session2.tcpOrUdpPacketSent + 1;
int dataLength = iPHeader.getDataLength() - tCPHeader.getHeaderLength();
if (session2.tcpOrUdpPacketSent == 2 && dataLength == 0) {
return;
}
if (session2.tcpOrUpdBytesSent == 0 && dataLength > 10) {
HttpRequestHeaderParser.parseHttpRequestHeader(session2, tCPHeader.mData, tCPHeader.mOffset + tCPHeader.getHeaderLength(), dataLength);
log(str, "Host:\n" + session2.remoteHost);
log(str, "Request: \n" + session2.method + session2.requestUrl);
if (session2.pgName == null) {
session2.refreshUID();
}
} else if (session2.tcpOrUpdBytesSent > 0 && !session2.isHttpsSession && session2.isHttp && session2.remoteHost == null && session2.requestUrl == null) {
session2.remoteHost = HttpRequestHeaderParser.getRemoteHost(tCPHeader.mData, tCPHeader.mOffset + tCPHeader.getHeaderLength(), dataLength);
session2.requestUrl = "http://" + session2.remoteHost + "/" + session2.pathUrl;
if (session2.pgName == null) {
session2.refreshUID();
}
}
iPHeader.setSourceIP(iPHeader.getDestinationIP());
iPHeader.setDestinationIP(LOCAL_IP);
tCPHeader.setDestinationPort(this.mTcpProxyServer.port);
CommonMethods.ComputeTCPChecksum(iPHeader, tCPHeader);
byteBuffer.position(byteBuffer.limit());
this.outputQueue.offer(byteBuffer);
session2.tcpOrUpdBytesSent += dataLength;
if (tCPHeader.isFinish()) {
refreshFinishState(session2, 4);
}
}
private void refreshFinishState(final NatSession natSession, int i) {
natSession.refreshFinishState(i);
if (natSession.hasAllFinish()) {
this.handler.postDelayed(new Runnable() {
@Override
public void run() {
NatSessionManager.removeSession(natSession.getLocalPort());
}
}, 500L);
}
}
private void waitUntilPrepared() {
while (prepare(this) != null) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
log(TAG, "waitUntilPrepared catch an exception %s\n" + e.getMessage());
}
}
}
private ParcelFileDescriptor establishVPN() throws Exception {
VpnService.Builder builder = new VpnService.Builder(this);
builder.setMtu(MUTE_SIZE);
this.selectPackage = ProxyConfig.Instance.getSelectPG();
log(TAG, "setMtu: \n" + ProxyConfig.Instance.getMTU());
ProxyConfig.IPAddress defaultLocalIP = ProxyConfig.Instance.getDefaultLocalIP();
LOCAL_IP = CommonMethods.ipStringToInt(defaultLocalIP.Address);
builder.addAddress(defaultLocalIP.Address, defaultLocalIP.PrefixLength);
log(TAG, "addAddress: %s/%d\n" + defaultLocalIP.Address + defaultLocalIP.PrefixLength);
builder.addRoute(VPN_ROUTE, 0);
for (String str : DNS_IPS) {
builder.addDnsServer(str);
}
try {
if (this.selectPackage != null && Build.VERSION.SDK_INT >= 21) {
builder.addAllowedApplication(this.selectPackage);
builder.addAllowedApplication(getPackageName());
}
} catch (Exception e) {
VPNLog.e(TAG, "failed to establishVPN msg = " + e.getMessage());
}
builder.setSession(VpnServiceHelper.getName());
return builder.establish();
}
@Override
public void run() {
try {
try {
log(TAG, "VPNService(%s) work thread is Running..." + ID);
long currentTimeMillis = System.currentTimeMillis();
vpnStartTime = currentTimeMillis;
lastVpnStartTimeFormat = TimeFormatUtil.formatYYMMDDHHMMSS(currentTimeMillis);
waitUntilPrepared();
this.outputQueue = new ConcurrentLinkedQueue<>();
TcpProxyServer tcpProxyServer = new TcpProxyServer(0);
this.mTcpProxyServer = tcpProxyServer;
tcpProxyServer.start();
UDPServer uDPServer = new UDPServer(this, this.outputQueue);
this.udpServer = uDPServer;
uDPServer.start();
NatSessionManager.clearAllSession();
log(TAG, "DnsProxy started.");
ConversationManager.getInstance().clear();
ProxyConfig.Instance.onVpnStart(this);
if (ProxyConfig.Instance.isSendToDesktop()) {
DesktopManager.getInstance().start(ProxyConfig.Instance.getClientIP());
}
while (this.isRunning) {
runVPN();
}
} catch (InterruptedException e) {
VPNLog.e(TAG, "VpnService run catch an exception " + e.getMessage());
e.printStackTrace();
} catch (Exception e2) {
VPNLog.e(TAG, "VpnService run catch an exception " + e2.getMessage());
e2.printStackTrace();
}
} finally {
log(TAG, "VpnService terminated");
ProxyConfig.Instance.onVpnEnd(this);
dispose();
}
}
public void disconnectVPN() {
try {
if (this.mVPNInterface != null) {
this.mVPNInterface.close();
this.mVPNInterface = null;
}
} catch (Exception e) {
VPNLog.e(TAG, "failed to disconnectVPN msg = " + e.getMessage());
}
this.mVPNOutputStream = null;
}
private synchronized void dispose() {
try {
disconnectVPN();
} catch (Exception unused) {
}
try {
if (this.mTcpProxyServer != null) {
this.mTcpProxyServer.stop();
this.mTcpProxyServer = null;
log(TAG, "TcpProxyServer stopped.");
}
} catch (Exception unused2) {
}
try {
this.udpServer.closeAllUDPConn();
} catch (Exception unused3) {
}
ThreadProxy.getInstance().execute(new Runnable() {
@Override
public void run() {
SSLJudge.getInstance().saveData();
DefaultAppManager.getsInstance().saveData();
}
});
stopSelf();
setVpnRunningStatus(false);
this.handler.postDelayed(new Runnable() {
@Override
public void run() {
if (CaptureVpnService.this.isRunning) {
return;
}
DesktopManager.getInstance().stop();
}
}, 3000L);
}
public boolean vpnRunningStatus() {
return this.isRunning;
}
public void setVpnRunningStatus(boolean z) {
this.isRunning = z;
}
@Override
protected void dump(FileDescriptor fileDescriptor, PrintWriter printWriter, String[] strArr) {
super.dump(fileDescriptor, printWriter, strArr);
Log.d(TAG, "dump start");
VpnServiceDumpHelper.dump(strArr);
printWriter.print("dump CaptureVpnService");
Log.d(TAG, "dump end");
}
}