#!/bin/bash

mark=$1
def_gateway=$2
def_interface=$3
vpn_gateway=$4
vpn_interface=$5
remote_ip=$6
netclass=$7
allow_lan=$8
mode=$9
# v6 default-gateway and v6 VPN-gateway. Empty when no IPv6 is configured;
# the v6 blocks below are gated on these being non-empty.
def_gateway_v6=${10}
vpn_gateway_v6=${11}

net_cls_root="`mount -l -t cgroup | grep "net_cls on" | cut -d ' ' -f 3 | head -n 1`"
if [ ! -f "$net_cls_root/windscribe/net_cls.classid" ]; then
    modprobe cls_cgroup
    if [ $? -ne 0 ]; then
        echo "Could not load cls_cgroup module"
        exit 1
    fi

    net_cls_root="`mount -l -t cgroup | grep "net_cls on" | cut -d ' ' -f 3 | head -n 1`"
    if [ -z "$net_cls_root" ]; then
        if [ -d /sys/fs/cgroup/net_cls ]; then
            # on some distros, cgroups v2 net_cls is mounted and it may be a symlink.  If so, unmount it and mount v1
            mount -o remount,rw /sys/fs/cgroup

            link="`readlink /sys/fs/cgroup/net_cls`"
            if [ -n "$link" ]; then
                umount /sys/fs/cgroup/${link}
            fi
            rm -f /sys/fs/cgroup/net_cls
        fi
        mkdir -p /sys/fs/cgroup/net_cls
        mount -t cgroup -onet_cls net_cls /sys/fs/cgroup/net_cls

        net_cls_root="`mount -l -t cgroup | grep "net_cls on" | cut -d ' ' -f 3 | head -n 1`"
        if [ -z "$net_cls_root" ]; then
            echo "Could not find cgroup root"
            exit 1
        fi
    fi

    mkdir -p /etc/iproute2 # create dir if it doesn't exist
    touch /etc/iproute2/rt_tables # create file if it doesn't exist

    # Add "windscribe" table definition if it doesn't exist
    if [ "`grep -c "69 windscribe" /etc/iproute2/rt_tables`" -eq 0 ]; then
        echo "69 windscribe" >> /etc/iproute2/rt_tables
    fi
    if [ "`grep -c "70 windscribe_include" /etc/iproute2/rt_tables`" -eq 0 ]; then
        echo "70 windscribe_include" >> /etc/iproute2/rt_tables
    fi

    # Create separate routing table for packets with our mark
    ip rule add fwmark "$mark" priority 16384 table windscribe
    ip route add default via "$def_gateway" dev "$def_interface" table windscribe
    ip route add 10.255.255.0/24 dev "$vpn_interface" table windscribe

    # Create separate routing table for packets that should always go into tunnel
    ip route add default via "$vpn_gateway" dev "$vpn_interface" table windscribe_include
    ip route add "$remote_ip" dev "$def_interface" table windscribe_include

    # IPv6 sibling of the rules above. 10.255.255.0/24 and $remote_ip are v4-only
    # and have no v6 counterpart.
    if [ -n "$def_gateway_v6" ] || [ -n "$vpn_gateway_v6" ]; then
        ip -6 rule add fwmark "$mark" priority 16384 table windscribe
    fi
    if [ -n "$def_gateway_v6" ]; then
        ip -6 route add default via "$def_gateway_v6" dev "$def_interface" table windscribe
    elif [ -n "$vpn_gateway_v6" ]; then
        # v4-only host with a dual-stack VPN: terminate marked v6 packets here so
        # they don't fall through to the WG 'not fwmark' rule and leak into the tunnel.
        ip -6 route add unreachable default table windscribe
    fi
    if [ -n "$vpn_gateway_v6" ]; then
        ip -6 route add default via "$vpn_gateway_v6" dev "$vpn_interface" table windscribe_include
    fi

    # Create net_cls id
    mkdir "$net_cls_root/windscribe"
    echo "$netclass" > "$net_cls_root/windscribe/net_cls.classid"
fi

# Allow IP rules to consult main routing table first, ignoring /0 or /1 routes
ip rule add priority 16383 table main suppress_prefixlength 1
priority="`ip rule show | grep 51820 | cut -d ":" -f1`" # priority of WireGuard rule, if it exists
if [ -n "$priority" ]; then
    # WG uses the same ip rule mechanism, just adjust the WG rule
    ip rule add priority $((priority - 1)) table main suppress_prefixlength 0
else
    # For non-WG protocols, remove rule forcing other traffic into the tunnel
    ip rule del priority 16385 table windscribe_include
fi

# IPv6 sibling of the priority adjust above.
if [ -n "$def_gateway_v6" ] || [ -n "$vpn_gateway_v6" ]; then
    ip -6 rule add priority 16383 table main suppress_prefixlength 1
    priority_v6="`ip -6 rule show | grep 51820 | cut -d ":" -f1`"
    if [ -n "$priority_v6" ]; then
        ip -6 rule add priority $((priority_v6 - 1)) table main suppress_prefixlength 0
    else
        ip -6 rule del priority 16385 table windscribe_include
    fi
fi

# make sure to exit with code 0 since an above command may fail if we are adding a duplicate rule or
# deleting a non-existent rule; these are not errors
exit 0
