#!/bin/sh /etc/rc.common # Copyright (C) 2018 Ycarus (Yannick Chabanois) START=99 STOP=10 USE_PROCD=1 . /usr/lib/unbound/iptools.sh _bypass_ip() { local ip=$1 local type=$2 [ -z "$type" ] && type="all" valid_ip4=$( valid_subnet4 $ip) valid_ip6=$( valid_subnet6 $ip) if [ "$valid_ip4" = "ok" ]; then ipset -q add omr_dst_bypass_$type $ip elif [ "$valid_ip6" = "ok" ]; then ipset -q add omr6_dst_bypass_$type $ip fi } _bypass_domains() { local domain local intf config_get domain $1 name config_get intf $1 interface _bypass_domain $domain $intf } _bypass_domain() { local domain=$1 local intf=$2 [ -z "$intf" ] && intf="all" if [ -n "$domain" ]; then domain=$(echo $domain | sed 's:^\.::') #logger -t "omr-bypass" "Get IPs of $domain..." if [ -z $BOOT ]; then resolve=$(dig a +timeout=3 +nocmd +noall +answer $domain | awk '{print $5}') for ip in $resolve; do _bypass_ip $ip $intf done resolve=$(dig aaaa +timeout=3 +nocmd +noall +answer $domain | awk '{print $5}') for ip in $resolve; do _bypass_ip $ip $intf done fi uci -q add_list dhcp.@dnsmasq[0].ipset="/$domain/omr_dst_bypass_$intf,omr6_dst_bypass_$intf" #logger -t "omr-bypass" "Get IPs of $domain... Done" fi } _bypass_mac() { local mac local intf config_get mac $1 mac config_get intf $1 interface local intfid="$(uci -q get omr-bypass.$intf.id)" [ -z "$intf" ] && intf="all" [ -z "$mac" ] && return if [ "$intf" = "all" ]; then iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass -m mac --mac-source $mac -j MARK --set-mark 0x539 COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6 -m mac --mac-source $mac -j MARK --set-mark 0x6539 COMMIT EOF else iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass -m mac --mac-source $mac -j MARK --set-mark 0x539$intfid COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6 -m mac --mac-source $mac -j MARK --set-mark 0x6539$intfid COMMIT EOF fi } _bypass_lan_ip() { local ip local intf config_get ip $1 ip config_get intf $1 interface local intfid="$(uci -q get omr-bypass.$intf.id)" [ -z "$intf" ] && intf="all" [ -z "$ip" ] && return if [ "$intf" = "all" ]; then iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass -s $ip -j MARK --set-mark 0x539 COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6 -s $ip -j MARK --set-mark 0x6539 COMMIT EOF else iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass -s $ip -j MARK --set-mark 0x539$intfid COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6 -s $ip -j MARK --set-mark 0x6539$intfid COMMIT EOF fi } _bypass_proto() { local proto local intf config_get proto $1 proto config_get intf $1 interface local intfid="$(uci -q get omr-bypass.$intf.id)" [ -z "$intf" ] && intf="all" [ -z "$proto" ] && return if [ "$intf" = "all" ]; then iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass-dpi -m ndpi --proto $proto -j MARK --set-mark 0x539 COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6-dpi -m ndpi --proto $proto -j MARK --set-mark 0x6539 COMMIT EOF else iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass-dpi -m ndpi --proto $proto -j MARK --set-mark 0x539$intfid COMMIT EOF ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6-dpi -m ndpi --proto $proto -j MARK --set-mark 0x6539$intfid COMMIT EOF fi # Use dnsmasq ipset to bypass domains of the proto local domains domains="$(cat /proc/net/xt_ndpi/host_proto | grep $proto: | sed -e "s/$proto://" -e 's/*//' -e 's/,/ /g')" if [ -n "$domains" ]; then for domain in $domains; do if [ -n "$domain" ] && [ "$(uci -q show omr-bypass | grep $domain)" = "" ]; then _bypass_domain $domain $intf fi done fi } _intf_rule() { local intf config_get intf $1 ifname [ -z "$intf" ] && intf=$(ifstatus "$1" | jsonfilter -q -e '@["l3_device"]') #count=$((count+1)) config_get count $1 metric local mode config_get mode $1 multipath "off" [ "$mode" = "off" ] && return [ -z "$count" ] && return [ -z "$intf" ] && return [ "$(echo $1 | grep _dev)" != "" ] && return ipset -q flush omr_dst_bypass_$intf > /dev/null 2>&1 ipset -q flush omr6_dst_bypass_$intf > /dev/null 2>&1 ipset -q --exist restore <<-EOF create omr_dst_bypass_$intf hash:net hashsize 64 create omr6_dst_bypass_$intf hash:net family inet6 hashsize 64 EOF if [ "$(uci -q get openmptcprouter.settings.uci_rules)" = "1" ]; then uci -q batch <<-EOF >/dev/null delete network.${1}_fw_rule=rule set network.${1}_fw_rule=rule set network.${1}_fw_rule.priority=1 set network.${1}_fw_rule.mark=0x539${count} set network.${1}_fw_rule.lookup=${count} delete network.${1}_fw_rule6=rule6 set network.${1}_fw_rule6=rule6 set network.${1}_fw_rule6.priority=1 set network.${1}_fw_rule6.mark=0x6539${count} set network.${1}_fw_rule6.lookup=${count} commit network EOF else ip rule add prio 1 fwmark 0x539$count lookup $count pref 1 > /dev/null 2>&1 ip -6 rule add prio 1 fwmark 0x6539$count lookup 6$count > /dev/null 2>&1 fi if [ "$(iptables -w 40 -t mangle -L | grep omr_dst_bypass_$intf)" = "" ]; then iptables-restore --wait=60 --noflush <<-EOF *mangle -I omr-bypass 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count COMMIT EOF fi if [ "$(iptables -w 40 -t nat -L | grep ss_rules_pre_src)" != "" ] && [ "$(iptables -w 40 -t nat -L | grep omr_dst_bypass_$intf)" = "" ]; then iptables-restore --wait=60 --noflush <<-EOF *nat -I ss_rules_dst 1 -m set --match-set omr_dst_bypass_$intf dst -j RETURN -I ss_rules_local_out 1 -m set --match-set omr_dst_bypass_$intf dst -j RETURN -I ss_rules_local_out 2 -m mark --mark 0x539$count -j RETURN -I ss_rules_pre_src 1 -m set --match-set omr_dst_bypass_$intf dst -j MARK --set-mark 0x539$count -I ss_rules_pre_src 2 -m mark --mark 0x539$count -j RETURN COMMIT EOF fi if [ "$(ip6tables -w 40 -t mangle -L | grep omr6_dst_bypass_$intf)" = "" ]; then ip6tables-restore --wait=60 --noflush <<-EOF *mangle -I omr-bypass6 1 -m set --match-set omr6_dst_bypass_$intf dst -j MARK --set-mark 0x6539$count COMMIT EOF fi if [ "$(ip6tables -w 40 -t nat -L | grep ss_rules6_pre_src)" != "" ] && [ "$(ip6tables -w 40 -t nat -L | grep omr6_dst_bypass_$intf)" = "" ]; then ip6tables-restore --wait=60 --noflush <<-EOF *nat -I ss_rules6_dst 1 -m set --match-set omr6_dst_bypass_$intf dst -j RETURN -I ss_rules6_local_out 1 -m set --match-set omr6_dst_bypass_$intf dst -j RETURN -I ss_rules6_local_out 2 -m mark --mark 0x6539$count -j RETURN -I ss_rules6_pre_src 1 -m set --match-set omr6_dst_bypass_$intf dst -j MARK --set-mark 0x6539$count -I ss_rules6_pre_src 2 -m mark --mark 0x6539$count -j RETURN COMMIT EOF fi uci -q set omr-bypass.$intf=interface uci -q set omr-bypass.$intf.id=$count } _bypass_ip_set() { local ip local interface config_get ip $1 ip config_get interface $1 interface _bypass_ip $ip $interface } _bypass_asn() { local asn local interface config_get asn $1 asn config_get interface $1 interface local asnips asnips=`curl --max-time 4 -s -k https://stat.ripe.net/data/announced-prefixes/data.json?resource=${asn} | jsonfilter -q -e '@.data.prefixes.*.prefix'` for ip in $asnips; do _bypass_ip $ip $interface done } _bypass_omr_server() { local ip config_get ip $1 ip _bypass_ip $ip } boot() { BOOT=1 start "$@" } start_service() { #local count logger -t "omr-bypass" "Starting OMR-ByPass..." ipset -q flush omr_dst_bypass_all > /dev/null 2>&1 ipset -q flush omr6_dst_bypass_all > /dev/null 2>&1 ipset -q --exist restore <<-EOF create omr_dst_bypass_all hash:net hashsize 64 create omr6_dst_bypass_all hash:net family inet6 hashsize 64 EOF iptables-save --counters | grep -v omr-bypass | iptables-restore --counters iptables-restore --wait=60 --noflush <<-EOF *mangle :omr-bypass - -I PREROUTING 1 -m addrtype ! --dst-type LOCAL -j omr-bypass COMMIT EOF ip6tables-save --counters | grep -v omr-bypass6 | ip6tables-restore --counters ip6tables-restore --wait=60 --noflush <<-EOF *mangle :omr-bypass6 - -I PREROUTING 1 -m addrtype ! --dst-type LOCAL -j omr-bypass6 COMMIT EOF config_load network config_foreach _intf_rule interface local ndpi_rules="" config_load openmptcprouter config_foreach _bypass_omr_server server config_load omr-bypass config_foreach _bypass_ip_set ips config_foreach _bypass_mac macs config_foreach _bypass_lan_ip lan_ip config_foreach _bypass_asn asns dnsmasqipset=$(uci -q get dhcp.@dnsmasq[0].ipset | sed 's/ /\n/g' | grep -v dst_bypass) uci -q delete dhcp.@dnsmasq[0].ipset if [ -n "$dnsmasqipset" ]; then for dnsipset in $dnsmasqipset; do uci -q add_list dhcp.@dnsmasq[0].ipset=$dnsipset done fi config_foreach _bypass_domains domains uci -q commit dhcp ip rule add prio 1 fwmark 0x539 lookup 991337 > /dev/null 2>&1 ip -6 rule add prio 1 fwmark 0x6539 lookup 6991337 > /dev/null 2>&1 if [ "$(iptables -w 40 -t mangle -L | grep 'match-set omr_dst_bypass_all dst MARK set')" = "" ]; then iptables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 COMMIT EOF fi if [ "$(iptables -w 40 -t nat -L | grep ss_rules_pre_src)" != "" ] && [ "$(iptables -w 40 -t nat -L | grep omr_dst_bypass_all)" = "" ]; then iptables-restore --wait=60 --noflush <<-EOF *nat -I ss_rules_dst 1 -m set --match-set omr_dst_bypass_all dst -j RETURN -I ss_rules_local_out 1 -m set --match-set omr_dst_bypass_all dst -j RETURN -I ss_rules_local_out 2 -m mark --mark 0x539 -j RETURN -I ss_rules_pre_src 1 -m set --match-set omr_dst_bypass_all dst -j MARK --set-mark 0x539 -I ss_rules_pre_src 2 -m mark --mark 0x539 -j RETURN COMMIT EOF fi if [ "$(ip6tables -w 40 -t mangle -L | grep 'match-set omr6_dst_bypass_all dst MARK set')" = "" ]; then ip6tables-restore --wait=60 --noflush <<-EOF *mangle -A omr-bypass6 -m set --match-set omr6_dst_bypass_all dst -j MARK --set-mark 0x6539 COMMIT EOF fi if [ "$(ip6tables -w 40 -t nat -L | grep ss_rules6_pre_src)" != "" ] && [ "$(ip6tables -w 40 -t nat -L | grep omr6_dst_bypass_all)" = "" ]; then ip6tables-restore --wait=60 --noflush <<-EOF *nat -I ss_rules6_dst 1 -m set --match-set omr6_dst_bypass_all dst -j RETURN -I ss_rules6_local_out 1 -m set --match-set omr6_dst_bypass_all dst -j RETURN -I ss_rules6_local_out 2 -m mark --mark 0x6539 -j RETURN -I ss_rules6_pre_src 1 -m set --match-set omr6_dst_bypass_all dst -j MARK --set-mark 0x6539 -I ss_rules6_pre_src 2 -m mark --mark 0x6539 -j RETURN COMMIT EOF fi iptables-save --counters | grep -v omr-bypass-dpi | iptables-restore --counters iptables-restore --wait=60 --noflush <<-EOF *mangle :omr-bypass-dpi - -A PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass-dpi -A POSTROUTING -m addrtype --dst-type LOCAL -j omr-bypass-dpi COMMIT EOF ip6tables-save --counters | grep -v omr-bypass6-dpi | ip6tables-restore --counters ip6tables-restore --wait=60 --noflush <<-EOF *mangle :omr-bypass6-dpi - -A PREROUTING -m addrtype ! --dst-type LOCAL -j omr-bypass6-dpi -A POSTROUTING -m addrtype --dst-type LOCAL -j omr-bypass6-dpi COMMIT EOF config_load omr-bypass config_foreach _bypass_proto dpis /etc/init.d/dnsmasq reload logger -t "omr-bypass" "OMR-ByPass is running" } stop_service() { iptables-save --counters | grep -v omr-bypass | iptables-restore --counters iptables-save --counters | grep -v omr_dst | iptables-restore --counters ip6tables-save --counters | grep -v omr-bypass6 | ip6tables-restore --counters ip6tables-save --counters | grep -v omr6_dst | ip6tables-restore --counters for setname in $(ipset -n list | grep "omr_"); do ipset destroy "$setname" 2>/dev/null || true done } service_triggers() { PROCD_RELOAD_DELAY=1000 procd_add_reload_trigger omr-bypass procd_add_raw_trigger "interface.*" 2000 /etc/init.d/omr-bypass restart } reload_service() { [ "$( ipset -n list | grep omr_ )" = "" ] && return 0 start }