539 lines
13 KiB
Bash
Executable File
539 lines
13 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
####################################################################################
|
|
#/etc/config/smartvpn example
|
|
#
|
|
#config global "settings"
|
|
# option disabled "1"
|
|
# option status "off"
|
|
# option type vpn
|
|
# option domain_file /etc/smartvpn/proxy.txt
|
|
# option proxy_local_port 10080
|
|
# option proxy_remote_ip 54.85.90.122
|
|
|
|
#mac: devices which transfer through vpn
|
|
#notmac: devices which not transfer through vpn
|
|
#config device 'device'
|
|
# list mac '34:17:eb:d0:e6:f9'
|
|
# list mac '34:17:eb:d0:e6:a9'
|
|
#host: website which transfer through vpn
|
|
#nothost: website which not transfer through vpn
|
|
#config dest 'dest'
|
|
# list host '.google.com'
|
|
# list notnet '169.254.0.0/16'
|
|
# list notnet '0.0.0.0/8'
|
|
# list notnet '10.0.0.0/8'
|
|
# list notnet '127.0.0.0/8'
|
|
# list notnet '169.254.0.0/16'
|
|
# list notnet '172.16.0.0/12'
|
|
# list notnet '192.168.0.0/16'
|
|
# list notnet '224.0.0.0/4'
|
|
# list notnet '240.0.0.0/4'
|
|
####################################################################################
|
|
|
|
#model=`nvram get model`
|
|
#if [ -z "$model" ]; then
|
|
# model=`cat /proc/xiaoqiang/model`
|
|
#fi
|
|
#if [ "$model" != "R1D" ]; then
|
|
# return 1
|
|
#fi
|
|
|
|
. /lib/functions.sh
|
|
. /lib/functions/network.sh
|
|
|
|
ipset_name="smartvpn"
|
|
ipset_ip_name="smartvpn_ip"
|
|
ipset_mark="0x10"
|
|
|
|
vpn_status="down"
|
|
smartvpn_cfg_domain_disabled=1
|
|
smartvpn_cfg_status="off"
|
|
smartvpn_cfg_type="vpn"
|
|
smartvpn_cfg_domainfile=""
|
|
|
|
dnsmasq_conf_path="/etc/dnsmasq.d/"
|
|
smartdns_conf_path="/etc/smartvpn/"
|
|
smartdns_conf_name="smartdns.conf"
|
|
smartdns_conf="$smartdns_conf_path/$smartdns_conf_name"
|
|
|
|
rule_file_ip="/etc/smartvpn/smartvpn_ip.txt"
|
|
|
|
set_smartvpn_cfg_status_on="uci set smartvpn.settings.status=on; uci commit smartvpn;"
|
|
set_smartvpn_cfg_status_off="uci set smartvpn.settings.status=off; uci commit smartvpn;"
|
|
|
|
hostlist_not_null=0
|
|
|
|
smartvpn_logger()
|
|
{
|
|
echo "smartvpn: $1"
|
|
logger -t smartvpn "$1"
|
|
}
|
|
|
|
smartvpn_usage()
|
|
{
|
|
echo "usage: ./smartvpn.sh on|off"
|
|
echo "value: on -- enable smartvpn"
|
|
echo "value: off -- disable smartvpn"
|
|
echo "note: smartvpn only used when vpn is UP!"
|
|
echo ""
|
|
}
|
|
|
|
dnsmasq_restart()
|
|
{
|
|
dnamasq_lock="/var/run/samartvpn.dnsmasq.lock"
|
|
trap "lock -u $dnamasq_lock; exit 1" SIGHUP SIGINT SIGTERM
|
|
lock $dnamasq_lock
|
|
|
|
$set_smartvpn_switch_off >/dev/null 2>&1
|
|
$set_switch_commit >/dev/null 2>&1
|
|
|
|
process_pid=$(ps | grep "/usr/sbin/dnsmasq" |grep -v "grep /usr/sbin/dnsmasq" | awk '{print $1}' 2>/dev/null)
|
|
process_num=$( echo $process_pid |awk '{print NF}' 2>/dev/null)
|
|
process_pid1=$( echo $process_pid |awk '{ print $1; exit;}' 2>/dev/null)
|
|
process_pid2=$( echo $process_pid |awk '{ print $2; exit;}' 2>/dev/null)
|
|
|
|
[ "$process_num" != "2" ] && /etc/init.d/dnsmasq restart
|
|
|
|
retry_times=0
|
|
while [ $retry_times -le 2 ]
|
|
do
|
|
let retry_times+=1
|
|
rm /var/etc/dnsmasq.conf
|
|
/etc/init.d/dnsmasq restart
|
|
sleep 1
|
|
|
|
process_newpid=$(ps | grep "/usr/sbin/dnsmasq" |grep -v "grep /usr/sbin/dnsmasq" | awk '{print $1}' 2>/dev/null)
|
|
process_newnum=$( echo $process_newpid |awk '{print NF}' 2>/dev/null)
|
|
process_newpid1=$( echo $process_newpid |awk '{ print $1; exit;}' 2>/dev/null)
|
|
process_newpid2=$( echo $process_newpid |awk '{ print $2; exit;}' 2>/dev/null)
|
|
|
|
echo "old: $process_pid1/$process_pid2 new: $process_newpid1/$process_newpid2"
|
|
|
|
[ "$process_pid1" == "$process_newpid1" ] && continue;
|
|
[ "$process_pid1" == "$process_newpid2" ] && continue;
|
|
[ "$process_pid2" == "$process_newpid1" ] && continue;
|
|
[ "$process_pid2" == "$process_newpid2" ] && continue;
|
|
|
|
break
|
|
done
|
|
|
|
lock -u $dnamasq_lock
|
|
}
|
|
|
|
smartvpn_dns_start()
|
|
{
|
|
# move dnsmasq conf
|
|
if [ -f $smartdns_conf ]; then
|
|
mv $smartdns_conf $dnsmasq_conf_path
|
|
fi
|
|
|
|
# flush dnsmasq
|
|
dnsmasq_restart
|
|
|
|
return
|
|
}
|
|
|
|
smartvpn_dns_stop()
|
|
{
|
|
# del smartvpn dnsmasq conf
|
|
rm "$dnsmasq_conf_path/$smartdns_conf_name"
|
|
rm "/var/etc/dnsmasq.d/$smartdns_conf_name"
|
|
rm "/tmp/etc/dnsmasq.d/$smartdns_conf_name"
|
|
|
|
# flush dnsmasq
|
|
dnsmasq_restart
|
|
|
|
return
|
|
}
|
|
|
|
smartvpn_ipset_create()
|
|
{
|
|
|
|
ipset list | grep $ipset_name > /dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
ipset create $ipset_name hash:ip > /dev/null 2>&1
|
|
ipset create $ipset_ip_name hash:net > /dev/null 2>&1
|
|
fi
|
|
}
|
|
|
|
smartvpn_ipset_add_by_file()
|
|
{
|
|
local _ipfile=$1
|
|
|
|
[ -f $_ipfile ] || return
|
|
|
|
ipset create $ipset_ip_name hash:net > /dev/null 2>&1
|
|
|
|
smartvpn_logger "add ip to ipset $ipset_ip_name."
|
|
cat $_ipfile | while read line
|
|
do
|
|
ipset add $ipset_ip_name $line
|
|
done
|
|
|
|
}
|
|
|
|
smartvpn_ipset_delete()
|
|
{
|
|
ipset flush $ipset_name
|
|
ipset flush $ipset_ip_name
|
|
|
|
ipset destroy $ipset_name # maybe failed, but doesn't matter
|
|
ipset destroy $ipset_ip_name # maybe failed, but doesn't matter
|
|
|
|
return
|
|
}
|
|
|
|
|
|
smartvpn_vpn_route_delete()
|
|
{
|
|
# del subnet default routing
|
|
network_get_subnet subnet lan
|
|
ip rule del from $(fix_subnet $subnet) table vpn
|
|
smartvpn_logger "delete $subnet to vpn."
|
|
|
|
return 0
|
|
}
|
|
|
|
smartvpn_vpn_route_add()
|
|
{
|
|
# after smartvpn is off, add wan route if vpn is still up
|
|
if [ $vpn_status == "up" ]; then
|
|
|
|
network_get_subnet subnet lan
|
|
smartvpn_logger "add $subnet to vpn."
|
|
ip rule del from $(fix_subnet $subnet) table vpn
|
|
ip rule add from $(fix_subnet $subnet) table vpn
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
smartvpn_wandns2vpn_remove()
|
|
{
|
|
network_get_dnsserver dnsservers wan
|
|
for dnsserver in $dnsservers; do
|
|
smartvpn_logger "wan dns del $dnsserver to vpn"
|
|
ip rule del to $dnsserver table vpn
|
|
done
|
|
}
|
|
|
|
smartvpn_firewall_reload_add()
|
|
{
|
|
uci -q batch <<-EOF >/dev/null
|
|
set firewall.smartvpn=include
|
|
set firewall.smartvpn.path="/lib/firewall.sysapi.loader smartvpn"
|
|
set firewall.smartvpn.reload=1
|
|
commit firewall
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
smartvpn_firewall_reload_delete()
|
|
{
|
|
uci -q batch <<-EOF >/dev/null
|
|
delete firewall.smartvpn
|
|
commit firewall
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
smartvpn_device_table="smartvpn_device"
|
|
smartvpn_mark_table="smartvpn_mark"
|
|
smartvpn_vpn_mark_redirect_open()
|
|
{
|
|
|
|
ip rule add fwmark $ipset_mark table vpn
|
|
|
|
#allowmacs="$(uci get smartvpn.device.mac 2>/dev/null)"
|
|
#notnets="$(uci get smartvpn.dest.notnet 2>/dev/null)"
|
|
|
|
iptables -t mangle -F $smartvpn_device_table 2>/dev/null
|
|
iptables -t mangle -X $smartvpn_device_table 2>/dev/null
|
|
iptables -t mangle -N $smartvpn_device_table 2>/dev/null
|
|
|
|
iptables -t mangle -F $smartvpn_mark_table 2>/dev/null
|
|
iptables -t mangle -X $smartvpn_mark_table 2>/dev/null
|
|
iptables -t mangle -N $smartvpn_mark_table 2>/dev/null
|
|
|
|
#which dest not transfer through VPN
|
|
#if [ "$smartvpn_cfg_hostnotnet" != "" ]
|
|
#then
|
|
# for notnet in $smartvpn_cfg_hostnotnet
|
|
# do
|
|
# smartvpn_logger "locat net add $notnet."
|
|
# iptables -t nat -A $smartvpn_mark_table -d $notnet -j ACCEPT
|
|
# done
|
|
#fi
|
|
|
|
#allowmacs not NULL
|
|
if [ "$smartvpn_cfg_devicemac" != "" ]
|
|
then
|
|
for mac in $smartvpn_cfg_devicemac
|
|
do
|
|
smartvpn_logger "device mac add $mac."
|
|
iptables -t mangle -A $smartvpn_device_table -m mac --mac-source $mac -j RETURN
|
|
done
|
|
|
|
iptables -t mangle -A $smartvpn_device_table -j ACCEPT
|
|
else
|
|
smartvpn_logger "all devices traffic to vpn."
|
|
iptables -t mangle -A $smartvpn_device_table -j RETURN
|
|
fi
|
|
|
|
smartvpn_logger "$dnsmasq_conf_path/$smartdns_conf_name hostlist_not_null $hostlist_not_null."
|
|
#dns mark not NULL
|
|
[ -s $dnsmasq_conf_path/$smartdns_conf_name ] && {
|
|
hostlist_not_null=1
|
|
}
|
|
smartvpn_logger "hostlist_not_null $hostlist_not_null."
|
|
|
|
if [ "$hostlist_not_null" != "1" ]
|
|
then
|
|
smartvpn_logger "add all host mark $ipset_mark to vpn."
|
|
iptables -t mangle -A $smartvpn_mark_table -j MARK --set-mark $ipset_mark
|
|
else
|
|
smartvpn_wandns2vpn_remove
|
|
smartvpn_logger "add ipset $ipset_name + $ipset_ip_name to vpn."
|
|
iptables -t mangle -A $smartvpn_mark_table -m set --match-set $ipset_name dst -j MARK --set-mark $ipset_mark
|
|
iptables -t mangle -A $smartvpn_mark_table -m set --match-set $ipset_ip_name dst -j MARK --set-mark $ipset_mark
|
|
fi
|
|
|
|
iptables -t mangle -A PREROUTING -j smartvpn_device
|
|
iptables -t mangle -A PREROUTING -j smartvpn_mark
|
|
|
|
return
|
|
}
|
|
|
|
smartvpn_vpn_mark_redirect_close()
|
|
{
|
|
iptables -t mangle -D PREROUTING -j smartvpn_device
|
|
iptables -t mangle -D PREROUTING -j smartvpn_mark
|
|
|
|
iptables -t mangle -F $smartvpn_device_table
|
|
iptables -t mangle -X $smartvpn_device_table
|
|
|
|
iptables -t mangle -F $smartvpn_mark_table
|
|
iptables -t mangle -X $smartvpn_mark_table
|
|
|
|
#iptables -t mangle -D $smartvpn_mark_table -m set --match-set $ipset_name dst -j MARK --set-mark $ipset_mark
|
|
|
|
ip rule del fwmark $ipset_mark table vpn > /dev/null 2>&1
|
|
|
|
|
|
return
|
|
}
|
|
|
|
vpn_status_get()
|
|
{
|
|
network_is_up vpn
|
|
if [ $? -eq 0 ]; then
|
|
vpn_status="up"
|
|
else
|
|
vpn_status="down"
|
|
fi
|
|
return
|
|
}
|
|
|
|
#config remote "vpn"
|
|
# option disabled "1"
|
|
# option status "off"
|
|
# option domain_file /etc/smartvpn/vpn.txt
|
|
# option type vpn
|
|
|
|
smartvpn_config_get()
|
|
{
|
|
config_load "smartvpn"
|
|
|
|
config_get smartvpn_cfg_domain_switch vpn switch &>/dev/null;
|
|
|
|
config_get smartvpn_cfg_domain_disabled vpn disabled &>/dev/null;
|
|
|
|
config_get smartvpn_cfg_status vpn status &>/dev/null;
|
|
|
|
config_get smartvpn_cfg_type vpn type &>/dev/null;
|
|
|
|
config_get smartvpn_cfg_domainfile vpn domain_file &>/dev/null;
|
|
|
|
config_get smartvpn_cfg_devicemac device mac &>/dev/null
|
|
|
|
config_get smartvpn_cfg_devicedisabled device disabled &>/dev/null
|
|
|
|
config_get smartvpn_cfg_hostnotnet dest notnet &>/dev/null
|
|
|
|
if [ -z $smartvpn_cfg_domain_disabled ];
|
|
then
|
|
smartvpn_cfg_domain_disabled="0"
|
|
fi
|
|
|
|
if [ -z $smartvpn_cfg_status ];
|
|
then
|
|
smartvpn_cfg_status="off"
|
|
fi
|
|
|
|
if [ $smartvpn_cfg_type != "vpn" ]
|
|
then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
smartvpn_flush()
|
|
{
|
|
|
|
if [ $smartvpn_cfg_domain_disabled -ne 0 ]
|
|
then
|
|
smartvpn_logger "smartvpn not enabled."
|
|
return 1
|
|
fi
|
|
|
|
if [ $smartvpn_cfg_type != "vpn" ]
|
|
then
|
|
smartvpn_logger "smartvpn not in vpn."
|
|
return 1
|
|
fi
|
|
|
|
if [ $smartvpn_cfg_status != "on" ];
|
|
then
|
|
smartvpn_logger "smartvpn not run."
|
|
return 1
|
|
fi
|
|
|
|
smartvpn_vpn_mark_redirect_close
|
|
|
|
smartvpn_vpn_mark_redirect_open
|
|
|
|
return 0;
|
|
}
|
|
|
|
smartvpn_set_off()
|
|
{
|
|
uci set smartvpn.vpn.status=off
|
|
uci commit smartvpn
|
|
}
|
|
|
|
smartvpn_set_on()
|
|
{
|
|
uci set smartvpn.vpn.status=on
|
|
uci commit smartvpn
|
|
}
|
|
|
|
smartvpn_open()
|
|
{
|
|
if [ $smartvpn_cfg_status == "on" ];
|
|
then
|
|
smartvpn_logger "already enabled."
|
|
return 1
|
|
fi
|
|
|
|
if [ $vpn_status != "up" ];
|
|
then
|
|
smartvpn_logger "vpn_status($vpn_status) is down, return."
|
|
return 1
|
|
fi
|
|
|
|
[ $smartvpn_cfg_domain_disabled == "1" ] && smartvpn_cfg_domainfile=""
|
|
|
|
if [ -s $smartvpn_cfg_domainfile -a $smartvpn_cfg_type == "vpn" ]
|
|
then
|
|
smartvpn_logger "translet domain to ipset."
|
|
gensmartdns.sh "$smartvpn_cfg_domainfile" "$smartdns_conf" "$rule_file_ip" "$ipset_name"
|
|
fi
|
|
|
|
[ $smartvpn_cfg_devicedisabled == "1" ] && smartvpn_cfg_devicemac=""
|
|
|
|
### enable smartvpn
|
|
smartvpn_ipset_create
|
|
|
|
[ -f $rule_file_ip ] && {
|
|
smartvpn_logger "add ips to ipset."
|
|
smartvpn_ipset_add_by_file $rule_file_ip
|
|
hostlist_not_null=1
|
|
rm $rule_file_ip
|
|
}
|
|
|
|
smartvpn_dns_start
|
|
smartvpn_vpn_route_delete
|
|
smartvpn_vpn_mark_redirect_open
|
|
smartvpn_firewall_reload_add
|
|
|
|
ip route flush table cache
|
|
|
|
smartvpn_logger "status set on."
|
|
|
|
smartvpn_set_on
|
|
|
|
smartvpn_logger "smartvpn open!"
|
|
|
|
return
|
|
}
|
|
|
|
smartvpn_close()
|
|
{
|
|
if [ $smartvpn_cfg_status == "off" ];
|
|
then
|
|
smartvpn_logger "status already off!"
|
|
return 0
|
|
fi
|
|
|
|
smartvpn_vpn_mark_redirect_close
|
|
smartvpn_vpn_route_add
|
|
smartvpn_firewall_reload_delete
|
|
|
|
smartvpn_dns_stop
|
|
|
|
smartvpn_ipset_delete
|
|
|
|
ip route flush table cache
|
|
|
|
smartvpn_set_off
|
|
smartvpn_logger "status set off."
|
|
|
|
smartvpn_logger "smartvpn close!"
|
|
|
|
return
|
|
}
|
|
|
|
vpn_status_get
|
|
|
|
smartvpn_config_get || return 1
|
|
|
|
OPT=$1
|
|
|
|
[ "$smartvpn_cfg_domain_switch" != "1" ] && return 1;
|
|
|
|
smartvpn_lock="/var/run/samartvpn.lock"
|
|
trap "lock -u $smartvpn_lock; exit 1" SIGHUP SIGINT SIGTERM
|
|
lock $smartvpn_lock
|
|
#main
|
|
case $OPT in
|
|
on)
|
|
smartvpn_close
|
|
smartvpn_cfg_status=off
|
|
smartvpn_open
|
|
lock -u $smartvpn_lock
|
|
return $?
|
|
;;
|
|
|
|
flush)
|
|
smartvpn_close
|
|
smartvpn_cfg_status=off
|
|
smartvpn_open
|
|
lock -u $smartvpn_lock
|
|
return $?
|
|
;;
|
|
off)
|
|
smartvpn_close
|
|
lock -u $smartvpn_lock
|
|
return $?
|
|
;;
|
|
|
|
*)
|
|
smartvpn_usage
|
|
lock -u $smartvpn_lock
|
|
return 1
|
|
;;
|
|
esac
|
|
|