#!/bin/bash

#
# Copyright (C) 2024 Nosignal <https://github.com/nosignals>
# 
# Contributors:
# - bobbyunknown <https://github.com/bobbyunknown>
#
# https://opensource.org/license/mit
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# mkdir -p /dev/net
# [ ! -L /dev/net/tun ] && ln -s /dev/tun /dev/net/tun

ulimit -SHn 1000000

id="200"
tun_device="Meta"
iptables=`command -v iptables`
nft=`command -v nft`
fw4=`command -v fw4`

intranet=(0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 233.252.0.0/24 240.0.0.0/4 255.255.255.255/32)

start_tun() {
    echo "[ `date +%T` ] - Starting iptables"
    ip rule add fwmark ${id} table ${id}
    ip route add default dev ${tun_device} table ${id}

    ${iptables} -I FORWARD -o ${tun_device} -j ACCEPT
    ${iptables} -I FORWARD -i ${tun_device} -j ACCEPT
    ${iptables} -t mangle -N NEKO_EXTERNAL

    for subnet in ${intranet[@]} ; do
        ${iptables} -t mangle -A NEKO_EXTERNAL -d ${subnet} -j RETURN
    done

    ${iptables} -t mangle -A NEKO_EXTERNAL -j MARK --set-xmark ${id}
    ${iptables} -t mangle -I PREROUTING -j NEKO_EXTERNAL
    ${iptables} -t mangle -N NEKO_LOCAL

    for subnet in ${intranet[@]} ; do
        ${iptables} -t mangle -A NEKO_LOCAL -d ${subnet} -j RETURN
    done

    ${iptables} -t mangle -A NEKO_LOCAL -j MARK --set-xmark ${id}
    ${iptables} -t mangle -I OUTPUT -j NEKO_LOCAL
}

stop_tun() {
    echo "[ `date +%T` ] - Cleaning iptables Route"
    ip rule del fwmark ${id} table ${id}
    ip route del default dev ${tun_device} table ${id}
    
    ${iptables} -F FORWARD
    ${iptables} -X FORWARD

    ${iptables} -t mangle -D OUTPUT -j NEKO_LOCAL
    ${iptables} -t mangle -D PREROUTING -j NEKO_EXTERNAL

    ${iptables} -t mangle -F NEKO_EXTERNAL
    ${iptables} -t mangle -X NEKO_EXTERNAL

    ${iptables} -t mangle -F NEKO_LOCAL
    ${iptables} -t mangle -X NEKO_LOCAL
}
start_tun_fw4() {
    echo "[ `date +%T` ] - Starting nftables"
    handles=`nft -a list chain inet fw4 forward |grep -E "oifname.*${tun_device}" |awk -F '# handle ' '{print$2}'`
    for handle in $handles; do
        $nft delete rule inet fw4 forward handle ${handle}
    done
    # $nft insert rule inet fw4 forward position 0 meta l4proto { tcp, udp } oifname ${tun_device} counter accept
    $nft insert rule inet fw4 forward position 0 meta l4proto { tcp, udp } oifname ${tun_device} counter accept comment \"Neko TUN Forward\"
    $nft insert rule inet fw4 forward position 0 meta l4proto { tcp, udp } iifname ${tun_device} counter accept comment \"Neko TUN Forward\"
    $nft insert rule inet fw4 input position 0 meta l4proto { tcp, udp } iifname ${tun_device} counter accept comment \"Neko TUN Input\"
    $nft insert rule inet fw4 srcnat position 0 meta nfproto { ipv4 } oifname ${tun_device} counter return comment \"Neko TUN Postrouting\"
}
stop_tun_fw4() {
    echo "[ `date +%T` ] - Cleaning nftables Route"

    nft_list=(forward input srcnat)
    for nft_now in ${nft_list[@]}; do
        handles=`nft -a list chain inet fw4 $nft_now |grep -E "Neko" |awk -F '# handle ' '{print$2}'`
        for handle in $handles; do
            $nft delete rule inet fw4 ${nft_now} handle ${handle}
        done
    done
}
while getopts ":sk" signal ; do
    case ${signal} in
        s)
            if [[ -n $fw4 ]] ; then
                echo "[ `date +%T` ] - FW4 Detected"
                start_tun_fw4
            else 
                echo "[ `date +%T` ] - FW3 Detected"
                start_tun
            fi
            ;;
        k)
            if [[ -n $fw4 ]] ; then
                echo "[ `date +%T` ] - FW4 Detected"
                stop_tun_fw4
            else 
                echo "[ `date +%T` ] - FW3 Detected"
                stop_tun
            fi
            ;;
    esac
done
