#!/system/bin/sh
### Author: CuteBi ###
#### Version: 0.4 ####
#####    tun    #####

#读取模式文件  得到所需内容
readModeFile() {
    [ ! -f "../$modeName" -a -f "../${modeName}.conf" ] && modeName+='.conf'
    tunDevice=`grep '^ *tunDevice' "../$modeName" | grep -o '= *[^\;]*'`
    tunDevice=${tunDevice#=}
}

#通过包名得到uid
getPackageUid() {
    packageName=${1%%_*}  #过滤包名后面的端口
    if echo $packageName | grep -q '[A-Za-z]'; then
        packageInfo=`grep -oE "^$packageName ([0-9])+" /data/system/packages.list`
        [ $? != 0 ] && return 1
        echo "$1" | grep -qE '_([0-9])+' && \
            echo "${packageInfo#* }_${1#*_}" || \
            echo "${packageInfo#* }"
    else
        echo "$1"
    fi
}

#同时执行iptables和ip6tables
ipts() {
    iptables $@
    ip6tables $@
}

#放行
allowService() {
    #本地UDP放行
    for app in $localUdpAllowApps; do
        uid=`getPackageUid $app` || continue
        ipts -t mangle -I OUTPUT -p udp -m owner --uid ${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j ACCEPT
        [ "$app" != "$uid" ] && \
            grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
            ipts -t mangle -I OUTPUT -p udp -m owner --uid 999${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j ACCEPT
    done
    #本地TCP放行
    for app in $localTcpAllowApps; do
        uid=`getPackageUid $app` || continue
        ipts -t mangle -I OUTPUT -p tcp -m owner --uid ${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j ACCEPT
        [ "$app" != "$uid" ] && \
            grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
            ipts -t mangle -I OUTPUT -p tcp -m owner --uid 999${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j ACCEPT
    done
    #本地全局放行
    for app in $localAllowApps; do
        uid=`getPackageUid $app` || continue
        ipts -t mangle -I OUTPUT -m owner --uid $uid -j ACCEPT
        [ "$app" != "$uid" ] && \
            grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
            ipts -t mangle -I OUTPUT -m owner --uid 999$uid -j ACCEPT
    done
    #共享全局放行
    if [ "$shareAllow" == 1 ]; then
        ipts -t mangle -F PREROUTING
    else
        #共享UDP放行
        if [ -n "$shareAllowUdpPorts" ]; then
            ipts -t mangle -I PREROUTING -p udp -m multiport --dport $shareAllowUdpPorts -j ACCEPT
        fi
        #共享TCP放行
        if [ -n "$shareAllowTcpPorts" ]; then
            ipts -t mangle -I PREROUTING -p tcp -m multiport --dport $shareAllowTcpPorts -j ACCEPT
        fi
    fi
    #不代理ipv6则清除ipv6规则
    if [ "$ipv6Opt" != 'proxy' ]; then
        ip6tables -t mangle -F OUTPUT
        ip6tables -t mangle -F PREROUTING
    fi
}

#配置ip[6]tables
set_iptables() {
    ###ipv4和ipv6规则
    #WiFi代理规则
    [ "$allowWifi" == '1' ] && \
        ipts -t mangle -A OUTPUT -o wlan+ -j ACCEPT || \
        #标记WiFi(WiFi的内网可能是192.168/16和fe80::/10)的DNS
        ipts -t mangle -A OUTPUT -o wlan+ -p 17 --dport 53 -j  MARK --set-xmark 5201314
    ##开启只代理部分应用
    if [ -n "$onlyProxyApps" ]; then
        ipts -t mangle -A OUTPUT -m owner --gid 3004 -j ACCEPT
        for app in $onlyProxyApps; do
            uid=`getPackageUid $app` || continue
            ipts -t mangle -A OUTPUT -m owner --uid ${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j MARK --set-xmark 5201314
            [ "$app" != "$uid" ] && \
                grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
                ipts -t mangle -A OUTPUT -m owner --uid 999${uid%_*} `echo $uid|grep -q '_' && echo "-m multiport --dport ${uid#*_}"` -j MARK --set-xmark 5201314
        done
        return
    fi
    ##禁网不正常的数据包
    ipts -t mangle -A PREROUTING -m state --state INVALID -j DROP
    ipts -t mangle -A OUTPUT -m state --state INVALID -j DROP
    ##放行内核负责发送的RST包
    #ipts -t mangle -A OUTPUT -m owner ! --uid 0-999999999 -p 6 --tcp-flags ALL RST -j ACCEPT
    ##标记本机数据包
    iptables -t mangle -A OUTPUT ! -d 192.168/16 ! -o lo -m owner ! --gid 3004 -j MARK --set-xmark 5201314
    ip6tables -t mangle -A OUTPUT ! -d fe80::/10 ! -o lo -m owner ! --gid 3004 -j MARK --set-xmark 5201314
    #共享的数据包在FORWARD放行
    ipts -I FORWARD -j ACCEPT
    #标记ipv4共享数据包
    iptables -t mangle -A PREROUTING -s 192.168/16 ! -d 192.168/16 -j MARK --set-xmark 5201314
    #标记ipv6共享数据包
    ip6tables -t mangle -A PREROUTING -s fe80::/10 ! -d fe80::/10 -j MARK --set-xmark 5201314
}

ip_route() {
    ip rule add fwmark 5201314 lookup 101 pref 13001
    ip route add default dev $tunDevice table 101
    if [ "$ipv6Opt" == 'deny' ]; then  #禁网ipv6
        ip -6 rule add unreachable pref 13001
    elif [ "$ipv6Opt" != 'allow' ]; then  #代理ipv6
        ip -6 rule add iif lo fwmark 5201314 lookup 101 pref 13001
        ip -6 route add default dev $tunDevice table 101
    fi
}

createTun() {
    echo 1 > /proc/sys/net/ipv4/ip_forward
    [ ! -e "/dev/net/tun" ] && mkdir -p /dev/net && ln -s /dev/tun /dev/net/tun
}

statusCheck() {
    ##网卡和IP检测
    if false; then  #暂时不展示网卡IP
        ip addr | grep -E "^[0-9]+:|inet" | while read line; do
            if echo $line|grep -qE "^[0-9]+:"; then
                devName=`echo $line|grep -iE "^[0-9]+: [^:]+:"`
                devName=${devName#*: }
                devName=${devName%%:*}
                typeset -L17 devName=${devName%@*}
            else
                ipAddr=${line#* }
                ipAddr=${ipAddr%% *}
                echo "$devName$ipAddr"
            fi
        done
        echo
    fi
    grep -q '^clnc$' "/proc/`grep -o ^[0-9]* clnc.pid 2>/dev/null`/comm" 2>/dev/null && \
        echo '✔  clnc 正在运行' || \
        echo '✘  clnc 没有运行'
    echo "\n✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
    echo '❁ ipv4 mangle表 PREROUTING链:'
    iptables -t mangle -S PREROUTING
    echo '✺ ipv4 mangle表 OUTPUT链:'
    iptables -t mangle -S OUTPUT
    echo "\n✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
    echo '❁ ipv6 mangle表 PREROUTING链:'
    ip6tables -t mangle -S PREROUTING
    echo '✺ ipv6 mangle表 OUTPUT链:'
    ip6tables -t mangle -S OUTPUT
}

clearServer() {
    #关闭程序
    ./clnc -k
    #清理ip路由规则
    {
        while ip rule del pref 13001; do done
        while ip -6 rule del pref 13001; do done
        ipts -t mangle -F PREROUTING
        ipts -t mangle -F OUTPUT
        ipts -D FORWARD -j ACCEPT
    } 2>/dev/null
}

startServer() {
    readModeFile  #读取模式文件
    createTun  #创建tun
    ##禁网，防止清理规则时跳点
    ipts -I OUTPUT -m owner ! --gid 3004 -j DROP
    ipts -I FORWARD -j DROP
    clearServer  #清理规则
    set_iptables  #设置ip[6]tables代理规则
    allowService  #执行放行代码
    export CLNC_INIT_CONFIG_DNS=`getprop net.dns1`
    [ -z "$CLNC_INIT_CONFIG_DNS" ] && export CLNC_INIT_CONFIG_DNS=119.29.29.29
    ./clnc -g 3004 -p clnc.pid -c "../$modeName"  #启动clnc
    ip_route  #ip路由
    ##解除禁网
    ipts -D OUTPUT -m owner ! --gid 3004 -j DROP
    ipts -D FORWARD -j DROP
}

aliasIptables() {
    if iptables --help | grep -q "\-w"; then
        alias iptables="iptables -w"
        alias ip6tables="ip6tables -w"
    else
        iptables() {
            result=`/system/bin/iptables $@ 2>&1`
            [ "$?" == '4' ] && iptables $@ || echo -E "$result"|grep -qE 'xtables block|xtables_lock wait = [1-9]'
        }
        ip6tables() {
            result=`/system/bin/ip6tables $@ 2>&1`
            [ "$?" == '4' ] && ip6tables $@ || echo -E "$result"|grep -qE 'xtables block|xtables_lock wait = [1-9]'
        }
    fi
}

readConfigFile() {
    eval "`grep -v '^\;' ../config.ini`"  #ini文件;开头是注释
}

main() {
    cd "${1%/*}"
    readConfigFile
    aliasIptables
    [ "$2" == 'stop' ] && clearServer
    [ "$2" == 'start' ] && startServer
    statusCheck
}

main "$0" "$1" 2>&1
