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");
    }
}