diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index 2cee4f09..5656d13a 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -29,8 +29,6 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; @@ -49,7 +47,6 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; -import androidx.core.content.ContextCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; @@ -77,13 +74,13 @@ public class CaptureService extends VpnService implements Runnable { private String vpn_dns; private String dns_server; private String collector_address; - private String tls_proxy_address; + private String socks5_proxy_address; private Prefs.DumpMode dump_mode; - private boolean tls_decryption_enabled; + private boolean socks5_enabled; private boolean ipv6_enabled; private int collector_port; private int http_server_port; - private int tls_proxy_port; + private int socks5_proxy_port; private long last_bytes; private int last_connections; private static CaptureService INSTANCE; @@ -186,9 +183,9 @@ public class CaptureService extends VpnService implements Runnable { collector_address = Prefs.getCollectorIp(prefs); collector_port = Prefs.getCollectorPort(prefs); http_server_port = Prefs.getHttpServerPort(prefs); - tls_decryption_enabled = Prefs.getTlsDecryptionEnabled(prefs); - tls_proxy_address = Prefs.getTlsProxyAddress(prefs); - tls_proxy_port = Prefs.getTlsProxyPort(prefs); + socks5_enabled = Prefs.getTlsDecryptionEnabled(prefs); // TODO rename + socks5_proxy_address = Prefs.getSocks5ProxyAddress(prefs); + socks5_proxy_port = Prefs.getSocks5ProxyPort(prefs); dump_mode = Prefs.getDumpMode(prefs); ipv6_enabled = Prefs.getIPv6Enabled(prefs); last_bytes = 0; @@ -541,11 +538,11 @@ public class CaptureService extends VpnService implements Runnable { return(collector_port); } - public String getTlsProxyAddress() { return(tls_proxy_address); } + public String getSocks5ProxyAddress() { return(socks5_proxy_address); } - public int getTlsDecryptionEnabled() { return tls_decryption_enabled ? 1 : 0; } + public int getSocks5Enabled() { return socks5_enabled ? 1 : 0; } - public int getTlsProxyPort() { return(tls_proxy_port); } + public int getSocks5ProxyPort() { return(socks5_proxy_port); } public int getIPv6Enabled() { return(ipv6_enabled ? 1 : 0); } diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/SettingsActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/SettingsActivity.java index 9e25ddae..d956f3bc 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/SettingsActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/SettingsActivity.java @@ -82,9 +82,9 @@ public class SettingsActivity extends BaseActivity { } public static class SettingsFragment extends PreferenceFragmentCompat { - private SwitchPreference mTlsDecryptionEnabled; - private EditTextPreference mTlsProxyIp; - private EditTextPreference mTlsProxyPort; + private SwitchPreference mTlsDecryptionEnabled; // TODO rename + private EditTextPreference mSocks5ProxyIp; + private EditTextPreference mSocks5ProxyPort; private Preference mTlsHelp; @Override @@ -93,10 +93,10 @@ public class SettingsActivity extends BaseActivity { setupUdpExporterPrefs(); setupHttpServerPrefs(); - setupTlsProxyPrefs(); + setupSocks5ProxyPrefs(); setupOtherPrefs(); - tlsDecryptionHideShow(mTlsDecryptionEnabled.isChecked()); + socks5ProxyHideShow(mTlsDecryptionEnabled.isChecked()); } private boolean validatePort(String value) { @@ -128,32 +128,35 @@ public class SettingsActivity extends BaseActivity { mHttpServerPort.setOnPreferenceChangeListener((preference, newValue) -> validatePort(newValue.toString())); } - private void setupTlsProxyPrefs() { + private void setupSocks5ProxyPrefs() { mTlsHelp = findPreference("tls_how_to"); mTlsDecryptionEnabled = findPreference(Prefs.PREF_TLS_DECRYPTION_ENABLED_KEY); mTlsDecryptionEnabled.setOnPreferenceChangeListener((preference, newValue) -> { - tlsDecryptionHideShow((Boolean) newValue); + socks5ProxyHideShow((Boolean) newValue); return true; }); /* TLS Proxy IP validation */ - mTlsProxyIp = findPreference(Prefs.PREF_TLS_PROXY_IP_KEY); - mTlsProxyIp.setOnPreferenceChangeListener((preference, newValue) -> { + mSocks5ProxyIp = findPreference(Prefs.PREF_SOCKS5_PROXY_IP_KEY); + mSocks5ProxyIp.setOnPreferenceChangeListener((preference, newValue) -> { Matcher matcher = Patterns.IP_ADDRESS.matcher(newValue.toString()); return(matcher.matches()); }); /* TLS Proxy port validation */ - mTlsProxyPort = findPreference(Prefs.PREF_TLS_PROXY_PORT_KEY); - mTlsProxyPort.setOnBindEditTextListener(editText -> editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED)); - mTlsProxyPort.setOnPreferenceChangeListener((preference, newValue) -> validatePort(newValue.toString())); + mSocks5ProxyPort = findPreference(Prefs.PREF_SOCKS5_PROXY_PORT_KEY); + mSocks5ProxyPort.setOnBindEditTextListener(editText -> editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED)); + mSocks5ProxyPort.setOnPreferenceChangeListener((preference, newValue) -> validatePort(newValue.toString())); } - private void tlsDecryptionHideShow(boolean decryptionEnabled) { - mTlsProxyIp.setVisible(decryptionEnabled); - mTlsProxyPort.setVisible(decryptionEnabled); - mTlsHelp.setVisible(decryptionEnabled); + private void socks5ProxyHideShow(boolean decryptionEnabled) { + mSocks5ProxyIp.setVisible(decryptionEnabled); + mSocks5ProxyPort.setVisible(decryptionEnabled); + + // TODO + //mTlsHelp.setVisible(decryptionEnabled); + mTlsHelp.setVisible(false); } private void setupOtherPrefs() { diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java index 5b691984..109eb1c7 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java @@ -29,8 +29,8 @@ public class Prefs { public static final String DUMP_PCAP_FILE = "pcap_file"; public static final String PREF_COLLECTOR_IP_KEY = "collector_ip_address"; public static final String PREF_COLLECTOR_PORT_KEY = "collector_port"; - public static final String PREF_TLS_PROXY_IP_KEY = "tls_proxy_ip_address"; - public static final String PREF_TLS_PROXY_PORT_KEY = "tls_proxy_port"; + public static final String PREF_SOCKS5_PROXY_IP_KEY = "socks5_proxy_ip_address"; + public static final String PREF_SOCKS5_PROXY_PORT_KEY = "socks5_proxy_port"; public static final String PREF_TLS_DECRYPTION_ENABLED_KEY = "tls_decryption_enabled"; public static final String PREF_APP_FILTER = "app_filter"; public static final String PREF_HTTP_SERVER_PORT = "http_server_port"; @@ -65,8 +65,8 @@ public class Prefs { public static DumpMode getDumpMode(SharedPreferences p) { return(getDumpMode(p.getString(PREF_PCAP_DUMP_MODE, DEFAULT_DUMP_MODE))); } public static int getHttpServerPort(SharedPreferences p) { return(Integer.parseInt(p.getString(Prefs.PREF_HTTP_SERVER_PORT, "8080"))); } public static boolean getTlsDecryptionEnabled(SharedPreferences p) { return(p.getBoolean(PREF_TLS_DECRYPTION_ENABLED_KEY, false)); } - public static String getTlsProxyAddress(SharedPreferences p) { return(p.getString(PREF_TLS_PROXY_IP_KEY, "0.0.0.0")); } - public static int getTlsProxyPort(SharedPreferences p) { return(Integer.parseInt(p.getString(Prefs.PREF_TLS_PROXY_PORT_KEY, "8080"))); } + public static String getSocks5ProxyAddress(SharedPreferences p) { return(p.getString(PREF_SOCKS5_PROXY_IP_KEY, "0.0.0.0")); } + public static int getSocks5ProxyPort(SharedPreferences p) { return(Integer.parseInt(p.getString(Prefs.PREF_SOCKS5_PROXY_PORT_KEY, "8080"))); } public static String getAppFilter(SharedPreferences p) { return(p.getString(PREF_APP_FILTER, "")); } public static boolean getIPv6Enabled(SharedPreferences p) { return(p.getBoolean(PREF_IPV6_ENABLED, false)); } public static boolean useEnglishLanguage(SharedPreferences p){ return("english".equals(p.getString(PREF_APP_LANGUAGE, "system")));} diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.c b/app/src/main/jni/vpnproxy-jni/vpnproxy.c index be15f5f1..72bc989b 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.c +++ b/app/src/main/jni/vpnproxy-jni/vpnproxy.c @@ -54,13 +54,6 @@ typedef struct dns_packet { /* ******************************************************* */ -typedef struct mitm_proxy_hdr { - uint32_t dst_ip; - uint16_t dst_port; -} __attribute__((packed)) mitm_proxy_hdr_t; - -/* ******************************************************* */ - typedef struct jni_methods { jmethodID getApplicationByUid; jmethodID protect; @@ -90,23 +83,6 @@ static bool dump_capture_stats_now = false; static ndpi_protocol_bitmask_struct_t masterProtos; static uint32_t new_dns_server = 0; -/* TCP/IP packet to hold the mitmproxy header */ -static char mitmproxy_pkt_buffer[] = { - "\x45\x00" \ - - /* Total length: 52 + 6 (sizeof mitm_proxy_hdr_t) */ - "\x00\x3a" \ - - "\xb8\x9e\x40\x00\x40\x06\xf7\xe1\x00\x00\x00\x00\x00\x00" \ - "\x00\x00\x00\x00\x00\x00\x65\xbf\xc2\xaf\x08\x93\x36\x09\x80\x18" \ - "\x01\xf5\x00\x00\x00\x00\x01\x01\x08\x0a\x6c\xe2\x4f\x95\x4a\xe0" \ - "\x92\x51" \ - - /* TCP payload */ - "\x01\x02\x03\x04\x05\x06" -}; -static zdtun_pkt_t mitm_pkt; - /* ******************************************************* */ /* NOTE: these must be reset during each run, as android may reuse the service */ @@ -742,49 +718,14 @@ static bool check_dns_req_allowed(struct vpnproxy_data *proxy, zdtun_conn_t *con /* ******************************************************* */ -/* - * Check if the packet should be redirected to the mitmproxy - */ -static void check_tls_mitm(zdtun_t *tun, struct vpnproxy_data *proxy, zdtun_pkt_t *pkt, zdtun_conn_t *conn) { +static void check_socks5_redirection(zdtun_t *tun, struct vpnproxy_data *proxy, zdtun_pkt_t *pkt, zdtun_conn_t *conn) { conn_data_t *data = zdtun_conn_get_userdata(conn); if(shouldIgnoreConn(proxy, zdtun_conn_get_5tuple(conn), data)) return; - if(pkt->tuple.ipproto == IPPROTO_TCP) { - uint32_t mitm_ip = proxy->tls_decryption.proxy_ip; - uint16_t mitm_port = proxy->tls_decryption.proxy_port; - - bool is_new = ((data->sent_pkts + data->rcvd_pkts) == 0); - - if(is_new) { - uint16_t port = ntohs(pkt->tuple.dst_port); - - if (port == 443) { - zdtun_ip_t dnatip = {0}; - dnatip.ip4 = mitm_ip; - zdtun_conn_dnat(conn, &dnatip, mitm_port); - data->mitm_header_needed = true; - } - } else if(data->mitm_header_needed && (pkt->l7_len > 0) && (pkt->tuple.ipver == 4)) { - // TODO allow IPv6 -> IPv4 redirection - /* First L7 packet, send the mitmproxy header first */ - mitm_proxy_hdr_t *mitm = (mitm_proxy_hdr_t*) mitm_pkt.l7; - - /* Fix the packet with the correct peers */ - mitm_pkt.tuple.src_ip.ip4 = mitm_pkt.ip4->saddr = pkt->ip4->saddr; - mitm_pkt.tuple.dst_ip.ip4 = mitm_pkt.ip4->daddr = mitm_ip; - mitm_pkt.tuple.src_port = mitm_pkt.tcp->th_sport = pkt->tcp->th_sport; - mitm_pkt.tuple.dst_port = mitm_pkt.tcp->th_dport = mitm_port; - - /* Send the original (pre-nat) IP and port */ - mitm->dst_ip = pkt->tuple.dst_ip.ip4; - mitm->dst_port = pkt->tuple.dst_port; - zdtun_send_oob(tun, &mitm_pkt, conn); - - data->mitm_header_needed = false; - } - } + if((pkt->tuple.ipproto == IPPROTO_TCP) && (((data->sent_pkts + data->rcvd_pkts) == 0))) + zdtun_conn_proxy(conn); } /* ******************************************************* */ @@ -1034,8 +975,6 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { init_log(ANDROID_LOG_DEBUG, env, vpn_class, vpn); - zdtun_parse_pkt(mitmproxy_pkt_buffer, sizeof(mitmproxy_pkt_buffer)-1, &mitm_pkt); - /* Classes */ cls.vpn_service = vpn_class; cls.conn = jniFindClass(env, "com/emanuelef/remote_capture/model/ConnectionDescriptor"); @@ -1076,10 +1015,10 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { .tcp_socket = false, .enabled = (bool) getIntPref(env, vpn, "dumpPcapToUdp"), }, - .tls_decryption = { - .enabled = (bool) getIntPref(env, vpn, "getTlsDecryptionEnabled"), - .proxy_ip = getIPv4Pref(env, vpn, "getTlsProxyAddress"), - .proxy_port = htons(getIntPref(env, vpn, "getTlsProxyPort")), + .socks5 = { + .enabled = (bool) getIntPref(env, vpn, "getSocks5Enabled"), + .proxy_ip = getIPv4Pref(env, vpn, "getSocks5ProxyAddress"), + .proxy_port = htons(getIntPref(env, vpn, "getSocks5ProxyPort")), }, .ipv6 = { .enabled = (bool) getIntPref(env, vpn, "getIPv6Enabled"), @@ -1161,6 +1100,12 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { } } + if(proxy.socks5.enabled) { + zdtun_ip_t dnatip = {0}; + dnatip.ip4 = proxy.socks5.proxy_ip; + zdtun_set_socks5_proxy(tun, &dnatip, proxy.socks5.proxy_port); + } + new_dns_server = 0; gettimeofday(&now_tv, NULL); now_ms = now_tv.tv_sec * 1000 + now_tv.tv_usec / 1000; @@ -1235,8 +1180,8 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { goto housekeeping; } - if(proxy.tls_decryption.enabled) - check_tls_mitm(tun, &proxy, &pkt, conn); + if(proxy.socks5.enabled) + check_socks5_redirection(tun, &proxy, &pkt, conn); if((rc = zdtun_forward(tun, &pkt, conn)) != 0) { char buf[512]; diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.h b/app/src/main/jni/vpnproxy-jni/vpnproxy.h index 41498428..de46038a 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.h +++ b/app/src/main/jni/vpnproxy-jni/vpnproxy.h @@ -57,7 +57,6 @@ typedef struct conn_data { char *url; jint uid; bool pending_notification; - bool mitm_header_needed; } conn_data_t; typedef struct vpn_conn { @@ -110,7 +109,7 @@ typedef struct vpnproxy_data { bool enabled; u_int32_t proxy_ip; u_int32_t proxy_port; - } tls_decryption; + } socks5; struct { bool enabled; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd36c264..3f87b1f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -121,5 +121,10 @@ Light Dark Theme + Enable SOCKS5 Proxy + When enabled, all the TCP connections will be redirected to the specified SOCKS5 proxy. + Proxy + Proxy IP Address + Proxy Port diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 2a4847a6..52efec28 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -43,12 +43,12 @@ app:useSimpleSummaryProvider="true" /> - + diff --git a/submodules/zdtun b/submodules/zdtun index a29c548a..e5d24d18 160000 --- a/submodules/zdtun +++ b/submodules/zdtun @@ -1 +1 @@ -Subproject commit a29c548af21f5e09a6111f3c08b7f8edf804991b +Subproject commit e5d24d18cad9ee460900955ec7cb12b32df0b7c2