package org.zarroboogs.smartzpn.tunnel.httpconnect; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import org.zarroboogs.smartzpn.SmartZpnApplication; import org.zarroboogs.smartzpn.core.ProxyConfigLoader; import org.zarroboogs.smartzpn.tunnel.Tunnel; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.util.Locale; import java.util.UUID; public class HttpConnectTunnel extends Tunnel { private boolean mTunnelEstablished; private HttpConnectConfig mConfig; public HttpConnectTunnel(HttpConnectConfig config, Selector selector) throws IOException { super(config.ServerAddress, selector); mConfig = config; } @Override protected void onConnected(ByteBuffer buffer) throws Exception { String request = String.format(Locale.ENGLISH, "CONNECT %s:%d HTTP/1.0\r\nProxy-Connection: keep-alive\r\nUser-Agent: %s\r\nX-App-Install-ID: %s\r\n\r\n", m_DestAddress.getHostName(), m_DestAddress.getPort(), ProxyConfigLoader.getsInstance().getUserAgent(), getAppInstallID()); buffer.clear(); buffer.put(request.getBytes()); buffer.flip(); if (this.write(buffer, true)) {//发送连接请求到代理服务器 this.beginReceive();//开始接收代理服务器响应数据 } } String getAppInstallID() { SharedPreferences preferences = SmartZpnApplication.getContext().getSharedPreferences("SmartProxy", Context.MODE_PRIVATE); String appInstallID = preferences.getString("AppInstallID", null); if (appInstallID == null || appInstallID.isEmpty()) { appInstallID = UUID.randomUUID().toString(); SharedPreferences.Editor editor = preferences.edit(); editor.putString("AppInstallID", appInstallID); editor.commit(); } return appInstallID; } String getVersionName() { try { PackageManager packageManager = SmartZpnApplication.getContext().getPackageManager(); // getPackageName()是你当前类的包名,0代表是获取版本信息 PackageInfo packInfo = packageManager.getPackageInfo(SmartZpnApplication.getContext().getPackageName(), 0); String version = packInfo.versionName; return version; } catch (Exception e) { return "0.0"; } } void trySendPartOfHeader(ByteBuffer buffer) throws Exception { int bytesSent = 0; if (buffer.remaining() > 10) { int pos = buffer.position() + buffer.arrayOffset(); String firString = new String(buffer.array(), pos, 10).toUpperCase(); if (firString.startsWith("GET /") || firString.startsWith("POST /")) { int limit = buffer.limit(); buffer.limit(buffer.position() + 10); super.write(buffer, false); bytesSent = 10 - buffer.remaining(); buffer.limit(limit); if (ProxyConfigLoader.IS_DEBUG) System.out.printf("Send %d bytes(%s) to %s\n", bytesSent, firString, m_DestAddress); } } } @Override protected void beforeSend(ByteBuffer buffer) throws Exception { if (ProxyConfigLoader.getsInstance().isIsolateHttpHostHeader()) { trySendPartOfHeader(buffer);//尝试发送请求头的一部分,让请求头的host在第二个包里面发送,从而绕过机房的白名单机制。 } } @Override protected void afterReceived(ByteBuffer buffer) throws Exception { if (!mTunnelEstablished) { //收到代理服务器响应数据 //分析响应并判断是否连接成功 String response = new String(buffer.array(), buffer.position(), 12); if (response.matches("^HTTP/1.[01] 200$")) { buffer.limit(buffer.position()); } else { throw new Exception(String.format("Proxy server responsed an error: %s", response)); } mTunnelEstablished = true; super.onTunnelEstablished(); } } @Override protected boolean isTunnelEstablished() { return mTunnelEstablished; } @Override protected void onDispose() { mConfig = null; } }