侧边栏壁纸
  • 累计撰写 29 篇文章
  • 累计创建 2 个标签
  • 累计收到 25 条评论

目 录CONTENT

文章目录

ros ddns脚本(clouflare)和动态ip回流脚本

Qiui
2025-03-04 / 1 评论 / 0 点赞 / 53 阅读 / 0 字

1. Cloudflare ddns脚本 本脚本是基于视频https://youtu.be/cSTHn2gxScY?si=r0p1PdiWqeddCJ01更改而来. 将原本需要用global api token 改为普通api token 首先需要获取获取records_ID,参考原视频。 Linux/unix终端下,

curl -X GET "https://api.cloudflare.com/client/v4/zones/Zone_ID/dns_records" \
-H "x-auth-email:email" \
-H "x-auth-key:auth-key" \
-H "content-type: application/json"

  新建script,那么填 cf_ddns 如果运行完总是会报红字错误,试试最后加一行空行

# Update Cloudflare DNS IPv4 address script
# RouterOS version >= 7.x is required

# ** CONFIGURE SECTION **

# WAN IPv4 interface
:local wanif "pppoe-out1"

# Cloudflare section
:local email "email"
:local key "auth-key"
:local zoneID "Zone_ID"
:local recordsID "record_ID"

# Domain hostname
:local hostName "ddns域名"

# DNS server for resolution
:local dnsServer "1.1.1.1"

# ** END OF CONFIGURE SECTION **

# Get WAN interface IPv4 address
:local ip4new [/ip address get [/ip address find interface=$wanif] address]
:set ip4new [:pick [:tostr $ip4new] 0 [:find [:tostr $ip4new] "/"]]

:if ([:len $ip4new] = 0) do={
:log error "[Cloudflare DDNS] Could not get IPv4 for interface $wanif"
:error "[Cloudflare DDNS] Could not get IPv4 for interface $wanif"
}

# Use DNS resolve with specified server to get current IP address of the domain
:local resolvedIp [:resolve $hostName server=$dnsServer]

:if ($resolvedIp = "") do={
:log error "[Cloudflare DDNS] Could not resolve $hostName using server $dnsServer"
:error "[Cloudflare DDNS] Could not resolve $hostName using server $dnsServer"
}

:log info "[Cloudflare DDNS] DNS resolved IP for $hostName: $resolvedIp"
:log info "[Cloudflare DDNS] Current WAN IPv4 address: $ip4new"

:if ($ip4new = $resolvedIp) do={
:log info "[Cloudflare DDNS] WAN IPv4 address for interface $wanif and DNS resolved IP are the same, no update needed."
} else {
:log info "[Cloudflare DDNS] WAN IPv4 address for interface $wanif has been changed to $ip4new."

:local url "https://api.cloudflare.com/client/v4/zones/$zoneID/dns_records/$recordsID"
:local header "X-Auth-Email: $email,Authorization: Bearer $key,Content-Type:application/json"
:local data "{\"type\":\"A\",\"name\":\"$hostName\",\"content\":\"$ip4new\",\"ttl\":60,\"proxied\":false}"

:log info "[Cloudflare DDNS] URL: $url"
:log info "[Cloudflare DDNS] HEADER: $header"
:log info "[Cloudflare DDNS] DATA: $data"
:log info "[Cloudflare DDNS] Updating host $hostName address."

:local jsonAnswer [/tool fetch http-method=put mode=https http-header-field=$header http-data=$data url=$url as-value output=user]

:if ([:len $jsonAnswer] > 0) do={

/system script run "JParseFunctions"; local JSONLoads; local JSONUnload
:local result ([$JSONLoads ($jsonAnswer->"data")]->"success")
$JSONUnload

:if ($result = true) do={
:log info "[Cloudflare DDNS] Successfully updated IPv4 address to $ip4new."
} else {
:log error "[Cloudflare DDNS] Error while updating IPv4 address."
}
} else {
:log error "[Cloudflare DDNS] No answer from Cloudflare API."
}
}

  pppoe-out1 使用的profile内的On Up部分加上:(末尾留一行空行

:delay 3s
/system/script/
run cf_ddns

2. 动态ip回流脚本 新建script ,名为“dynamic_nat”

:global addold

:global addnew

:set addnew [/interface get [/interface find name="pppoe-out1"] running]

:if ($addnew=true) do={

:set addold [/ip address get [/ip address find dynamic=yes interface="pppoe-out1"] address]

:set addold [:pick $addold 0 ([:len $addold ] -3)]

/ip firewall nat set [/ip firewall nat find comment="dynamic_nat"] dst-address=$addold

}

  同样的,在pppoe-out1 使用的profile内的On Up部分加上就变成了如下:

#dynamic_nat

:delay 3s
execute "dynamic_nat"

#cf_ddns
/system/script/
run cf_ddns

另外,ros版本大于7.14的话,新建脚本JParseFunctions,作为依赖库。来源参考: https://github.com/Winand/mikrotik-json-parser

# -------------------------------- JParseFunctions ---------------------------------------------------
# ------------------------------- fJParsePrint ----------------------------------------------------------------
:global fJParsePrint
:if (!any $fJParsePrint) do={ :global fJParsePrint do={
  :global JParseOut
  :local TempPath
  :global fJParsePrint

  :if ([:len $1] = 0) do={
    :set $1 "\$JParseOut"
    :set $2 $JParseOut
   }
   
  :foreach k,v in=$2 do={
    :if ([:typeof $k] = "str") do={
      :set k "\"$k\""
    }
    :set TempPath ($1. "->" . $k)
    :if ([:typeof $v] = "array") do={
      :if ([:len $v] > 0) do={
        $fJParsePrint $TempPath $v
      } else={
        :put "$TempPath = [] ($[:typeof $v])"
      }
    } else={
        :put "$TempPath = $v ($[:typeof $v])"
    }
  }
}}
# ------------------------------- fJParsePrintVar ----------------------------------------------------------------
:global fJParsePrintVar
:if (!any $fJParsePrintVar) do={ :global fJParsePrintVar do={
  :global JParseOut
  :local TempPath
  :global fJParsePrintVar
  :local fJParsePrintRet ""

  :if ([:len $1] = 0) do={
    :set $1 "\$JParseOut"
    :set $2 $JParseOut
   }
   
  :foreach k,v in=$2 do={
    :if ([:typeof $k] = "str") do={
      :set k "\"$k\""
    }
    :set TempPath ($1. "->" . $k)
    :if ($fJParsePrintRet != "") do={
      :set fJParsePrintRet ($fJParsePrintRet . "\r\n")
    }    
    :if ([:typeof $v] = "array") do={
      :if ([:len $v] > 0) do={
        :set fJParsePrintRet ($fJParsePrintRet . [$fJParsePrintVar $TempPath $v])
      } else={
        :set fJParsePrintRet ($fJParsePrintRet . "$TempPath = [] ($[:typeof $v])")
      }
    } else={
        :set fJParsePrintRet ($fJParsePrintRet . "$TempPath = $v ($[:typeof $v])")
    }
  }
  :return $fJParsePrintRet
}}
# ------------------------------- fJSkipWhitespace ----------------------------------------------------------------
:global fJSkipWhitespace
:if (!any $fJSkipWhitespace) do={ :global fJSkipWhitespace do={
  :global Jpos
  :global JSONIn
  :global Jdebug
  :while ($Jpos < [:len $JSONIn] and ([:pick $JSONIn $Jpos] ~ "[ \r\n\t]")) do={
    :set Jpos ($Jpos + 1)
  }
  :if ($Jdebug) do={:put "fJSkipWhitespace: Jpos=$Jpos Char=$[:pick $JSONIn $Jpos]"}
}}
# -------------------------------- fJParse ---------------------------------------------------------------
:global fJParse
:if (!any $fJParse) do={ :global fJParse do={
  :global Jpos
  :global JSONIn
  :global Jdebug
  :global fJSkipWhitespace
  :local Char

  :if (!$1) do={
    :set Jpos 0
   }
  
  $fJSkipWhitespace
  :set Char [:pick $JSONIn $Jpos]
  :if ($Jdebug) do={:put "fJParse: Jpos=$Jpos Char=$Char"}
  :if ($Char="{") do={
    :set Jpos ($Jpos + 1)
    :global fJParseObject
    :return [$fJParseObject]
  } else={
    :if ($Char="[") do={
      :set Jpos ($Jpos + 1)
      :global fJParseArray
      :return [$fJParseArray]
    } else={
      :if ($Char="\"") do={
        :set Jpos ($Jpos + 1)
        :global fJParseString
        :return [$fJParseString]
      } else={
#        :if ([:pick $JSONIn $Jpos ($Jpos+2)]~"^-\?[0-9]") do={
        :if ($Char~"[eE0-9.+-]") do={
          :global fJParseNumber
          :return [$fJParseNumber]
        } else={

          :if ($Char="n" and [:pick $JSONIn $Jpos ($Jpos+4)]="null") do={
            :set Jpos ($Jpos + 4)
            :return []
          } else={
            :if ($Char="t" and [:pick $JSONIn $Jpos ($Jpos+4)]="true") do={
              :set Jpos ($Jpos + 4)
              :return true
            } else={
              :if ($Char="f" and [:pick $JSONIn $Jpos ($Jpos+5)]="false") do={
                :set Jpos ($Jpos + 5)
                :return false
              } else={
                :put "Err.Raise 8732. No JSON object could be fJParseed"
                :set Jpos ($Jpos + 1)
                :return []
              }
            }
          }
        }
      }
    }
  }
}}

#-------------------------------- fJParseString ---------------------------------------------------------------
:global fJParseString
:if (!any $fJParseString) do={ :global fJParseString do={
  :global Jpos
  :global JSONIn
  :global Jdebug
  :global fUnicodeToUTF8
  :local Char
  :local StartIdx
  :local Char2
  :local TempString ""
  :local UTFCode
  :local Unicode

  :set StartIdx $Jpos
  :set Char [:pick $JSONIn $Jpos]
  :if ($Jdebug) do={:put "fJParseString: Jpos=$Jpos Char=$Char"}
  :while ($Jpos < [:len $JSONIn] and $Char != "\"") do={
    :if ($Char="\\") do={
      :set Char2 [:pick $JSONIn ($Jpos + 1)]
      :if ($Char2 = "u") do={
        :set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+2) ($Jpos+6)]"]
        :if ($UTFCode>=0xD800 and $UTFCode<=0xDFFF) do={
# Surrogate pair
          :set Unicode  (($UTFCode & 0x3FF) << 10)
          :set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+8) ($Jpos+12)]"]
          :set Unicode ($Unicode | ($UTFCode & 0x3FF) | 0x10000)
          :set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])         
          :set Jpos ($Jpos + 12)
        } else= {
# Basic Multilingual Plane (BMP)
          :set Unicode $UTFCode
          :set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])
          :set Jpos ($Jpos + 6)
        }
        :set StartIdx $Jpos
        :if ($Jdebug) do={:put "fJParseString Unicode: $Unicode"}
      } else={
        :if ($Char2 ~ "[\\bfnrt\"]") do={
          :if ($Jdebug) do={:put "fJParseString escape: Char+Char2 $Char$Char2"}
          :set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [[:parse "(\"\\$Char2\")"]])
          :set Jpos ($Jpos + 2)
          :set StartIdx $Jpos
        } else={
          :if ($Char2 = "/") do={
            :if ($Jdebug) do={:put "fJParseString /: Char+Char2 $Char$Char2"}
            :set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . "/")
            :set Jpos ($Jpos + 2)
            :set StartIdx $Jpos
          } else={
            :put "Err.Raise 8732. Invalid escape"
            :set Jpos ($Jpos + 2)
          }
        }
      }
    } else={
      :set Jpos ($Jpos + 1)
    }
    :set Char [:pick $JSONIn $Jpos]
  }
  :set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos])
  :set Jpos ($Jpos + 1)
  :if ($Jdebug) do={:put "fJParseString: $TempString"}
  :return $TempString
}}

#-------------------------------- fJParseNumber ---------------------------------------------------------------
:global fJParseNumber
:if (!any $fJParseNumber) do={ :global fJParseNumber do={
  :global Jpos
  :local StartIdx
  :global JSONIn
  :global Jdebug
  :local NumberString
  :local Number

  :set StartIdx $Jpos   
  :set Jpos ($Jpos + 1)
  :while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]~"[eE0-9.+-]") do={
    :set Jpos ($Jpos + 1)
  }
  :set NumberString [:pick $JSONIn $StartIdx $Jpos]
  :set Number [:tonum $NumberString] 
  :if ([:typeof $Number] = "num") do={
    :if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $Number ($[:typeof $Number])"}
    :return $Number
  } else={
    :if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $NumberString ($[:typeof $NumberString])"}
    :return $NumberString
  }
}}

#-------------------------------- fJParseArray ---------------------------------------------------------------
:global fJParseArray
:if (!any $fJParseArray) do={ :global fJParseArray do={
  :global Jpos
  :global JSONIn
  :global Jdebug
  :global fJParse
  :global fJSkipWhitespace
  :local Value
  :local ParseArrayRet [:toarray ""]
  
  $fJSkipWhitespace    
  :while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!= "]") do={
    :set Value [$fJParse true]
    :set ($ParseArrayRet->([:len $ParseArrayRet])) $Value
    :if ($Jdebug) do={:put "fJParseArray: Value="; :put $Value}
    $fJSkipWhitespace
    :if ([:pick $JSONIn $Jpos] = ",") do={
      :set Jpos ($Jpos + 1)
      $fJSkipWhitespace
    }
  }
  :set Jpos ($Jpos + 1)
#  :if ($Jdebug) do={:put "ParseArrayRet: "; :put $ParseArrayRet}
  :return $ParseArrayRet
}}

# -------------------------------- fJParseObject ---------------------------------------------------------------
:global fJParseObject
:if (!any $fJParseObject) do={ :global fJParseObject do={
  :global Jpos
  :global JSONIn
  :global Jdebug
  :global fJSkipWhitespace
  :global fJParseString
  :global fJParse
# Syntax :local ParseObjectRet ({}) don't work in recursive call, use [:toarray ""] for empty array!!!
  :local ParseObjectRet [:toarray ""]
  :local Key
  :local Value
  :local ExitDo false
  
  $fJSkipWhitespace
  :while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!="}" and !$ExitDo) do={
    :if ([:pick $JSONIn $Jpos]!="\"") do={
      :put "Err.Raise 8732. Expecting property name"
      :set ExitDo true
    } else={
      :set Jpos ($Jpos + 1)
      :set Key [$fJParseString]
      $fJSkipWhitespace
      :if ([:pick $JSONIn $Jpos] != ":") do={
        :put "Err.Raise 8732. Expecting : delimiter"
        :set ExitDo true
      } else={
        :set Jpos ($Jpos + 1)
        :set Value [$fJParse true]
        :set ($ParseObjectRet->$Key) $Value
        :if ($Jdebug) do={:put "fJParseObject: Key=$Key Value="; :put $Value}
        $fJSkipWhitespace
        :if ([:pick $JSONIn $Jpos]=",") do={
          :set Jpos ($Jpos + 1)
          $fJSkipWhitespace
        }
      }
    }
  }
  :set Jpos ($Jpos + 1)
#  :if ($Jdebug) do={:put "ParseObjectRet: "; :put $ParseObjectRet}
  :return $ParseObjectRet
}}

# ------------------- fByteToEscapeChar ----------------------
:global fByteToEscapeChar
:if (!any $fByteToEscapeChar) do={ :global fByteToEscapeChar do={
#  :set $1 [:tonum $1]
  :return [[:parse "(\"\\$[:pick "0123456789ABCDEF" (($1 >> 4) & 0xF)]$[:pick "0123456789ABCDEF" ($1 & 0xF)]\")"]]
}}

# ------------------- fUnicodeToUTF8----------------------
:global fUnicodeToUTF8
:if (!any $fUnicodeToUTF8) do={ :global fUnicodeToUTF8 do={
  :global fByteToEscapeChar
#  :local Ubytes [:tonum $1]
  :local Nbyte
  :local EscapeStr ""

  :if ($1 < 0x80) do={
    :set EscapeStr [$fByteToEscapeChar $1]
  } else={
    :if ($1 < 0x800) do={
      :set Nbyte 2
    } else={  
      :if ($1 < 0x10000) do={
        :set Nbyte 3
      } else={
        :if ($1 < 0x20000) do={
          :set Nbyte 4
        } else={
          :if ($1 < 0x4000000) do={
            :set Nbyte 5
          } else={
            :if ($1 < 0x80000000) do={
              :set Nbyte 6
            }
          }
        }
      }
    }
    :for i from=2 to=$Nbyte do={
      :set EscapeStr ([$fByteToEscapeChar ($1 & 0x3F | 0x80)] . $EscapeStr)
      :set $1 ($1 >> 6)
    }
    :set EscapeStr ([$fByteToEscapeChar (((0xFF00 >> $Nbyte) & 0xFF) | $1)] . $EscapeStr)
  }
  :return $EscapeStr
}}

# ------------------- Load JSON from arg --------------------------------
global JSONLoads
if (!any $JSONLoads) do={ global JSONLoads do={
    global JSONIn $1
    global fJParse
    local ret [$fJParse]
    set JSONIn
    global Jpos; set Jpos
    global Jdebug; if (!$Jdebug) do={set Jdebug}
    return $ret
}}

# ------------------- Load JSON from file --------------------------------
global JSONLoad
if (!any $JSONLoad) do={ global JSONLoad do={
    if ([len [/file find name=$1]] > 0) do={
        global JSONLoads
        return [$JSONLoads [/file get $1 contents]]
    }
}}

# ------------------- Unload JSON parser library ----------------------
global JSONUnload
if (!any $JSONUnload) do={ global JSONUnload do={
    global JSONIn; set JSONIn
    global Jpos; set Jpos
    global Jdebug; set Jdebug
    global fByteToEscapeChar; set fByteToEscapeChar
    global fJParse; set fJParse
    global fJParseArray; set fJParseArray
    global fJParseNumber; set fJParseNumber
    global fJParseObject; set fJParseObject
    global fJParsePrint; set fJParsePrint
    global fJParsePrintVar; set fJParsePrintVar
    global fJParseString; set fJParseString
    global fJSkipWhitespace; set fJSkipWhitespace
    global fUnicodeToUTF8; set fUnicodeToUTF8
    global JSONLoads; set JSONLoads
    global JSONLoad; set JSONLoad
    global JSONUnload; set JSONUnload
}}
# ------------------- End JParseFunctions----------------------

这样ddns和动态ip脚本就会随着每一次重新pppoe拨号重新运行

0

评论区