[v1.0.8] Support app dns request

This commit is contained in:
Ghost in the Cyber 2019-07-10 13:04:18 +08:00 committed by chendefine
parent 4fe443de57
commit 7177ec42d8
8 changed files with 337 additions and 6 deletions

View File

@ -12,6 +12,7 @@ if [ ! -f /data/v2ray/manual ] ; then
$MODDIR/scripts/v2ray.service start &> /data/v2ray/run/service.log && \
if [ -f /data/v2ray/appid.list ] || [ -f /data/v2ray/softap.list ] ; then
$MODDIR/scripts/v2ray.tproxy enable &>> /data/v2ray/run/service.log
[ -f "$MODDIR/scripts/v2ray-dns.keeper" ] && $MODDIR/scripts/v2ray-dns.service start &>> /data/v2ray/run/service.log &
fi
fi

View File

@ -142,6 +142,7 @@ on_install() {
mkdir -p $MODPATH/system/etc
unzip -j -o "$ZIPFILE" 'v2ray/scripts/*' -d $MODPATH/scripts >&2
unzip -j -o "$ZIPFILE" "v2ray/bin/$ARCH/*" -d $MODPATH/system/bin >&2
[ -f $MODPATH/system/bin/v2ray-dns.keeper ] && mv $MODPATH/system/bin/v2ray-dns.keeper $MODPATH/scripts >&2
# copy v2ray data and config
ui_print "- Copy V2Ray config and data files"
@ -149,12 +150,14 @@ on_install() {
mkdir -p /data/v2ray/run
[ -f /data/v2ray/softap.list ] || \
echo "softap0" > /data/v2ray/softap.list
[ -f /data/v2ray/config.json ] || \
unzip -j -o "$ZIPFILE" "v2ray/etc/config.json" -d /data/v2ray >&2
[ -f /data/v2ray/resolv.conf ] || \
unzip -j -o "$ZIPFILE" "v2ray/etc/resolv.conf" -d /data/v2ray >&2
unzip -j -o "$ZIPFILE" "v2ray/etc/geosite.dat" -d /data/v2ray >&2
unzip -j -o "$ZIPFILE" "v2ray/etc/geoip.dat" -d /data/v2ray >&2
unzip -j -o "$ZIPFILE" "v2ray/etc/config.json" -d /data/v2ray/run >&2
mv /data/v2ray/run/config.json /data/v2ray/config.json.template
[ -f /data/v2ray/config.json ] || \
cp /data/v2ray/config.json.template /data/v2ray/config.json
ln -s /data/v2ray/resolv.conf $MODPATH/system/etc/resolv.conf
}
@ -169,6 +172,9 @@ set_permissions() {
set_perm $MODPATH/scripts/v2ray.inotify 0 0 0755
set_perm $MODPATH/scripts/v2ray.service 0 0 0755
set_perm $MODPATH/scripts/v2ray.tproxy 0 0 0755
set_perm $MODPATH/scripts/v2ray-dns.handle 0 0 0755
set_perm $MODPATH/scripts/v2ray-dns.keeper 0 0 0755
set_perm $MODPATH/scripts/v2ray-dns.service 0 0 0755
set_perm $MODPATH/system/bin/v2ray ${inet_uid} ${inet_uid} 0755
set_perm $MODPATH/system/bin/v2ctl ${inet_uid} ${inet_uid} 0755
set_perm /data/v2ray ${inet_uid} ${inet_uid} 0755

View File

@ -1,6 +1,6 @@
id=v2ray
name=V2ray for Android
version=v4.19.1
versionCode=20190622
versionCode=20190707
author=chendefine
description=V2ray core with service scripts for Android

View File

@ -15,6 +15,22 @@
},
// List of inbound proxy configurations.
"inbounds": [{
// Just listen for DNS proxy.
"port": 65534,
// Tag of the inbound for DNS proxy routing.
"tag": "dns-in",
// DNS proxy protocol must be dokodemo-door.
"protocol": "dokodemo-door",
// Setting of DNS proxy.
"settings": {
"port": 53,
"address": "1.1.1.1",
"network": "tcp,udp"
}
},{
// Port to listen on. You may need root access if the value is less than 1024.
"port": 65535,
@ -61,6 +77,12 @@
// Tag of the outbound. May be used for routing.
"tag": "direct"
},{
// DNS Proxy Outbond
"protocol": "dns",
// Tag of the outbound for DNS proxy routing.
"tag": "dns-out"
},{
"protocol": "blackhole",
"settings": {},
@ -75,6 +97,12 @@
"routing": {
"domainStrategy": "IPOnDemand",
"rules":[
{
// Proxy DNS request
"type": "field",
"inboundTag": ["dns-in"],
"outboundTag": "dns-out"
},
{
// Bypass private IPs.
"type": "field",
@ -117,6 +145,8 @@
},
"servers": [
"1.1.1.1",
"8.8.8.8",
"9.9.9.9",
{
"address": "114.114.114.114",
"port": 53,
@ -125,7 +155,6 @@
"geosite:cn"
]
},
"8.8.8.8",
"localhost"
]
},

View File

@ -0,0 +1,196 @@
#!/system/bin/sh
host_ip=""
inet_uid="3003"
proxy_port="65534"
iptables_wait="iptables"
proxy_for_app=false
appid_file="/data/v2ray/appid.list"
work_path="`dirname $0`"
find_outbound="${work_path}/v2ray-dns.keeper -o"
suit_iptables_version() {
iptables_version=`iptables -V | grep -o "v1\.[0-9]"`
if [ "${iptables_version}" = "v1.4" ] ; then
## fix options for lower version iptables
export ANDROID_DATA=/data
export ANDROID_ROOT=/system
iptables_wait="iptables -w"
elif [ "${iptables_version}" = "v1.6" ] || [ "${iptables_version}" = "v1.8" ] ; then
iptables_wait="iptables -w 100"
else
iptables_wait="echo iptables"
fi
}
find_netstat_path() {
[ -f /system/bin/netstat ] && alias netstat="/system/bin/netstat" && return 0
[ -f /system/xbin/netstat ] && alias netstat="/system/xbin/netstat" && return 0
return 1
}
iptables_chain_exist() {
local chain_list="$1"
local target_chain="$2"
if `echo "${chain_list}" | grep -q ":${target_chain} "` ; then
return 0
fi
return 1
}
probe_v2ray_listen() {
find_netstat_path || return
v2ray_listen=`netstat -unlp | grep v2ray`
if eval "echo \"${v2ray_listen}\" | grep -q :::${proxy_port}" || eval "echo \"${v2ray_listen}\" | grep -q 0.0.0.0:${proxy_port}" ; then
return
else
echo "[Error]: V2Ray service is not listening on port ${proxy_port} ."
exit 1
fi
}
probe_v2ray_target() {
## add eof to appid and softap file
echo "" >> "${appid_file}"
## trim empty line in appid and softap file
sed -i '/^$/d' "${appid_file}"
## probe proxy app
if [ -f ${appid_file} ] ; then
## check appid_file is white-list or black-list
if head -1 "${appid_file}" | grep -q 'bypass' ; then
app_proxy_mode="skip"
else
app_proxy_mode="pick"
fi
## filter appid number
while read appid_line ; do
appid_text=(`echo ${appid_line}`)
for appid_word in ${appid_text[*]} ; do
if echo "${appid_word}" | grep -q '#' ; then
break
elif [ "${appid_word}" -ge 0 ] 2>/dev/null ; then
appid_list=(${appid_list[*]} ${appid_word})
fi
done
done < ${appid_file}
fi
## check proxy app or not
if ( [ "${app_proxy_mode}" = "skip" ] || ( [ "${app_proxy_mode}" = "pick" ] && [ ${#appid_list[@]} -gt 0 ] ) ) ; then
proxy_for_app=true
fi
## check enable proxy iptables or not
if ! ${proxy_for_app} ; then
echo "[Error]: V2Ray service is not proxy for APP."
exit 1
fi
}
probe_uid_app_name() {
app_handle="$2"
if [ "$1" == "0" ] ; then
app_name="root"
else
app_name=`grep " $1 " /data/system/packages.list | cut -d ' ' -f 1`
app_name=`echo ${app_name} | sed 's/ / \& /g'`
fi
if [ "${app_name}" != "" ] ; then
echo "[Info]: ${app_handle} ${app_name} APP's DNS request."
else
echo "[Warning]: APP with uid=$1 is not found."
return 1
fi
}
proxy_app_dns_iptables() {
## create iptables proxy chains for app tcp
${iptables_wait} -t nat -N APP_DNS_PROXY
## bypass v2ray program
${iptables_wait} -t nat -A APP_DNS_PROXY -m owner --uid-owner ${inet_uid} -j RETURN
## white-list mode
if [ "${app_proxy_mode}" = "pick" ] ; then
## proxy all apps network
if [ "${appid_list[*]}" = "0" ] ; then
echo "[Info]: Proxy all APP's DNS request."
${iptables_wait} -t nat -A APP_DNS_PROXY -m owner ! --uid-owner ${inet_uid} -j V2RAY_APP_DNS
## proxy assign app
else
for appid in ${appid_list[@]}; do
probe_uid_app_name ${appid} "Proxy" && \
${iptables_wait} -t nat -A APP_DNS_PROXY -m owner --uid-owner ${appid} -j V2RAY_APP_DNS
done
fi
## black-list mode
elif [ "${app_proxy_mode}" = "skip" ] ; then
for appid in ${appid_list[@]}; do
probe_uid_app_name ${appid} "Ignore" && \
${iptables_wait} -t nat -A APP_DNS_PROXY -m owner --uid-owner ${appid} -j RETURN
done
echo "[Info]: Proxy all remaining APP's DNS request."
${iptables_wait} -t nat -A APP_DNS_PROXY -m owner ! --uid-owner ${inet_uid} -j V2RAY_APP_DNS
fi
## apply proxy rules to iptables
${iptables_wait} -t nat -A OUTPUT -p udp --dport 53 -j APP_DNS_PROXY
}
create_proxy_iptables() {
while [ "${host_ip}" == "" ] || [ "${host_ip}" == "0.0.0.0" ] || [ "${host_ip}" == "127.0.0.1" ] ; do
host_ip=`${find_outbound}`
sleep 2
done
local iptables_chains=`iptables-save -t nat | cut -d ' ' -f 1 | tr "\n" " " | grep -o ":[0-9A-Z_]* "`
if ! iptables_chain_exist "${iptables_chains}" "V2RAY_APP_DNS" ; then
## create basic iptables proxy chains
echo "[Info]: Create DNS proxy chains to ${host_ip}:${proxy_port}"
${iptables_wait} -t nat -N V2RAY_APP_DNS
else
## flush basic iptables proxy chains
echo "[Info]: Rebuild DNS proxy chains to ${host_ip}:${proxy_port}"
${iptables_wait} -t nat -F V2RAY_APP_DNS
fi
## build basic iptables proxy chains
${iptables_wait} -t nat -A V2RAY_APP_DNS -p udp -j DNAT --to-destination ${host_ip}:${proxy_port}
if ! iptables_chain_exist "${iptables_chains}" "APP_DNS_PROXY" && ${proxy_for_app} ; then
## proxy app network
proxy_app_dns_iptables
fi
}
flush_endpoint_iptables() {
${iptables_wait} -t nat -F V2RAY_APP_DNS 2>/dev/null
}
flush_nat_iptables() {
echo "[Info]: Clean nat proxy iptables rules."
local iptables_chains=`iptables-save -t nat | cut -d ' ' -f 1 | tr "\n" " " | grep -o ":[0-9A-Z_]* "`
${iptables_wait} -t nat -D OUTPUT -p udp --dport 53 -j APP_DNS_PROXY 2>/dev/null
if iptables_chain_exist "${iptables_chains}" "APP_DNS_PROXY" ; then
${iptables_wait} -t nat -F APP_DNS_PROXY
${iptables_wait} -t nat -X APP_DNS_PROXY
fi
if iptables_chain_exist "${iptables_chains}" "V2RAY_APP_DNS" ; then
${iptables_wait} -t nat -F V2RAY_APP_DNS
${iptables_wait} -t nat -X V2RAY_APP_DNS
fi
unset iptables_chains
}
disable_proxy() {
flush_nat_iptables
}
case "$1" in
enable)
flush_endpoint_iptables
probe_v2ray_listen
probe_v2ray_target
sleep 2
create_proxy_iptables
;;
disable)
disable_proxy
;;
*)
echo "usage: $0 {enable|disable}"
;;
esac

View File

@ -0,0 +1,91 @@
#!/system/bin/sh
proxy_port="65534"
work_path="`dirname $0`"
bin_name="v2ray-dns.keeper"
bin_file="${work_path}/${bin_name}"
run_path="/data/v2ray/run"
pid_file="${run_path}/dns-keeper.pid"
log_file="${run_path}/dns-keeper.log"
handle_script="${work_path}/v2ray-dns.handle"
find_netstat_path() {
[ -f /system/bin/netstat ] && alias netstat="/system/bin/netstat" && return 0
[ -f /system/xbin/netstat ] && alias netstat="/system/xbin/netstat" && return 0
return 1
}
probe_keeper_alive() {
[ -f ${pid_file} ] && cmd_file="/proc/`cat ${pid_file}`/cmdline" || return 1
[ -f ${cmd_file} ] && grep -q "v2ray-dns.keeper" ${cmd_file} && return 0 || return 1
}
probe_v2ray_listen() {
find_netstat_path || return
v2ray_listen=`netstat -unlp | grep v2ray`
if eval "echo \"${v2ray_listen}\" | grep -q :::${proxy_port}" || eval "echo \"${v2ray_listen}\" | grep -q 0.0.0.0:${proxy_port}" ; then
return 0
else
return 1
fi
}
display_keeper_pid() {
if probe_keeper_alive ; then
echo "[Info]: ${bin_name} service is running. ( PID: `cat ${pid_file}` )"
return 0
else
echo "[Info]: ${bin_name} service is stopped."
return 1
fi
}
start_service() {
if probe_keeper_alive ; then
echo "[Info]: ${bin_name} service is running. ( PID: `cat ${pid_file}` )"
return 0
elif probe_v2ray_listen ; then
echo "[Info]: Starting ${bin_name} service."
mkdir -p ${run_path}
nohup ${bin_file} -d "${handle_script} enable" &>${log_file} &
echo -n $! > ${pid_file}
if probe_keeper_alive ; then
echo "[Info]: ${bin_name} service is running. ( PID: `cat ${pid_file}` )"
return 0
else
echo "[Error]: Start ${bin_name} service Failed."
rm -f ${pid_file}
return 1
fi
else
echo "[Error]: V2Ray service is not listening on port ${proxy_port} for DNS proxy."
exit 1
return 2
fi
}
stop_service() {
if display_keeper_pid ; then
echo "[Info]: Stopping ${bin_name} service."
kill `cat ${pid_file}`
sleep 1
display_keeper_pid
fi
${handle_script} disable
rm -f ${pid_file}
}
case "$1" in
start)
start_service
;;
stop)
stop_service
;;
status)
display_keeper_pid
;;
*)
echo "$0: usage: $0 {start|stop|status}"
;;
esac

View File

@ -4,6 +4,8 @@ inotify=`realpath $0`
scripts_dir=`dirname ${inotify}`
service="${scripts_dir}/v2ray.service"
tproxy="${scripts_dir}/v2ray.tproxy"
dns_proxy_keeper="${scripts_dir}/v2ray-dns.keeper"
dns_proxy_service="${scripts_dir}/v2ray-dns.service"
events=$1
monitor_dir=$2
@ -13,11 +15,13 @@ start_v2ray() {
${service} start && \
if [ -f /data/v2ray/appid.list ] || [ -f /data/v2ray/softap.list ] ; then
${tproxy} enable
[ -f "${dns_proxy_keeper}" ] && ${dns_proxy_service} start
fi
}
stop_v2ray() {
${tproxy} disable
[ -f "${dns_proxy_keeper}" ] && ${dns_proxy_service} stop
${service} stop
}

View File

@ -101,8 +101,12 @@ probe_v2ray_target() {
probe_uid_app_name() {
app_handle="$2"
app_name=`grep " $1 " /data/system/packages.list | cut -d ' ' -f 1`
app_name=`echo ${app_name} | sed 's/ / \& /g'`
if [ "$1" == "0" ] ; then
app_name="root"
else
app_name=`grep " $1 " /data/system/packages.list | cut -d ' ' -f 1`
app_name=`echo ${app_name} | sed 's/ / \& /g'`
fi
if [ "${app_name}" != "" ] ; then
echo "[Info]: ${app_handle} ${app_name} APP's network."
else