From d7b0dc611f9fe10f5be116e4581dae08958666a7 Mon Sep 17 00:00:00 2001 From: Stan Grishin Date: Thu, 25 Jan 2018 19:16:35 -0800 Subject: [PATCH] vpnbypass: better start/stop from Web UI and triggers Signed-off-by: Stan Grishin --- net/vpnbypass/Makefile | 53 ++++++++++++++++++-- net/vpnbypass/files/README.md | 8 +-- net/vpnbypass/files/vpnbypass.init | 78 ++++++++++++++++-------------- 3 files changed, 93 insertions(+), 46 deletions(-) diff --git a/net/vpnbypass/Makefile b/net/vpnbypass/Makefile index 50614e6140..2c0b545cff 100644 --- a/net/vpnbypass/Makefile +++ b/net/vpnbypass/Makefile @@ -4,8 +4,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=vpnbypass -PKG_VERSION:=1.3.0 -PKG_RELEASE:=6 +PKG_VERSION:=1.3.1 +PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0+ PKG_MAINTAINER:=Stan Grishin @@ -15,15 +15,16 @@ define Package/vpnbypass SECTION:=net CATEGORY:=Network DEPENDS:=+ipset +iptables - CONFLICTS:=openvpn-policy-routing - TITLE:=Simple VPN Bypass Service + CONFLICTS:=vpn-policy-routing + TITLE:=VPN Bypass Service PKGARCH:=all endef define Package/vpnbypass/description This service can be used to enable simple VPN split tunnelling. Supports accessing domains, IP ranges outside of your VPN tunnel. -Also supports dedicating local ports/IP ranges for direct internet access (outside of your VPN tunnel). +Also supports dedicating local ports/IP ranges for direct +internet access (outside of your VPN tunnel). Please see the README for further information. endef @@ -52,4 +53,46 @@ define Package/vpnbypass/install $(INSTALL_DATA) ./files/vpnbypass.hotplug $(1)/etc/hotplug.d/firewall/94-vpnbypass endef + +define Package/$(PKG_NAME)/postinst + #!/bin/sh + # check if we are on real system + if [ -z "$${IPKG_INSTROOT}" ]; then + while [ ! -z "$(uci -q get ucitrack.@vpnbypass[-1] 2>/dev/null)" ] ; do + uci -q delete ucitrack.@vpnbypass[-1] + done + + while [ ! -z "$(uci -q get ucitrack.@firewall[-1].affects 2>/dev/null | awk '/vpnbypass/')" ] ; do + uci -q del_list ucitrack.@firewall[-1].affects='vpnbypass' + done + + uci -q batch <<-EOF >/dev/null + add ucitrack vpnbypass + set ucitrack.@vpnbypass[-1].init='vpnbypass' + add_list ucitrack.@firewall[-1].affects='vpnbypass' + commit ucitrack + EOF + fi + exit 0 +endef + +define Package/$(PKG_NAME)/prerm + #!/bin/sh + # check if we are on real system + if [ -z "$${IPKG_INSTROOT}" ]; then + echo "Stopping service and removing rc.d symlink for vpnbypass" + /etc/init.d/vpnbypass stop || true + /etc/init.d/vpnbypass disable + + while [ ! -z "$(uci -q get ucitrack.@vpnbypass[-1] 2>/dev/null)" ] ; do + uci -q delete ucitrack.@vpnbypass[-1] + done + + while [ ! -z "$(uci -q get ucitrack.@firewall[-1].affects 2>/dev/null | awk '/vpnbypass/')" ] ; do + uci -q del_list ucitrack.@firewall[-1].affects='vpnbypass' + done + fi + exit 0 +endef + $(eval $(call BuildPackage,vpnbypass)) diff --git a/net/vpnbypass/files/README.md b/net/vpnbypass/files/README.md index ddeeab9ff3..eaccd2ca59 100644 --- a/net/vpnbypass/files/README.md +++ b/net/vpnbypass/files/README.md @@ -1,5 +1,5 @@ # VPN Bypass -A simple PROCD-based vpnbypass service for OpenWrt/LEDE Project. Useful if your router accesses internet thru VPN client/tunnel, but you want specific traffic (ports, IP ranges, domains or local IP ranges) to be routed outside of this tunnel. +A simple PROCD-based ```vpnbypass``` service for OpenWrt/LEDE Project. Useful if your router accesses internet thru VPN client/tunnel, but you want specific traffic (ports, IP ranges, domains or local IP ranges) to be routed outside of this tunnel. ## Features - Allows to define local ports so that traffic to them is routed outside of the VPN tunnel (by default routes Plex Media Server traffic (port 32400) outside of the VPN tunnel). @@ -52,15 +52,15 @@ If these packages are not found in the official feed/repo for your version of Op #### Add custom repo to your router If your router is not set up with the access to repository containing these packages you will need to add custom repository to your router by connecting to your router via ssh and running the following commands: -###### OpenWrt CC 15.05.1 +###### OpenWrt 15.05.1 ```sh -opkg update; opkg install wget libopenssl +opkg update; opkg install ca-certificates wget libopenssl echo -e -n 'untrusted comment: public key 7ffc7517c4cc0c56\nRWR//HUXxMwMVnx7fESOKO7x8XoW4/dRidJPjt91hAAU2L59mYvHy0Fa\n' > /tmp/stangri-repo.pub && opkg-key add /tmp/stangri-repo.pub ! grep -q 'stangri_repo' /etc/opkg/customfeeds.conf && echo 'src/gz stangri_repo https://raw.githubusercontent.com/stangri/openwrt-repo/master' >> /etc/opkg/customfeeds.conf opkg update ``` -###### LEDE Project and OpenWrt DD trunk +###### LEDE Project 17.01.x and OpenWrt 18.xx or later ```sh opkg update; opkg install uclient-fetch libustream-mbedtls echo -e -n 'untrusted comment: public key 7ffc7517c4cc0c56\nRWR//HUXxMwMVnx7fESOKO7x8XoW4/dRidJPjt91hAAU2L59mYvHy0Fa\n' > /tmp/stangri-repo.pub && opkg-key add /tmp/stangri-repo.pub diff --git a/net/vpnbypass/files/vpnbypass.init b/net/vpnbypass/files/vpnbypass.init index 67ab2cb23d..de7ff5ac2a 100644 --- a/net/vpnbypass/files/vpnbypass.init +++ b/net/vpnbypass/files/vpnbypass.init @@ -4,38 +4,45 @@ PKG_VERSION= export START=94 export USE_PROCD=1 -readonly __ok__='\033[0;32m[\xe2\x9c\x93]\033[0m' -readonly __fail__='\033[0;31m[\xe2\x9c\x97]\033[0m' -readonly __pass__='\033[0;33m[-]\033[0m' -readonly __error__='\033[0;31mERROR\033[0m' +readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m' +readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m' +readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m' +readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m' +readonly __PASS__='\033[0;33m[-]\033[0m' +readonly _ERROR_='\033[0;31mERROR\033[0m' -export verbosity=2 TID='200' IPSET='vpnbypass' FW_MARK='0x010000' FW_MASK='0xff0000' wan_if4 wan_gw +export serviceEnabled verbosity=2 TID='200' IPSET='vpnbypass' FW_MARK='0x010000' FW_MASK='0xff0000' wan_if4 wan_gw -output() { [[ $# -ne 1 ]] && { [[ ! $((verbosity & $1)) -gt 0 ]] && return 0 || shift; }; local msg; msg=$(echo -n "${1/$p_name /service }" | sed 's|\\033\[[0-9]\?;\?[0-9]\?[0-9]\?m||g'); [[ -t 1 ]] && echo -e -n "$1"; [[ $(echo -e -n "$msg" | wc -l) -gt 0 ]] && logger -t "${PKG_NAME:-service} [$$]" "$(echo -e -n ${logmsg}${msg})" && logmsg='' || logmsg=${logmsg}${msg}; } -PKG_NAME="${PKG_NAME:-vpnbypass}"; p_name="${PKG_NAME} ${PKG_VERSION}" +output() { [[ $# -ne 1 ]] && { [[ ! $((verbosity & $1)) -gt 0 ]] && return 0 || shift; }; local msg; msg=$(echo -n "${1/$serviceName /service }" | sed 's|\\033\[[0-9]\?;\?[0-9]\?[0-9]\?m||g'); [[ -t 1 ]] && echo -e -n "$1"; [[ $(echo -e -n "$msg" | wc -l) -gt 0 ]] && logger -t "${packageName:-service} [$$]" "$(echo -e -n ${logmsg}${msg})" && logmsg='' || logmsg=${logmsg}${msg}; } +readonly packageName='vpnbypass' +readonly serviceName="$packageName $PKG_VERSION" + +load_package_config() { + config_load "$packageName" + config_get_bool serviceEnabled 'config' 'enabled' 1 + config_get verbosity 'config' 'verbosity' '2' + source /lib/functions/network.sh +} is_enabled() { - local c=1 enabled - config_load $PKG_NAME - config_get_bool enabled 'config' 'enabled' 1 - config_get verbosity 'config' 'verbosity' '2' - config_get TID 'config' 'table_number' '200' - config_get IPSET 'config' 'ipset' 'vpnbypass' - config_get FW_MARK 'config' 'fw_mark' '0x010000' - config_get FW_MASK 'config' 'fw_mask' '0xff0000' - source /lib/functions/network.sh - [[ $enabled -gt 0 ]] || { output "$__error__: $p_name is not enabled.\n"; return 1; } - source /lib/functions/network.sh + local sleepCount=1 + load_package_config while : ; do network_find_wan wan_if4 + [ $serviceEnabled -gt 0 ] || return 1 [ -n "$wan_if4" ] && network_get_gateway wan_gw $wan_if4 - [[ $c -ge 25 || -n "$wan_gw" ]] && break - output "$p_name waiting for wan gateway...\n" - sleep 2; network_flush_cache; let "c+=1"; + [[ $sleepCount -ge 25 || -n "$wan_gw" ]] && break + output "$serviceName waiting for wan gateway...\n" + sleep 2; network_flush_cache; let "sleepCount+=1"; done - [ -n "$wan_gw" ] && return 0 || { output "$__error__: $p_name failed to discover WAN gateway.\n"; return 1; } + [ -n "$wan_gw" ] && return 0 + output "$__ERROR__: $serviceName failed to discover WAN gateway.\n"; return 1; } +is_ovpn() { local dev; dev=$(uci -q get network.$1.ifname); if [[ "${dev:0:3}" == "tun" || "${dev:0:3}" == "tap" || -f "/sys/devices/virtual/net/${dev}/tun_flags" ]]; then return 0; else return 1; fi; } +is_wan() { if [ -n "$wan_if4" ] && [ "$1" == "$wan_if4" ]; then return 0; else return 1; fi; } +is_supported_interface() { if is_wan "$1" || is_ovpn "$1"; then return 0; else return 1; fi; } + ipt() { local d; d=$(echo "$*" | sed s/-A/-D/g); [ "$d" != "$*" ] && iptables $d >/dev/null 2>&1 @@ -46,7 +53,7 @@ ipt() { d=$(echo "$*" | sed s/-N/-X/g) [ "$d" != "$*" ] && iptables $d >/dev/null 2>&1 d="$*" - iptables $d >/dev/null 2>&1 || output "\n$__error__: iptables $d\n" + iptables $d >/dev/null 2>&1 || output "\n$__ERROR__: iptables $d\n" } start_service() { @@ -70,29 +77,26 @@ start_service() { for ll in ${lports}; do ipt -t mangle -I VPNBYPASS 1 -j MARK --set-mark ${FW_MARK}/${FW_MASK} -p tcp -m multiport --sport "${ll//-/:}"; done for ll in ${routes}; do ipt -t mangle -I VPNBYPASS 1 -j MARK --set-mark ${FW_MARK}/${FW_MASK} -d "$ll"; done for ll in ${rports}; do ipt -t mangle -I VPNBYPASS 1 -j MARK --set-mark ${FW_MARK}/${FW_MASK} -p tcp -m multiport --dport "${ll//-/:}"; done - output "$p_name started with TID: $TID; FW_MARK: $FW_MARK\n" + output "$serviceName started with TID: $TID; FW_MARK: $FW_MARK\n" } stop_service() { - is_enabled || return 1 - + load_package_config ip rule del fwmark "$FW_MARK" table "$TID" >/dev/null 2>&1; ipset -q flush "$IPSET"; ipset -q destroy "$IPSET"; ip route flush table "$TID"; ip route flush cache; - iptables -t mangle -D PREROUTING -m mark --mark 0x00/${FW_MASK} -g VPNBYPASS >/dev/null 2>&1 - iptables -t mangle -F VPNBYPASS >/dev/null 2>&1; iptables -t mangle -X VPNBYPASS >/dev/null 2>&1; - output "$p_name stopped\n" + ipt -t mangle -D PREROUTING -m mark --mark 0x00/${FW_MASK} -g VPNBYPASS + ipt -t mangle -F VPNBYPASS; ipt -t mangle -X VPNBYPASS; + output "$serviceName stopped\n" } -reload_service(){ - start_service -} - -st_load_interfaces(){ local d; config_get d $1 ifname; [[ "$1" == "$wan_if4" || "$d" != "${d/tun}" || "$d" != "${d/tap}" ]] && ifaces=" ${1} ${ifaces}"; } +service_triggers_load_interface() { is_supported_interface "$1" && ifaces="${ifaces}${1} "; } service_triggers() { local ifaces n - procd_add_reload_trigger 'vpnbypass' + config_load network; config_foreach service_triggers_load_interface 'interface'; + procd_add_reload_trigger 'firewall' + procd_add_reload_trigger 'openvpn' procd_open_trigger - procd_add_config_trigger "config.change" "vpnbypass" /etc/init.d/vpnbypass reload - for n in $ifaces; do procd_add_interface_trigger "interface.*" "$n" /etc/init.d/openvpn-policy-routing reload; done; + for n in $ifaces; do procd_add_reload_interface_trigger "$n"; procd_add_interface_trigger "interface.*" "$n" /etc/init.d/${packageName} reload; done; + output 2 "$serviceName monitoring interfaces: $ifaces $_OK_\n" procd_close_trigger }