# 自动更新TP-Link虚拟服务器端口映射策略（IPv6）

> 通过相应脚本和定时任务配合，实现白天启用22、3389端口的 TCP 访问，晚上22点启用22、3389端口的 UDP 访问，变相实现白天开启 SSH、RDP 登录，晚上关闭SSH登录（解析：SSH 和 RDP 使用的是 TCP 协议，使用 UDP 协议无法访问）。

### update\_firewall\_22\_tcp.sh

```sh
#!/bin/bash

ROUTER_IP="192.168.1.1"
PASSWORD="qKL8r6vPPH9fbwK"
LOGIN_PAYLOAD="{\"method\":\"do\",\"login\":{\"password\":\"$PASSWORD\"}}"

# 获取 stok
RESPONSE=$(curl -s -X POST http://$ROUTER_IP/ \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data "$LOGIN_PAYLOAD")

# 提取 stok
STOK=$(echo $RESPONSE | grep -oP '(?<="stok":")[^"]+')

# 检查是否成功获取 stok
if [ -z "$STOK" ]; then
    echo "Failed to get stok."
    exit 1
fi

#echo "Successfully obtained stok: $STOK"


# 获取 jump IPv6
IPv6_jump_ssh=$(/usr/sbin/ip -6 addr show | awk '/inet6 / {gsub(/\/.*$/, "", $2); print length($2), $2}' | sort -nrk1 | head -n1 | awk '{print $2}')

if [ ! -e /usr/local/bin/IPv6_jump_ssh.txt ];then
  touch /usr/local/bin/IPv6_jump_ssh.txt
fi
IPv6_jump_ssh_old=$(cat /usr/local/bin/IPv6_jump_ssh.txt)


# 创建 JSON payload 文件
cat <<EOF > payload_firewall_get.json
{
    "firewall": {
        "table": "redirect"
    },
    "system": {
        "name": "sys_mode"
    },
    "port_manage": {
        "table": "mwan"
    },
    "method": "get"
}
EOF

# 使用获取到的 stok 进行后续请求
URL="http://$ROUTER_IP/stok=$STOK/ds"
RESPONSE1=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_firewall_get.json)

echo $RESPONSE1 | jq '.firewall.redirect[0]' | grep -i 'udp' &> /dev/null
redirect1_ssh_flag=$?


if [ "$IPv6_jump_ssh" != "$IPv6_jump_ssh_old" ] || [ "$redirect1_ssh_flag" == 0 ]; then

# 创建 JSON payload 文件
cat <<EOF > payload_update_firewall_22_tcp.json
{
    "firewall": {
        "redirect_1": {
            "proto": "tcp",
            "src_dport_start": 52322,
            "src_dport_end": 52322,
            "dest_port": 22,
            "wan_port": 0,
            "dest_ip": "",
            "dest_ip6": "$IPv6_jump_ssh"
        }
    },
    "method": "set"
}
EOF


RESPONSE2=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_update_firewall_22_tcp.json)


echo -n $IPv6_jump_ssh > /usr/local/bin/IPv6_jump_ssh.txt
date >> /var/log/update_firewall_22_tcp.log
echo "Firewall: TCP WAN-52322 -> LAN-22 ${IPv6_jump_ssh} updated!" &>> /var/log/update_firewall_22_tcp.log
echo >> /var/log/update_firewall_22_tcp.log

fi
```

### update\_firewall\_3389\_tcp.sh

```sh
#!/bin/bash

ROUTER_IP="192.168.1.1"
PASSWORD="qKL8r6vPPxxxxxx"
LOGIN_PAYLOAD="{\"method\":\"do\",\"login\":{\"password\":\"$PASSWORD\"}}"

# 获取 stok
RESPONSE=$(curl -s -X POST http://$ROUTER_IP/ \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data "$LOGIN_PAYLOAD")

# 提取 stok
STOK=$(echo $RESPONSE | grep -oP '(?<="stok":")[^"]+')

# 检查是否成功获取 stok
if [ -z "$STOK" ]; then
    echo "Failed to get stok."
    exit 1
fi

#echo "Successfully obtained stok: $STOK"

# 创建 JSON payload 文件
cat <<EOF > payload_online_hosts.json
{"hosts_info":{"table":"online_host"},"method":"get"}
EOF

# 使用获取到的 stok 进行后续请求
URL="http://$ROUTER_IP/stok=$STOK/ds"
RESPONSE1=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_online_hosts.json)

# 获取 Win rdp IPv6
IPv6_win_rdp=$(echo $RESPONSE1 | jq '.. | objects | select(.mac == "58-47-ca-73-8f-00") | .ipv6' | tr -d '"')
# echo $IPv6_win_rdp

if [ ! -e /usr/local/bin/IPv6_win_rdp.txt ];then
  touch /usr/local/bin/IPv6_win_rdp.txt
fi
IPv6_win_rdp_old=$(cat /usr/local/bin/IPv6_win_rdp.txt)


if [ -n "$IPv6_win_rdp" ] && [ "$IPv6_win_rdp" != "$IPv6_win_rdp_old" ]; then

# 创建 JSON payload 文件
cat <<EOF > payload_update_firewall_3389_tcp.json
{
    "firewall": {
        "redirect_2": {
            "proto": "tcp",
            "src_dport_start": 52389,
            "src_dport_end": 52389,
            "dest_port": 3389,
            "wan_port": 0,
            "dest_ip": "",
            "dest_ip6": "$IPv6_win_rdp"
        }
    },
    "method": "set"
}
EOF


RESPONSE2=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_update_firewall_3389_tcp.json)

echo -n $IPv6_win_rdp > /usr/local/bin/IPv6_win_rdp.txt
date >> /var/log/update_firewall_3389_tcp.log
echo "Firewall: TCP WAN-52389 -> LAN-3389 ${IPv6_win_rdp} updated!" &>> /var/log/update_firewall_3389_tcp.log
echo >> /var/log/update_firewall_3389_tcp.log

fi
```

### update\_firewall\_22\_3389\_udp.sh

```sh
#!/bin/bash

ROUTER_IP="192.168.1.1"
PASSWORD="qKL8r6vPPxxxxxx"
LOGIN_PAYLOAD="{\"method\":\"do\",\"login\":{\"password\":\"$PASSWORD\"}}"

# 获取 stok
RESPONSE=$(curl -s -X POST http://$ROUTER_IP/ \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data "$LOGIN_PAYLOAD")

# 提取 stok
STOK=$(echo $RESPONSE | grep -oP '(?<="stok":")[^"]+')

# 检查是否成功获取 stok
if [ -z "$STOK" ]; then
    echo "Failed to get stok."
    exit 1
fi

#echo "Successfully obtained stok: $STOK"

# 创建 JSON payload 文件
cat <<EOF > payload_firewall_get.json
{
    "firewall": {
        "table": "redirect"
    },
    "system": {
        "name": "sys_mode"
    },
    "port_manage": {
        "table": "mwan"
    },
    "method": "get"
}
EOF

# 使用获取到的 stok 进行后续请求
URL="http://$ROUTER_IP/stok=$STOK/ds"
RESPONSE=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_firewall_get.json)

redirect1_ssh=$(echo $RESPONSE | jq '.firewall.redirect[0]' | sed 's/tcp/udp/')
redirect2_rdp=$(echo $RESPONSE | jq '.firewall.redirect[1]' | sed 's/tcp/udp/')


# 创建 JSON payload 文件
cat <<EOF > payload_update_firewall_22_udp.json
{
    "firewall": $redirect1_ssh,
    "method": "set"
}
EOF

# 创建 JSON payload 文件
cat <<EOF > payload_update_firewall_3389_udp.json
{
    "firewall": $redirect2_rdp,
    "method": "set"
}
EOF

# 更新 firewall 22 UDP
RESPONSE1=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_update_firewall_22_udp.json)

# 更新 firewall 3389 UDP
RESPONSE2=$(curl -s -X POST $URL \
    -H "Accept: application/json, text/javascript, */*; q=0.01" \
    -H "Accept-Encoding: gzip, deflate" \
    -H "Accept-Language: zh-CN,zh;q=0.9" \
    -H "Cache-Control: no-cache" \
    -H "Connection: keep-alive" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -H "Origin: http://$ROUTER_IP" \
    -H "Pragma: no-cache" \
    -H "Referer: http://$ROUTER_IP/" \
    -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" \
    -H "X-Requested-With: XMLHttpRequest" \
    --data @payload_update_firewall_3389_udp.json)
```

### 权限设置

<pre class="language-bash"><code class="lang-bash">mv ./update_firewall_22_tcp.sh /usr/local/bin/update_firewall_22_tcp
mv ./update_firewall_3389_tcp.sh /usr/local/bin/update_firewall_3389_tcp
<strong>mv ./update_firewall_22_3389_udp.sh /usr/local/bin/update_firewall_22_3389_udp
</strong>
chmod +x /usr/local/bin/update_firewall_22_tcp
chmod +x /usr/local/bin/update_firewall_3389_tcp
chmod +x /usr/local/bin/update_firewall_22_3389_udp

</code></pre>

### 定时任务

<pre><code><strong>crontab -e
</strong>*/5 10-21 * * * /usr/local/bin/update_firewall_22_tcp &#x26;>> /var/log/update_firewall_22_tcp.log
*/2 10-21 * * * /usr/local/bin/update_firewall_3389_tcp &#x26;>> /var/log/update_firewall_3389_tcp.log
00 22 * * * /usr/local/bin/update_firewall_22_3389_udp &#x26;>> /var/log/update_firewall_22_3389_udp.log
</code></pre>
