├── CloudflareST ├── LICENSE ├── README.md ├── main.py ├── menu.py └── update.py /CloudflareST: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ymyuuu/OpenWrt-DDNS/a1def694516af4934f1cdeda94c387ceb0bb0ff1/CloudflareST -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Mingyu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenWrt DDNS 安装指南 2 | 3 | 本指南将介绍如何在 OpenWrt 上安装和配置优选反代IP或自定义测速 IP 的 DDNS(动态域名解析)服务。 4 | 5 | image 6 | 7 | ## 交流群和通知频道 8 | 9 | - 群聊: [HeroCore](https://t.me/HeroCore) 10 | - 频道: [HeroMsg](https://t.me/HeroMsg) 11 | 12 | ## 依赖 13 | 14 | 在开始安装之前,请确保已安装以下依赖: 15 | 16 | ```shell 17 | opkg update && 18 | opkg install wget unzip python3 python3-pip && 19 | pip3 install requests 20 | 21 | ``` 22 | 23 | ## 安装步骤 24 | 25 | 执行以下命令以安装 OpenWrt DDNS: 26 | 27 | ```shell 28 | mkdir -p /OpenWrt-DDNS && 29 | rm -rf /OpenWrt-DDNS/* && 30 | wget -O /OpenWrt-DDNS/OpenWrt-DDNS.zip https://github.com/ymyuuu/openwrt-ddns/archive/refs/heads/main.zip && 31 | unzip /OpenWrt-DDNS/OpenWrt-DDNS.zip -d /OpenWrt-DDNS && 32 | mv /OpenWrt-DDNS/OpenWrt-DDNS-main/* /OpenWrt-DDNS/ && 33 | rm -rf /OpenWrt-DDNS/OpenWrt-DDNS-main && 34 | rm /OpenWrt-DDNS/OpenWrt-DDNS.zip && 35 | rm /OpenWrt-DDNS/README.md && 36 | rm /OpenWrt-DDNS/LICENSE && 37 | cd /OpenWrt-DDNS && 38 | python3 update.py && 39 | python3 menu.py 40 | 41 | ``` 42 | 43 | 上述命令将执行以下操作: 44 | 45 | 1. 创建 `/OpenWrt-DDNS` 目录(如果不存在)。 46 | 2. 清空 `/OpenWrt-DDNS` 目录下的所有内容。 47 | 3. 使用 `wget` 下载 OpenWrt DDNS 源代码压缩包,并将其保存为 `/OpenWrt-DDNS/openwrt-ddns.zip`。 48 | 4. 使用 `unzip` 解压缩源代码压缩包到 `/OpenWrt-DDNS` 目录。 49 | 5. 将解压缩后的文件移动到 `/OpenWrt-DDNS` 目录。 50 | 6. 删除不再需要的文件和目录。 51 | 7. 切换到 `/openwrt-ddns` 目录。 52 | 8. 使用 `python3` 运行 `update.py` 脚本以更新配置。 53 | 9. 使用 `python3` 运行 `menu.py` 脚本以启动菜单界面。 54 | 55 | 请根据实际需求修改配置文件和参数。 56 | 57 | ## 后续操作 58 | 59 | 在安装完成后,如果后续需要运行 OpenWrt DDNS,可以直接执行以下命令: 60 | 61 | ```shell 62 | cd /OpenWrt-DDNS && python3 update.py && python3 main.py 63 | 64 | ``` 65 | 66 | 上述命令将切换到 `/OpenWrt-DDNS` 目录,并依次运行 `update.py` 和 `main.py` 脚本。 67 | 68 | 如果需要定时运行 OpenWrt DDNS,可以将以下内容添加到 OpenWrt 的计划任务中: 69 | 70 | ``` 71 | 0 * * * * cd /OpenWrt-DDNS && python3 update.py && python3 main.py 72 | ``` 73 | 74 | 这将使 OpenWrt 每小时执行一次 `/OpenWrt-DDNS` 目录下的 `update.py` 和 `main.py` 脚本。 75 | 76 | ## 自定义测速 IP 77 | 78 | 如果您需要自定义测速 IP,请按照以下步骤进行操作: 79 | 80 | 1. 打开 `/OpenWrt-DDNS` 目录。 81 | 2. 找到名为 `ip.txt` 的文件。 82 | 3. 使用文本编辑器打开 `ip.txt` 文件。 83 | 4. 在文件中输入您想要使用的测速 IP 地址。 84 | 5. 保存并关闭 `ip.txt` 文件。 85 | 86 | **请确保您输入的测速 IP 地址格式正确,并且每个 IP 地址占据一行。** 87 | 88 | **在编辑自定义测速 IP 列表完成后,您必须执行以下命令来运行自定义测速 IP 列表的 OpenWrt DDNS:** 89 | 90 | ```shell 91 | cd /OpenWrt-DDNS && python3 main.py 92 | 93 | ``` 94 | 95 | 上述命令将切换到 `/OpenWrt-DDNS` 目录,并运行 `main.py` 脚本。 96 | 97 | OpenWrt DDNS 将使用您在 `ip.txt` 文件中指定的测速 IP 地址来进行测速和更新。 98 | 99 | ## 免责声明 100 | 101 | **在使用本指南提供的信息和指令之前,请您务必仔细阅读并理解以下免责声明:** 102 | 103 | 1. OpenWrt DDNS 是一个第三方开发的项目,作者不对该项目的功能、安全性或可靠性提供任何担保或保证。使用 OpenWrt DDNS 时请自行承担风险。 104 | 2. 在安装和配置 OpenWrt DDNS 之前,请确保您已备份重要的系统和数据。OpenWrt DDNS 的安装和配置可能会对您的设备和网络环境产生影响,包括但不限于数据丢失、网络中断等问题。 105 | 3. OpenWrt DDNS 的使用可能涉及到您的网络设置和域名解析服务商的配置。请确保您已获得相关的授权和权限,并按照服务提供商的规定使用该服务。 106 | 4. OpenWrt DDNS 的安装和配置可能需要您对系统进行修改和调整。请确保您具备相应的技术知识和经验,并在操作之前充分了解相关的指令和操作风险。 107 | 5. OpenWrt DDNS 不对因使用本指南提供的信息和指令而导致的任何直接或间接损失或损害承担任何责任。 108 | 6. 本指南仅针对非中国大陆地区用户提供。中国大陆地区用户不得使用本指南提供的信息和指令。 109 | 110 | **请在使用 OpenWrt DDNS 之前仔细考虑,并自行评估风险和可行性。如果您对安装和配置有任何疑问或担忧,请咨询专业人士或寻求技术支持。** 111 | 112 | ## 许可证 113 | 114 | 本项目采用 MIT 许可证。详细信息请参阅 [LICENSE](LICENSE) 文件。 115 | 116 | 感谢你的使用!如果你对这个项目有任何改进或建议,也欢迎贡献代码或提出问题。 117 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import subprocess 4 | import csv 5 | import requests 6 | 7 | # 获取当前脚本的目录 8 | script_directory = os.path.dirname(os.path.realpath(__file__)) 9 | os.chdir(script_directory) 10 | 11 | # 配置文件路径 12 | config_file = os.path.join(script_directory, "speed-test.json") 13 | 14 | # 结果文件路径 15 | result_file = os.path.join(script_directory, "result.csv") 16 | ip_result_file = 'push-ip.txt' 17 | 18 | # 关闭代理工具,不输出结果和报错 19 | def stop_proxies(): 20 | commands = [ 21 | "/etc/init.d/passwall stop", 22 | "/etc/init.d/passwall2 stop", 23 | "/etc/init.d/ssr-plus stop", 24 | "/etc/init.d/openclash stop", 25 | "/etc/init.d/bypass stop", 26 | "/etc/init.d/helloworld stop" 27 | # Add more stop commands for other proxies if needed 28 | ] 29 | for command in commands: 30 | subprocess.run(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 31 | 32 | # 启动代理工具,不输出结果和报错 33 | def start_proxies(): 34 | commands = [ 35 | "/etc/init.d/passwall start", 36 | "/etc/init.d/passwall2 start", 37 | "/etc/init.d/ssr-plus start", 38 | "/etc/init.d/openclash start", 39 | "/etc/init.d/bypass start", 40 | "/etc/init.d/helloworld start" 41 | # Add more start commands for other proxies if needed 42 | ] 43 | for command in commands: 44 | subprocess.run(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 45 | 46 | def run_command_from_config(): 47 | # 先关闭代理工具 48 | stop_proxies() 49 | print(f"已自动关闭代理工具(如果存在)\n") 50 | 51 | if os.path.exists(config_file): 52 | with open(config_file, "r") as config: 53 | config_data = json.load(config) 54 | command = config_data["command"] 55 | # 直接执行命令 56 | try: 57 | subprocess.call(command, shell=True) 58 | except Exception as e: 59 | print(f"运行命令时发生错误: {str(e)}") 60 | return 61 | 62 | extract_top_ips() 63 | else: 64 | print("未找到配置文件,请先配置参数。") 65 | 66 | def extract_top_ips(): 67 | if os.path.exists(result_file): 68 | with open(result_file, "r") as csv_file: 69 | csv_reader = csv.reader(csv_file) 70 | ips = [] 71 | # 读取前十行的 IP 地址 72 | for i, row in enumerate(csv_reader): 73 | if i == 0: 74 | continue # Skip header row 75 | ips.append(row[0]) 76 | if i == 10: 77 | break 78 | 79 | # 保存前十个 IP 地址到文件 80 | with open(ip_result_file, "w") as top_ips_file: 81 | top_ips_file.write("\n".join(ips)) 82 | 83 | print("\n需要推送的 IP 已保存到push-ip.txt。") 84 | else: 85 | print("未找到 result.csv 文件,请确保命令执行成功并生成该文件.") 86 | 87 | def configure_dns_records(): 88 | # 从 'cf-dns.json' 获取DNS配置 89 | dns_config_file = 'cf-dns.json' 90 | if os.path.exists(dns_config_file): 91 | with open(dns_config_file, 'r') as file: 92 | dns_config = json.load(file) 93 | 94 | api_token = dns_config["api_token"] 95 | zone_id = dns_config["zone_id"] 96 | record_name = dns_config["record_name"] 97 | 98 | # 从 'push-ip.txt' 获取IP地址列表 99 | ip_addresses = [] 100 | with open(ip_result_file, 'r') as file: 101 | for line in file: 102 | ip_addresses.append(line.strip()) 103 | 104 | # 构建API请求头 105 | headers = { 106 | "Authorization": f"Bearer {api_token}", 107 | "Content-Type": "application/json" 108 | } 109 | 110 | # DNS记录的基本URL 111 | base_url = f"https://proxy.api.030101.xyz/https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" 112 | 113 | # 删除所有'A'记录 114 | print("\n正在删除所有 DNS 'A'记录") 115 | response = requests.get(base_url, headers=headers) 116 | if response.status_code == 200: 117 | data = response.json() 118 | for record in data["result"]: 119 | record_type = record["type"] 120 | if record_type == "A": # 仅删除'A'记录 121 | delete_url = f"{base_url}/{record['id']}" 122 | response = requests.delete(delete_url, headers=headers) 123 | if response.status_code != 200: 124 | print(f"删除'A'记录时出错,HTTP响应代码:{response.status_code}") 125 | return 126 | print("已删除所有DNS 'A'记录") 127 | else: 128 | print(f"无法获取DNS记录信息。响应代码: {response.status_code}") 129 | return 130 | 131 | # 创建新的'A'记录 132 | for ip in ip_addresses: 133 | dns_record = { 134 | "type": "A", 135 | "name": record_name, 136 | "content": ip, 137 | "ttl": 600, 138 | "proxied": False 139 | } 140 | 141 | # 发送POST请求创建DNS记录 142 | response = requests.post(base_url, headers=headers, json=dns_record) 143 | 144 | if response.status_code == 200: 145 | print(f"成功创建 (IPv4) DNS记录,IP地址: {ip}") 146 | else: 147 | print("创建DNS记录时出错") 148 | print(f"创建DNS记录时出错,HTTP响应代码:{response.status_code}") 149 | return 150 | else: 151 | print("未配置DNS参数 cf-dns.json 。") 152 | 153 | if __name__ == "__main__": 154 | run_command_from_config() 155 | configure_dns_records() 156 | start_proxies() # 最后重新启动代理工具 157 | print(f"\n已自动开启代理工具(如果存在)") 158 | -------------------------------------------------------------------------------- /menu.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import subprocess 4 | 5 | # 获取当前脚本的目录 6 | script_directory = os.path.dirname(os.path.realpath(__file__)) 7 | os.chdir(script_directory) 8 | 9 | # 配置文件路径 10 | config_file = os.path.join(script_directory, "speed-test.json") 11 | dns_file = os.path.join(script_directory, "cf-dns.json") 12 | 13 | def configure_parameters(): 14 | # 询问其他参数 15 | n = input("先配置点参数,你别急行不行,嗯?\n\n延迟测速线程 (-n, 默认 200): ") or "200" 16 | t = input("延迟测速次数 (-t, 默认 4): ") or "4" 17 | tp = input("测速端口 (-tp, 默认 80): ") or "80" 18 | tl = input("平均延迟上限 (-tl, 默认 200 ms): ") or "200" 19 | tll = input("平均延迟下限 (-tll, 默认 0 ms): ") or "0" 20 | tlr = input("丢包几率上限 (-tlr, 默认 1.00): ") or "1.00" 21 | p = input("显示结果数量 (-p, 默认10个): ") or "10" 22 | 23 | # 根据测速端口自动设置默认测速地址 24 | if tp in ["80", "8080", "8880", "2052", "2086", "2095"]: 25 | url = "http://speed.bestip.one/__down?bytes=50000000" 26 | elif tp in ["443", "8443", "2053", "2096", "2087", "2083"]: 27 | url = "https://speed.bestip.one/__down?bytes=50000000" 28 | else: 29 | url = input("测速地址 (-url, 默认 http://spurl.api.030101.xyz/100mb): ") or "https://spurl.api.030101.xyz/100mb" 30 | 31 | # 根据是否启用下载测速询问 32 | download_enabled = input("\n是否启用下载测速 (-dd, 默认回车启用, 输入任何字符禁用): ").strip().lower() 33 | if download_enabled: 34 | download_option = '-dd' 35 | dn = dt = sl = "0" 36 | else: 37 | download_option = '' 38 | dn = input("下载测速数量 (-dn, 默认 10): ") or "10" 39 | dt = input("下载测速时间 (-dt, 默认 3秒): ") or "3" 40 | sl = input("下载速度下限 (-sl, 默认 10.00 MB/s): ") or "10.00" 41 | 42 | # 生成命令 43 | command = f"./CloudflareST -n {n} -t {t} {download_option} -dn {dn} -dt {dt} -tp {tp} -url {url} -tl {tl} -tll {tll} -tlr {tlr} -sl {sl} -p {p}" 44 | 45 | # 添加执行权限 46 | subprocess.call(f"chmod +x {script_directory}/CloudflareST", shell=True) 47 | 48 | # 保存参数到配置文件 49 | with open(config_file, "w") as config: 50 | config_data = { 51 | "command": command 52 | } 53 | json.dump(config_data, config) 54 | 55 | # 询问用户是否进行DNS推送 56 | dns_push = input("\n是否要进行DNS推送到Cloudflare (回车是,输入任何字符否): ").strip() 57 | if dns_push == "": 58 | # 如果用户选择进行DNS推送 (按回车),继续询问DNS相关信息。 59 | api_token = input("请输入您的 Cloudflare API 令牌: ") 60 | zone_id = input("请输入您的区域ID: ") 61 | record_name = input("请输入DNS记录名称 (默认为 'ip'): ") or "ip" 62 | # 保存DNS信息到文件 63 | with open(dns_file, "w") as dns_config: 64 | dns_data = { 65 | "api_token": api_token, 66 | "zone_id": zone_id, 67 | "record_name": record_name 68 | } 69 | json.dump(dns_data, dns_config) 70 | else: 71 | # 如果用户选择不进行DNS推送(输入任何字符),删除 cf-dns.json 文件(如果存在)。 72 | if os.path.exists(dns_file): 73 | os.remove(dns_file) 74 | 75 | # 运行 main.py 76 | run_main_py() 77 | 78 | def run_main_py(): 79 | print("\n开始了哦,不许调皮哦\n") # 输出开始提示 80 | subprocess.call(f"python3 {script_directory}/main.py", shell=True) 81 | exit(0) 82 | 83 | def main(): 84 | if os.path.exists(config_file): 85 | while True: 86 | print("\n菜单:") 87 | print("1. 重新配置命令参数") 88 | print("2. 执行 main.py") 89 | print("3. 退出") 90 | 91 | choice = input("请选择一个选项: ") 92 | if choice == "1": 93 | configure_parameters() 94 | elif choice == "2": 95 | run_main_py() 96 | elif choice == "3": 97 | break 98 | else: 99 | print("请选择一个有效的选项。") 100 | else: 101 | configure_parameters() 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /update.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from datetime import datetime 4 | 5 | # 获取脚本所在的目录 6 | script_dir = os.path.dirname(os.path.abspath(__file__)) 7 | 8 | # 定义下载URL和文件名 9 | download_url = "https://ipdb.api.030101.xyz/?type=proxy" 10 | ip_txt_file_name = os.path.join(script_dir, "ip.txt") 11 | 12 | # 判断是否是第一次运行 13 | is_first_run = not os.path.exists(ip_txt_file_name) 14 | 15 | # 记录脚本运行的时间 16 | start_time = datetime.now() 17 | 18 | # 输出开始时间 19 | start_time_str = start_time.strftime('%Y-%m-%d %H:%M') 20 | print(f"\n{start_time_str} 正在下载更新反代IP库\n") 21 | 22 | # 下载ip.txt文件,并跳过前三行 23 | try: 24 | response = requests.get(download_url) 25 | response.raise_for_status() # 检查是否有HTTP错误 26 | with open(ip_txt_file_name, "wb") as txt_file: 27 | lines = response.iter_lines() 28 | next(lines) # 跳过第一行 29 | next(lines) # 跳过第二行 30 | next(lines) # 跳过第三行 31 | for line in lines: 32 | txt_file.write(line + b'\n') 33 | except Exception as e: 34 | print(f"下载ip.txt文件时出现错误: {str(e)}") 35 | response = None 36 | 37 | # 读取新的IP记录 38 | new_ip_list = [] 39 | if response: 40 | try: 41 | with open(ip_txt_file_name, "r") as new_ip_file: 42 | for line in new_ip_file: 43 | line = line.strip() 44 | if line: 45 | new_ip_list.append(line) 46 | except Exception as e: 47 | print(f"读取新的IP记录时出现错误: {str(e)}") 48 | 49 | # 输出更新信息 50 | end_time = datetime.now() 51 | start_time_str = start_time.strftime('%Y-%m-%d %H:%M') 52 | if response: 53 | count = len(new_ip_list) 54 | if not is_first_run: 55 | print(f"已更新IP库,共有 {count} 个IP\n") 56 | else: 57 | print(f"首次运行,已下载最新IP库,共有 {count} 个IP\n") 58 | else: 59 | print("由于下载ip.txt文件时出现错误,无法进行IP库更新。\n") 60 | --------------------------------------------------------------------------------