#!/bin/ash

#add_rule
function add_ipv4_rule() {
    if [ -z "$(ip -4 route show table all | grep 'local default dev lo table 256 scope host')" ]; then
        ip -4 route add local default dev lo table 256
    fi
    if [ -z "$(ip -4 rule | grep 'from all fwmark 0x100 lookup 256')" ]; then
        ip -4 rule add fwmark 0x100 table 256
    fi
}
function add_ipv6_rule() {
    if [ -z "$(ip -6 route show table all | grep 'local default dev lo table 256 metric 1024 pref medium')" ]; then
        ip -6 route add local default dev lo table 256
    fi
    if [ -z "$(ip -6 rule | grep 'from all fwmark 0x100 lookup 256')" ]; then
        ip -6 rule add fwmark 0x100 table 256
    fi
}

#del_rule
function del_ipv4_rule() {
    if [ -n "$(ip -4 route show table all | grep 'local default dev lo table 256 scope host')" ]; then
        ip -4 route del local default dev lo table 256
    fi
    if [ -n "$(ip -4 rule | grep 'from all fwmark 0x100 lookup 256')" ]; then
        ip -4 rule del fwmark 0x100 table 256
    fi
}
function del_ipv6_rule() {
    if [ -n "$(ip -6 route show table all | grep 'local default dev lo table 256 metric 1024 pref medium')" ]; then
        ip -6 route del local default dev lo table 256
    fi
    if [ -n "$(ip -6 rule | grep 'from all fwmark 0x100 lookup 256')" ]; then
        ip -6 rule del fwmark 0x100 table 256
    fi
}

#add_set
function add_ipv4_set() {
    if [ -z "$(nft list table inet fw4 | grep 'set lan4')" ]; then
        nft add set inet fw4 lan4 { type ipv4_addr\; flags interval\; }
    else
        nft flush set inet fw4 lan4
    fi
    nft add element inet fw4 lan4 { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 172.16.0.0/12, 169.254.0.0/16, 192.0.0.0/24, 192.88.99.0/24, 192.168.0.0/16, 224.0.0.0/3 }

    if [ -z "$(nft list table inet fw4 | grep 'set wan4')" ]; then
        nft add set inet fw4 wan4 { type ipv4_addr\; flags interval\; }
    else
        nft flush set inet fw4 wan4
    fi
    nft add element inet fw4 wan4 { $(ifstatus wan | jsonfilter -e '@["ipv4-address"][0].address')/$(ifstatus wan | jsonfilter -e '@["ipv4-address"][0].mask') }

}
function add_ipv6_set() {
    if [ -z "$(nft list table inet fw4 | grep 'set lan6')" ]; then
        nft add set inet fw4 lan6 { type ipv6_addr\; flags interval\; }
    else
        nft flush set inet fw4 lan6
    fi
    nft add element inet fw4 lan6 { ::, ::1, ::ffff:0:0:0/96, 64:ff9b::/96, 100::/64, 2001::/32, 2001:20::/28, 2001:db8::/32, 2002::/16, fc00::/7, fe80::/10, ff00::/8 }

    if [ -z "$(nft list table inet fw4 | grep 'set wan6')" ]; then
        nft add set inet fw4 wan6 { type ipv6_addr\; flags interval\; }
    else
        nft flush set inet fw4 wan6
    fi
    nft add element inet fw4 wan6 { $(ifstatus wan6 | jsonfilter -e '@["ipv6-prefix"][0].address')/$(ifstatus wan6 | jsonfilter -e '@["ipv6-prefix"][0].mask'), $(ifstatus wan6 | jsonfilter -e '@["ipv6-address"][0].address')/$(ifstatus wan6 | jsonfilter -e '@["ipv6-address"][0].mask') }
}

#del_set
function del_ipv4_set() {
    if [ -n "$(nft list table inet fw4 | grep 'set lan4')" ]; then
        nft delete set inet fw4 lan4
    fi

    if [ -n "$(nft list table inet fw4 | grep 'set wan4')" ]; then
        nft delete set inet fw4 wan4
    fi
}
function del_ipv6_set() {
    if [ -n "$(nft list table inet fw4 | grep 'set lan6')" ]; then
        nft delete set inet fw4 lan6
    fi

    if [ -n "$(nft list table inet fw4 | grep 'set wan6')" ]; then
        nft delete set inet fw4 wan6
    fi
}

#enable_tproxy
function enable_ipv4_tproxy() {
    if [ -z "$(nft list table inet fw4 | grep '@wan4')" ]; then
        nft add rule inet fw4 mangle_prerouting ip daddr @lan4 return
        nft add rule inet fw4 mangle_prerouting ip daddr @wan4 return
        nft add rule inet fw4 mangle_prerouting tcp dport { 0-65535 } tproxy to :$port meta mark set 0x100 accept
        nft add rule inet fw4 mangle_prerouting udp dport { 0-65535 } tproxy to :$port meta mark set 0x100 accept
        nft add rule inet fw4 mangle_output ip daddr @lan4 return
        nft add rule inet fw4 mangle_output ip daddr @wan4 return
        nft add rule inet fw4 mangle_output meta mark $mark return
        nft add rule inet fw4 mangle_output tcp dport { 0-65535 } meta mark set 0x100
        nft add rule inet fw4 mangle_output udp dport { 0-65535 } meta mark set 0x100
    fi
}
function enable_ipv6_tproxy() {
    if [ -z "$(nft list table inet fw4 | grep '@wan6')" ]; then
        nft flush chain inet fw4 mangle_prerouting
        nft flush chain inet fw4 mangle_output
        nft add rule inet fw4 mangle_prerouting ip daddr @lan4 return
        nft add rule inet fw4 mangle_prerouting ip daddr @wan4 return
        nft add rule inet fw4 mangle_prerouting ip6 daddr @lan6 return
        nft add rule inet fw4 mangle_prerouting ip6 daddr @wan6 return
        nft add rule inet fw4 mangle_prerouting tcp dport { 0-65535 } tproxy to :$port meta mark set 0x100 accept
        nft add rule inet fw4 mangle_prerouting udp dport { 0-65535 } tproxy to :$port meta mark set 0x100 accept
        nft add rule inet fw4 mangle_output ip daddr @lan4 return
        nft add rule inet fw4 mangle_output ip daddr @wan4 return
        nft add rule inet fw4 mangle_output ip6 daddr @lan6 return
        nft add rule inet fw4 mangle_output ip6 daddr @wan6 return
        nft add rule inet fw4 mangle_output meta mark $mark return
        nft add rule inet fw4 mangle_output tcp dport { 0-65535 } meta mark set 0x100
        nft add rule inet fw4 mangle_output udp dport { 0-65535 } meta mark set 0x100
    fi
}

#disable_tproxy
function disable_ipv4_tproxy() {
    nft flush chain inet fw4 mangle_prerouting
    nft flush chain inet fw4 mangle_output
}
function disable_ipv6_tproxy() {
    nft flush chain inet fw4 mangle_prerouting
    nft flush chain inet fw4 mangle_output
}

#check_network
function check_ipv4_network() {
    while true; do
        ping -c 3 -w 10 119.29.29.29 >/dev/null
        if [[ $? -eq 0 ]]; then
            break
        else
            exit 1
        fi
    done
}

function check_ipv6_network() {
    while true; do
        ping6 -c 3 -w 10 2402:4e00:: >/dev/null
        if [[ $? -eq 0 ]]; then
            break
        else
            exit 1
        fi
    done
}

#stop_service
function stop_all_service() {
    disable_ipv4_tproxy
    disable_ipv6_tproxy
    del_ipv4_rule
    del_ipv6_rule
    del_ipv4_set
    del_ipv6_set
}

#start_service
function start_ipv4_service() {
    stop_all_service
    check_ipv4_network
    add_ipv4_rule
    add_ipv4_set
    enable_ipv4_tproxy
}
function start_ipv6_service() {
    stop_all_service
    check_ipv4_network
    check_ipv6_network
    add_ipv4_rule
    add_ipv6_rule
    add_ipv4_set
    add_ipv6_set
    enable_ipv4_tproxy
    enable_ipv6_tproxy
}

reload_service() {
	restart
}
