OSDN Git Service

luci-app-unblockneteasemusic: initial fw4 support
authorZiMing Mo <msylgj@immortalwrt.org>
Sat, 12 Mar 2022 13:24:09 +0000 (21:24 +0800)
committerTianling Shen <cnsztl@immortalwrt.org>
Sun, 13 Mar 2022 05:04:31 +0000 (13:04 +0800)
Signed-off-by: ZiMing Mo <msylgj@immortalwrt.org>
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
applications/luci-app-unblockneteasemusic/root/etc/init.d/unblockneteasemusic
applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc [new file with mode: 0644]
applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc [new file with mode: 0644]
applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc [new file with mode: 0644]

index 1d03871..9dc778f 100755 (executable)
@@ -12,6 +12,8 @@ NAME="unblockneteasemusic"
 UPGRADE_CONF="/lib/upgrade/keep.d/$NAME"
 
 IPT_N="iptables -t nat"
+RULES_UC="/usr/share/$NAME/rules/default.uc"
+RULES_NFT="/etc/nftables.d/90-$NAME-rules.nft"
 
 is_enabled() {
        local enabled
@@ -62,6 +64,7 @@ start_service()
 
        procd_open_instance "$NAME"
        procd_set_param command node "/usr/share/$NAME/core/app.js"
+       append_param "-a" "0.0.0.0"
 
        local http_port https_port hijack_ways
        config_get http_port "config" "http_port" "5200"
@@ -70,19 +73,17 @@ start_service()
        [ "${hijack_ways}" = "use_hosts" ] && { http_port="80"; https_port="443"; }
        append_param "-p" "${http_port}":"${https_port}"
 
-       local lan_addr
-       lan_addr="$(uci get network.lan.ipaddr)"
        if is_enabled "config" "pub_access"; then
-               append_param "-a" "0.0.0.0"
-
-               iptables -I "INPUT" -p "tcp" --dport "${http_port}" -j "ACCEPT"
-               iptables -I "INPUT" -p "tcp" --dport "${https_port}" -j "ACCEPT"
-               echo "${http_port}:${https_port}" > "/tmp/$NAME.ports"
-
-               mkdir -p "/var/etc/"
-               echo "/etc/init.d/$NAME restart" > "/var/etc/$NAME.include"
-       else
-               append_param "-a" "${lan_addr}"
+               uci -q batch <<-EOF
+                       add firewall rule
+                       set firewall.@rule[-1].name='unblockneteasemusic_pub_access'
+                       set firewall.@rule[-1].proto='tcp'
+                       set firewall.@rule[-1].src='wan'
+                       set firewall.@rule[-1].dest_port='${http_port}-${https_port}'
+                       set firewall.@rule[-1].target='ACCEPT'
+                       commit firewall
+               EOF
+               fw4 reload
        fi
 
        local music_source
@@ -118,7 +119,10 @@ start_service()
        procd_set_param stderr 1
        procd_set_param respawn
 
+       local lan_addr
+       lan_addr="$(uci -q get network.lan.ipaddr)"
        if [ "${hijack_ways}" = "use_ipset" ]; then
+               ## TODO:wating for dnsmasq support nftset
                mkdir -p "/tmp/dnsmasq.d"
                rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf"
                cat <<-EOF > "/tmp/dnsmasq.d/dnsmasq-$NAME.conf"
@@ -133,42 +137,57 @@ start_service()
                EOF
                /etc/init.d/dnsmasq reload
 
-               ipset create "acl_neteasemusic_http" hash:ip
-               ipset create "acl_neteasemusic_https" hash:ip
                ip_addr_num="$(uci show "$NAME" | grep -c "filter_mode")"
                let ip_addr_num="ip_addr_num-1"
+               local acl_http_addr acl_https_addr
                [ "${ip_addr_num}" -ge "0" ] && for i in $(seq 0 "${ip_addr_num}")
                do
                        ip_addr="$(uci_get_by_name "acl_rule" "ip_addr" "" "$i")"
                        filter_mode="$(uci_get_by_name "acl_rule" "filter_mode" "" "$i")"
                        case "${filter_mode}" in
                        "disable_http")
-                               ipset -! add "acl_neteasemusic_http" "${ip_addr}"
+                               [ -n "$(command -v fw4)" ] && acl_http_addr="${acl_http_addr}${ip_addr}\n" || ipset -! add "acl_neteasemusic_http" "${ip_addr}"
                                ;;
                        "disable_https")
-                               ipset -! add "acl_neteasemusic_https" "${ip_addr}"
+                               [ -n "$(command -v fw4)" ] && acl_https_addr="${acl_https_addr}${ip_addr}\n" || ipset -! add "acl_neteasemusic_https" "${ip_addr}"
                                ;;
                        "disable_all")
-                               ipset -! add "acl_neteasemusic_http" "${ip_addr}"
-                               ipset -! add "acl_neteasemusic_https" "${ip_addr}"
+                               if [ -n "$(command -v fw4)" ]; then
+                                       acl_http_addr="${acl_http_addr}${ip_addr}\n"
+                                       acl_https_addr="${acl_https_addr}${ip_addr}\n"
+                               else
+                                       ipset -! add "acl_neteasemusic_http" "${ip_addr}"
+                                       ipset -! add "acl_neteasemusic_https" "${ip_addr}"
+                               fi
                                ;;
                        esac
                done
 
-               ipset create "neteasemusic" hash:ip
+               local neteasemusic_addr
                netease_music_ips="$(uclient-fetch -qO- "http://httpdns.n.netease.com/httpdns/v2/d?domain=music.163.com,interface.music.163.com,interface3.music.163.com,apm.music.163.com,apm3.music.163.com,clientlog.music.163.com,clientlog3.music.163.com" |jsonfilter -e '@.data.*.ip.*')"
                netease_music_ips2="$(uclient-fetch -qO- "https://music.httpdns.c.163.com/d" --post-data="music.163.com,interface.music.163.com,interface3.music.163.com,apm.music.163.com,apm3.music.163.com,clientlog.music.163.com,clientlog3.music.163.com" |jsonfilter -e '@.dns.*["ips"].*')"
-               echo -e "${netease_music_ips}\n${netease_music_ips2}" |sort -u |awk '{print "ipset add neteasemusic "$1}' |sh
-               $IPT_N -N "netease_cloud_music"
-               for local_addr in "0.0.0.0/8" "10.0.0.0/8" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "240.0.0.0/4"; do
-                       $IPT_N -A "netease_cloud_music" -d "${local_addr}" -j "RETURN"
-               done
-               $IPT_N -A "netease_cloud_music" -p "tcp" -m "set" ! --match-set "acl_neteasemusic_http" "src" --dport "80" -j "REDIRECT" --to-ports "${http_port}"
-               $IPT_N -A "netease_cloud_music" -p "tcp" -m "set" ! --match-set "acl_neteasemusic_https" "src" --dport "443" -j "REDIRECT" --to-ports "${https_port}"
-               $IPT_N -I "PREROUTING" -p "tcp" -m "set" --match-set "neteasemusic" "dst" -j "netease_cloud_music"
-
-               mkdir -p "/var/etc/"
-               echo "/etc/init.d/$NAME restart" > "/var/etc/$NAME.include"
+               ## Feature: use ucode to init NAT rules
+               local tmp="/tmp/$NAME"
+               local neteasemusic_addr="$(echo -e "${netease_music_ips}\n${netease_music_ips2}" |sort -u |awk '{print $1}')"
+               json_init
+               json_add_int o_http_port "${http_port}"
+               json_add_int o_https_port "${https_port}"
+               json_add_string o_acl_http_addr "$acl_http_addr"
+               json_add_string o_acl_https_addr "$acl_https_addr"
+               json_add_string o_neteasemusic_addr "$neteasemusic_addr"
+               json_dump -i >"$tmp.json"
+
+               if ucode -S -i "$RULES_UC" -E "$tmp.json" >"$tmp.nft" \
+                       && ! cmp -s "$tmp.nft" "$RULES_NFT"; then
+                       echo "table inet chk {include \"$tmp.nft\";}" >"$tmp.nft.chk"
+                       if nft -f "$tmp.nft.chk" -c; then
+                               mv "$tmp.nft" "$RULES_NFT"
+                               fw4 reload
+                       fi
+                       rm -f "$tmp.nft.chk"
+               fi
+               rm -f "$tmp.json"
+               rm -f "$tmp.nft"
        elif [ "${hijack_ways}" = "use_hosts" ]; then
                mkdir -p "/tmp/dnsmasq.d"
                rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf"
@@ -211,19 +230,17 @@ stop_service()
                echo "${self_issue_cert_key}" >> "${UPGRADE_CONF}"
        }
 
-       [ -f "/tmp/$NAME.ports" ] && {
-               iptables -D "INPUT" -p "tcp" --dport "$(awk -F ':' 'print $1' "/tmp/$NAME.ports")" -j "ACCEPT"
-               iptables -D "INPUT" -p "tcp" --dport "$(awk -F ':' 'print $2' "/tmp/$NAME.ports")" -j "ACCEPT"
-               rm -f "/tmp/$NAME.ports"
+       local rule="$(uci show firewall | grep "name='unblockneteasemusic_pub_access'" | awk -F '.' '{ print $2}')"
+       [ -n "${rule}" ] && {
+               uci -q batch <<-EOF
+                       delete firewall.${rule}
+                       commit firewall
+               EOF
        }
-
-       $IPT_N -D "PREROUTING" -p "tcp" -m set --match-set "neteasemusic" "dst" -j "netease_cloud_music"
-       $IPT_N -F "netease_cloud_music"
-       $IPT_N -X "netease_cloud_music"
-       ipset destroy "neteasemusic"
-       ipset destroy "acl_neteasemusic_http"
-       ipset destroy "acl_neteasemusic_https"
-       echo "" > "/var/etc/$NAME.include"
+       if [ -f "$RULES_NFT" ]; then
+               rm -f "$RULES_NFT"
+       fi
+       fw4 reload
 
        rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf"
        /etc/init.d/dnsmasq reload
diff --git a/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc b/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc
new file mode 100644 (file)
index 0000000..8e513f7
--- /dev/null
@@ -0,0 +1,25 @@
+{%
+
+let http_port = o_http_port;
+let https_port = o_https_port;
+
+%}
+
+chain netease_cloud_music {
+       type nat hook prerouting priority -1;
+       meta l4proto tcp ip daddr @neteasemusic_ipv4 jump netease_cloud_music_redir;
+       meta l4proto tcp ip6 daddr @neteasemusic_ipv6 jump netease_cloud_music_redir;
+}
+
+chain netease_cloud_music_redir {
+       ip daddr @local_addr_ipv4 return;
+       ip saddr @acl_neteasemusic_http_ipv4 accept;
+       ip saddr @acl_neteasemusic_https_ipv4 accept;
+       ip6 daddr @local_addr_ipv6 return;
+       ip6 saddr @acl_neteasemusic_http_ipv6 accept;
+       ip6 saddr @acl_neteasemusic_https_ipv6 accept;
+       tcp dport 80 counter redirect to :{{ http_port }};
+       tcp dport 443 counter redirect to :{{ https_port }};
+}
+
+
diff --git a/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc b/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc
new file mode 100644 (file)
index 0000000..9b9388a
--- /dev/null
@@ -0,0 +1,6 @@
+{%
+
+include("set.uc");
+include("chain.uc");
+
+%}
diff --git a/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc b/applications/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc
new file mode 100644 (file)
index 0000000..0bcf372
--- /dev/null
@@ -0,0 +1,94 @@
+{%
+
+let local_addr4 = "
+       0.0.0.0/8
+       10.0.0.0/8
+       100.64.0.0/10
+       127.0.0.0/8
+       169.254.0.0/16
+       172.16.0.0/12
+       192.0.0.0/24
+       192.0.2.0/24
+       192.31.196.0/24
+       192.52.193.0/24
+       192.88.99.0/24
+       192.168.0.0/16
+       192.175.48.0/24
+       198.18.0.0/15
+       198.51.100.0/24
+       203.0.113.0/24
+       224.0.0.0/4
+       240.0.0.0/4
+";
+let local_addr6 = "
+       ::1/128
+       ::/128
+       ::ffff:0:0/96
+       64:ff9b:1::/48
+       100::/64
+       fe80::/10
+       2001::/23
+       fc00::/7
+";
+let o_local_bypass = local_addr4 + " " + local_addr6;
+
+let set_suffix = {
+       "acl_neteasemusic_http": {
+               str: o_acl_http_addr,
+       },
+       "acl_neteasemusic_https": {
+               str: o_acl_https_addr,
+       },
+       "local_addr": {
+               str: o_local_bypass,
+       },
+       "neteasemusic": {
+               str: o_neteasemusic_addr,
+       },
+};
+
+function set_name(suf, af) {
+       if (af == 4) {
+               return suf+"_ipv4";
+       } else {
+               return suf+"_ipv6";
+       }
+}
+
+function set_elements_parse(res, str, af) {
+       for (let addr in split(str, /[ \t\n]/)) {
+               addr = trim(addr);
+               if (!addr) continue;
+               if (af == 4 && index(addr, ":") != -1) continue;
+               if (af == 6 && index(addr, ":") == -1) continue;
+               push(res, addr);
+       }
+}
+
+function set_elements(suf, af) {
+       let obj = set_suffix[suf];
+       let res = [];
+       let addr;
+
+       let str = obj["str"];
+       if (str) {
+               set_elements_parse(res, str, af);
+       }
+
+       return res;
+}
+%}
+
+{% for (let suf in set_suffix): for (let af in [4, 6]): %}
+set {{ set_name(suf, af) }} {
+       type ipv{{af}}_addr;
+       flags interval;
+{%   let elems = set_elements(suf, af); if (length(elems)): %}
+       elements = {
+{%     for (let i = 0; i < length(elems); i++): %}
+               {{ elems[i] }}{% if (i < length(elems) - 1): %},{% endif %}{% print("\n") %}
+{%     endfor %}
+       }
+{%   endif %}
+}
+{% endfor; endfor %}