From 76fb4ff6671417f844c5e77fdb42c12adcdcb93c Mon Sep 17 00:00:00 2001 From: chendefine Date: Sat, 30 Mar 2019 17:22:11 +0800 Subject: [PATCH] [v1.0.1] Add Transparent proxy iptables script. --- META-INF/com/google/android/update-binary | 155 +++++++++++++++++++++- README.md | 66 ++++++++- common/service.sh | 2 +- install.sh | 4 +- module.prop | 2 +- system/placeholder | 1 - uninstall.sh | 11 ++ v2ray/etc/config.json | 38 ++++-- v2ray/etc/v2ray.redirect | 149 +++++++++++++++++++++ v2ray/etc/v2ray.service | 21 ++- 10 files changed, 424 insertions(+), 25 deletions(-) delete mode 100644 system/placeholder create mode 100644 uninstall.sh create mode 100644 v2ray/etc/v2ray.redirect diff --git a/META-INF/com/google/android/update-binary b/META-INF/com/google/android/update-binary index 08bd14f..614871c 100644 --- a/META-INF/com/google/android/update-binary +++ b/META-INF/com/google/android/update-binary @@ -1,10 +1,151 @@ #!/sbin/sh -# This is a dummy file that should be replaced with a proper installer script -# If you are creating a module locally for personal usage or testing, -# download the script in the following URL: -# https://github.com/topjohnwu/Magisk/blob/master/scripts/module_installer.sh -# And replace this script with the downloaded script +TMPDIR=/dev/tmp +MOUNTPATH=/dev/magisk_img -# Error, this script should always be replaced -exit 1 +# Default permissions +umask 022 + +# Initial cleanup +rm -rf $TMPDIR 2>/dev/null +mkdir -p $TMPDIR + +# echo before loading util_functions +ui_print() { echo "$1"; } + +require_new_magisk() { + ui_print "***********************************" + ui_print " Please install the latest Magisk! " + ui_print "***********************************" + exit 1 +} + +imageless_magisk() { + [ $MAGISK_VER_CODE -gt 18100 ] + return $? +} + +########################################################################################## +# Environment +########################################################################################## + +OUTFD=$2 +ZIPFILE=$3 + +mount /data 2>/dev/null + +# Load utility functions +if [ -f /data/adb/magisk/util_functions.sh ]; then + . /data/adb/magisk/util_functions.sh + NVBASE=/data/adb +else + require_new_magisk +fi + +# Preperation for flashable zips +setup_flashable + +# Mount partitions +mount_partitions + +# Detect version and architecture +api_level_arch_detect + +# Setup busybox and binaries +$BOOTMODE && boot_actions || recovery_actions + +########################################################################################## +# Preparation +########################################################################################## + +# Extract common files +unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 + +[ ! -f $TMPDIR/install.sh ] && abort "! Unable to extract zip file!" +# Load install script +. $TMPDIR/install.sh + +if imageless_magisk; then + $BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules + MODULEROOT=$NVBASE/$MODDIRNAME +else + $BOOTMODE && IMGNAME=magisk_merge.img || IMGNAME=magisk.img + IMG=$NVBASE/$IMGNAME + request_zip_size_check "$ZIPFILE" + mount_magisk_img + MODULEROOT=$MOUNTPATH +fi + +MODID=`grep_prop id $TMPDIR/module.prop` +MODPATH=$MODULEROOT/$MODID + +print_modname + +ui_print "******************************" +ui_print "Powered by Magisk (@topjohnwu)" +ui_print "******************************" + +########################################################################################## +# Install +########################################################################################## + +# Create mod paths +rm -rf $MODPATH 2>/dev/null +mkdir -p $MODPATH + +# Remove placeholder +rm -f $MODPATH/system/placeholder 2>/dev/null + +# Custom uninstaller +[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh + +# Auto Mount +if imageless_magisk; then + $SKIPMOUNT && touch $MODPATH/skip_mount +else + $SKIPMOUNT || touch $MODPATH/auto_mount +fi + +# prop files +$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop + +# Module info +cp -af $TMPDIR/module.prop $MODPATH/module.prop +if $BOOTMODE; then + # Update info for Magisk Manager + if imageless_magisk; then + mktouch $NVBASE/modules/$MODID/update + cp -af $TMPDIR/module.prop $NVBASE/modules/$MODID/module.prop + else + mktouch /sbin/.magisk/img/$MODID/update + cp -af $TMPDIR/module.prop /sbin/.magisk/img/$MODID/module.prop + fi +fi + +# post-fs-data mode scripts +$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh + +# service mode scripts +$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh + +on_install + +# Handle replace folders +for TARGET in $REPLACE; do + mktouch $MODPATH$TARGET/.replace +done + +ui_print "- Setting permissions" +set_permissions + +########################################################################################## +# Finalizing +########################################################################################## + +cd / +imageless_magisk || unmount_magisk_img +$BOOTMODE || recovery_cleanup +rm -rf $TMPDIR $MOUNTPATH + +ui_print "- Done" +exit 0 diff --git a/README.md b/README.md index 902e595..abfcfe4 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,11 @@ This is a v2ray module for Magisk, and includes binaries for arm, arm64, x86, x6 ## Included -* [V2Ray]() +* [V2Ray core]() * [magisk-module-installer](https://github.com/topjohnwu/magisk-module-installer) +- V2Ray service script and Android transparent proxy iptables script + ## Install @@ -19,9 +21,13 @@ This is a v2ray module for Magisk, and includes binaries for arm, arm64, x86, x6 ## Config -V2ray config file is store in `/data/v2ray/config.json` . +- V2ray config file is store in `/data/v2ray/config.json` . + + +- Please make sure the config is correct. You can check it by running a command : + + `export V2RAY_LOCATION_ASSET=/data/v2ray; v2ray -test -config /data/v2ray/config.json` in android terminal. -Please make sure the config is correct. You can do that by running a command `v2ray -test -config /data/v2ray/config.json` in android terminal. @@ -29,7 +35,7 @@ Please make sure the config is correct. You can do that by running a command `v2 - V2ray service is autorun on boot. If you don't want it run automatically, you can just add a file `/data/v2ray/no-autostart` . -- You can also start / stop manually by run the service script in `$MODDIR` . For example, in my environment , the script's absolute path is `/sbin/.magisk/img/v2ray/v2ray.service` . +- You can start / stop manually by execute the service script in `$MODDIR/v2ray.service` . For example, in my environment , the script's absolute path is `/sbin/.magisk/img/v2ray/v2ray.service` . - So, if you want to start v2ray service, just run: @@ -43,12 +49,62 @@ Please make sure the config is correct. You can do that by running a command `v2 `/sbin/.magisk/img/v2ray/v2ray.service restart` +## Transparent proxy + +### Working principle + +This module also contains a simple script that helping you to make transparent proxy via iptables. In fact , the script is just make some REDIRECT and TPROXY rules to redirect app's network into 65535 port in localhost. And 65535 port is listen by v2ray inbond with dokodemo-door protocol. In summarize, the App proxy network path is looks like : + + + +**Android App** ( Browser, Google, Facebook, Twitter ... ... ) + + ⇕ ( TCP & UDP network protocol ) + +Android system **iptables** [ localhost inside ] + + ⇕ ( REDIRECT & TPROXY iptables rules ) + +127.0.0.1:65535 [ Inbond ] ----- **V2Ray** ----- [ Outbond ] + +​ ( Shadowsocks, Vmess ) ⇕ + + [ Internet outside ] ( SS, V2Ray) **Proxy Server** + +​ ( HTTP, TCP, ... other application protocol ) ⇕ + + ( Google, Facebook, Twitter ... ... ) **App Server** + + + +### Choose proxy target + +- Select mode : You can write a list of App's uid into `/data/v2ray/appid.list` file so that the script would select these App's network proxy via V2Ray. Each App's uid should separate by space or just One App's uid per line. + +- Global mode : You can write a single number "0" into `/data/v2ray/appid.list` file to make all App's network proxy via V2Ray. + + + +### Enable/Disable proxy + +- Only when the V2Ray service start normally on boot and `/data/v2ray/appid.list` file is not empty, the transparent proxy iptables script can run automatically. + +- Otherwise, you can execute iptables script in `$MODDIR/v2ray.redirect` . For example, in my environment: + + Enable transparent proxy: + + `/sbin/.magisk/img/v2ray/v2ray.redirect enable` + + Disable transparent proxy: + + `/sbin/.magisk/img/v2ray/v2ray.redirect disable` + ## Uninstall 1. Uninstall the module via Magisk Manager App. -2. Remove the directory with command `rm -rf /data/v2ray` . +2. You can clean v2ray data dir by running command `rm -rf /data/v2ray` . diff --git a/common/service.sh b/common/service.sh index b370f94..2fc51ad 100644 --- a/common/service.sh +++ b/common/service.sh @@ -8,4 +8,4 @@ MODDIR=${0%/*} # This script will be executed in late_start service mode -if [ ! -f /data/v2ray/no-autostart ] ; then $MODDIR/v2ray.service start ; fi +if [ ! -f /data/v2ray/no-autostart ] ; then $MODDIR/v2ray.service start && [ -f /data/v2ray/appid.list ] && $MODDIR/v2ray.redirect enable ; fi diff --git a/install.sh b/install.sh index 7e7bf97..2649bfe 100644 --- a/install.sh +++ b/install.sh @@ -140,13 +140,14 @@ on_install() { mkdir -p $MODPATH/system/bin mkdir -p $MODPATH/system/etc unzip -j -o "$ZIPFILE" "v2ray/etc/v2ray.service" -d $MODPATH >&2 + unzip -j -o "$ZIPFILE" "v2ray/etc/v2ray.redirect" -d $MODPATH >&2 unzip -j -o "$ZIPFILE" "v2ray/bin/$ARCH/*" -d $MODPATH/system/bin >&2 # copy v2ray data and config ui_print "- Copy V2Ray config and data files" mkdir -p /data/v2ray mkdir -p /data/v2ray/run - [ -f /data/v2ray/config.json ] || \\ + [ -f /data/v2ray/config.json ] || \ unzip -j -o "$ZIPFILE" "v2ray/etc/config.json" -d /data/v2ray >&2 unzip -j -o "$ZIPFILE" "v2ray/etc/resolv.conf" -d /data/v2ray >&2 unzip -j -o "$ZIPFILE" "v2ray/etc/geosite.dat" -d /data/v2ray >&2 @@ -163,6 +164,7 @@ set_permissions() { # The following is the default rule, DO NOT remove set_perm_recursive $MODPATH 0 0 0755 0644 set_perm $MODPATH/v2ray.service 0 0 0755 + set_perm $MODPATH/v2ray.redirect 0 0 0755 set_perm $MODPATH/system/bin/v2ray ${inet_uid} ${inet_uid} 6755 set_perm $MODPATH/system/bin/v2ctl ${inet_uid} ${inet_uid} 6755 set_perm /data/v2ray ${inet_uid} ${inet_uid} 0755 diff --git a/module.prop b/module.prop index 5ffe525..db69813 100644 --- a/module.prop +++ b/module.prop @@ -1,6 +1,6 @@ id=v2ray name=V2ray for Android version=v4.18 -versionCode=20190329 +versionCode=20190330 author=chendefine description=V2ray core with service scripts for Android diff --git a/system/placeholder b/system/placeholder deleted file mode 100644 index 1a69395..0000000 --- a/system/placeholder +++ /dev/null @@ -1 +0,0 @@ -This file will be deleted in Magisk Manager, it is only a placeholder for git diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..25ed399 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,11 @@ +########################################################################################## +# +# V2Ray Magisk Module Uninstaller Script +# +########################################################################################## + +remove_v2ray_data_dir() { + rm -rf /data/v2ray +} + +remove_v2ray_data_dir diff --git a/v2ray/etc/config.json b/v2ray/etc/config.json index e79155d..9ffc5c5 100644 --- a/v2ray/etc/config.json +++ b/v2ray/etc/config.json @@ -8,6 +8,7 @@ // By default, V2Ray write error log to stdout. // "error": "/path/to/error/log/file", + "error": "/data/v2ray/run/error.log", // Log level, one of "debug", "info", "warning", "error", "none" "loglevel": "warning" @@ -15,22 +16,22 @@ // List of inbound proxy configurations. "inbounds": [{ // Port to listen on. You may need root access if the value is less than 1024. - "port": 1080, + "port": 65535, // IP address to listen on. Change to "0.0.0.0" to listen on all network interfaces. "listen": "127.0.0.1", // Tag of the inbound proxy. May be used for routing. - "tag": "socks-inbound", + "tag": "proxy-inbound", // Protocol name of inbound proxy. - "protocol": "socks", + "protocol": "dokodemo-door", // Settings of the protocol. Varies based on protocol. "settings": { - "auth": "noauth", - "udp": false, - "ip": "127.0.0.1" + "timeout": 10, + "network": "tcp,udp", + "followRedirect": true }, // Enable sniffing on TCP connection. @@ -42,6 +43,15 @@ }], // List of outbound proxy configurations. "outbounds": [{ + // Replace your proxy protocol in this section, like: vmess or shadowsocks + "protocol": "freedom", + + // Settings of the protocol. Varies based on protocol. + "settings": {}, + + // Tag of the outbound. May be used for routing. + "tag": "proxy" + },{ // Protocol name of the outbound proxy. "protocol": "freedom", @@ -65,10 +75,22 @@ "domainStrategy": "IPOnDemand", "rules":[ { - // Blocks access to private IPs. Remove this if you want to access your router. + // Bypass private IPs. "type": "field", "ip": ["geoip:private"], - "outboundTag": "blocked" + "outboundTag": "direct" + }, + { + // Bypass all china IPs. + "type": "field", + "ip": ["geoip:cn"], + "outboundTag": "direct" + }, + { + // Bypass all china sites. + "type": "field", + "domain": ["geosite:cn"], + "outboundTag": "direct" }, { // Blocks major ads. diff --git a/v2ray/etc/v2ray.redirect b/v2ray/etc/v2ray.redirect new file mode 100644 index 0000000..db39acb --- /dev/null +++ b/v2ray/etc/v2ray.redirect @@ -0,0 +1,149 @@ +#!/system/bin/sh + +route_id="1130" +inet_uid="3003" +route_name="v2ray" +proxy_port="65535" +proxy_mark="0x20151130" +appid_file="/data/v2ray/appid.list" +table_file="/data/misc/net/rt_tables" + +appid_list=`[ -f ${appid_file} ] && cat ${appid_file}` + +intranet=(0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4) + +probe_uid_app_name() { + app_name=`grep " $1 " /data/system/packages.list | cut -d ' ' -f 1` + app_name=`echo ${app_name} | sed 's/ / \& /g'` + if [ "${app_name}" != "" ] ; then + echo "Redirect ${app_name} APP's network." + else + echo "APP with uid=$1 is not found." + return 1 + fi +} + +delete_route_table() { + if eval "ip rule | grep -q \"from all fwmark ${proxy_mark} lookup\"" ; then + echo "Clean UDP redirection route table." + ip rule del fwmark ${proxy_mark} lookup ${route_id} + ip route flush table ${route_id} + fi + sed -i "/${route_id} ${route_name}/d" ${table_file} +} + +create_route_table() { + echo "Create UDP redirection route table." + echo "${route_id} ${route_name}" >> ${table_file} + ip route add local default dev lo table ${route_id} + ip rule add fwmark ${proxy_mark} lookup ${route_id} +} + +flush_tcp_iptables() { + echo "Clean TCP redirection iptables rules." + iptables -w 10 -t nat -D OUTPUT -p tcp -j TCP_PRE_PROXY 2>/dev/null + if eval "iptables -w 10 -t nat -L TCP_PRE_PROXY &>/dev/null" ; then + iptables -w 10 -t nat -F TCP_PRE_PROXY + iptables -w 10 -t nat -X TCP_PRE_PROXY + fi + if eval "iptables-save -t nat | grep -q ':V2RAY '" ; then + iptables -w 10 -t nat -F V2RAY + iptables -w 10 -t nat -X V2RAY + fi +} + +flush_udp_iptables() { + echo "Clean UDP redirection iptables rules." + iptables -w 10 -t mangle -D PREROUTING -p udp -j V2RAY 2>/dev/null + iptables -w 10 -t mangle -D OUTPUT -p udp -j UDP_PRE_PROXY 2>/dev/null + if eval "iptables-save -t mangle | grep -q ':UDP_PRE_PROXY '" ; then + iptables -w 10 -t mangle -F UDP_PRE_PROXY + iptables -w 10 -t mangle -X UDP_PRE_PROXY + fi + if eval "iptables-save -t mangle | grep -q ':V2RAY '" ; then + iptables -w 10 -t mangle -F V2RAY + iptables -w 10 -t mangle -X V2RAY + fi +} + +init_tcp_iptables() { + echo "Create TCP redirection iptables rules." + ## create NAT iptables for TCP redirect + iptables -w 10 -t nat -N V2RAY + iptables -w 10 -t nat -N TCP_PRE_PROXY + ## bypass intranet + for subnet in ${intranet[@]}; do + iptables -w 10 -t nat -A V2RAY -d ${subnet} -j RETURN + done + ## bypass v2ray program + iptables -w 10 -t nat -A TCP_PRE_PROXY -m owner --uid-owner ${inet_uid} -j RETURN + ## apply to NAT iptables OUTPUT + iptables -w 10 -t nat -A V2RAY -p tcp -j REDIRECT --to-ports ${proxy_port} +} + +init_udp_iptables() { + echo "Create UDP redirection iptables rules." + ## create Mangle iptables for UDP redirect + iptables -w 10 -t mangle -N V2RAY + iptables -w 10 -t mangle -N UDP_PRE_PROXY + ## bypass intranet + for subnet in ${intranet[@]}; do + iptables -w 10 -t mangle -A UDP_PRE_PROXY -d ${subnet} -j RETURN + done + ## bypass v2ray program + iptables -w 10 -t mangle -A UDP_PRE_PROXY -m owner --uid-owner ${inet_uid} -j RETURN + ## apply to Mangle iptables OUTPUT & PREROUTING + iptables -w 10 -t mangle -A V2RAY -p udp -m mark --mark ${proxy_mark} -j TPROXY --on-ip 127.0.0.1 --on-port ${proxy_port} +} + +redirect_iptables() { + if [ "${appid_list}" = "0" ] ; then + ## redirect global network + echo "Redirect TCP & UDP with Global mode." + iptables -w 10 -t nat -A TCP_PRE_PROXY -m owner ! --uid-owner ${inet_uid} -j V2RAY + iptables -w 10 -t mangle -A UDP_PRE_PROXY -m owner ! --uid-owner ${inet_uid} -j MARK --set-mark ${proxy_mark} + else + ## effect assign app + for appid in ${appid_list}; do + probe_uid_app_name ${appid} && \ + iptables -w 10 -t nat -A TCP_PRE_PROXY -m owner --uid-owner ${appid} -j V2RAY && \ + iptables -w 10 -t mangle -A UDP_PRE_PROXY -m owner --uid-owner ${appid} -j MARK --set-mark ${proxy_mark} + done + fi +} + +apply_iptables_rules() { + iptables -w 10 -t nat -A OUTPUT -p tcp -j TCP_PRE_PROXY + iptables -w 10 -t mangle -A OUTPUT -p udp -j UDP_PRE_PROXY + iptables -w 10 -t mangle -A PREROUTING -p udp -j V2RAY +} + +disable_redirect() { + delete_route_table + flush_tcp_iptables + flush_udp_iptables +} + +enable_redirect() { + disable_redirect + create_route_table + init_tcp_iptables + init_udp_iptables + redirect_iptables + apply_iptables_rules +} + +case "$1" in + enable) + enable_redirect + ;; + disable) + disable_redirect + ;; + renew) + enable_redirect + ;; + *) + echo "$0: usage: $0 {enable|disable|renew}" + ;; +esac diff --git a/v2ray/etc/v2ray.service b/v2ray/etc/v2ray.service index 80368fa..9966d02 100644 --- a/v2ray/etc/v2ray.service +++ b/v2ray/etc/v2ray.service @@ -22,6 +22,13 @@ probe_service() { fi } +simple_clean_iptables() { + echo "Clean relevant iptables simply." + iptables -w 10 -t nat -D OUTPUT -p tcp -j TCP_PRE_PROXY 2>/dev/null + iptables -w 10 -t mangle -D PREROUTING -p udp -j V2RAY 2>/dev/null + iptables -w 10 -t mangle -D OUTPUT -p udp -j UDP_PRE_PROXY 2>/dev/null +} + do_start() { if ! probe_service && [ -f ${CONFFILE} ] && ${V2RAY} ${V2RAY_OPTS} -test ; then echo "Starting ${NAME} service." @@ -31,6 +38,16 @@ do_start() { chmod 6755 ${V2RAY} ${V2RAY} ${V2RAY_OPTS} & echo -n $! > ${PIDFILE} + sleep 10 + if probe_service ; then + echo "Start ${NAME} service Done." + else + rm -f ${PIDFILE} + echo "Start ${NAME} service Failed." + return 1 + fi + else + return 2 fi } @@ -47,11 +64,13 @@ case "$1" in do_start ;; stop) + simple_clean_iptables do_stop ;; restart) do_stop - do_start + do_start || \ + simple_clean_iptables ;; *) echo "$0: usage: $0 {start|stop|restart}"