mirror of
https://github.com/jeessy2/ddns-go.git
synced 2024-11-25 16:46:24 +08:00
feat: support english (#967)
* feat: init the i18n * fix: porkbun * refactor: http_util GetHTTPResponse * fix: save * fix: add more i18n * feat: i18n at writing.html * feat: README EN * fix: default api * fix: pic
This commit is contained in:
parent
8b508c6f0a
commit
eec98404fe
22
README.md
22
README.md
@ -2,6 +2,8 @@
|
||||
|
||||
[![GitHub release](https://img.shields.io/github/release/jeessy2/ddns-go.svg?logo=github&style=flat-square) ![GitHub release downloads](https://img.shields.io/github/downloads/jeessy2/ddns-go/total?logo=github)](https://github.com/jeessy2/ddns-go/releases/latest) [![Go version](https://img.shields.io/github/go-mod/go-version/jeessy2/ddns-go)](https://github.com/jeessy2/ddns-go/blob/master/go.mod) [![](https://goreportcard.com/badge/github.com/jeessy2/ddns-go/v5)](https://goreportcard.com/report/github.com/jeessy2/ddns-go/v5) [![](https://img.shields.io/docker/image-size/jeessy/ddns-go)](https://registry.hub.docker.com/r/jeessy/ddns-go) [![](https://img.shields.io/docker/pulls/jeessy/ddns-go)](https://registry.hub.docker.com/r/jeessy/ddns-go)
|
||||
|
||||
中文 | [English](https://github.com/jeessy2/ddns-go/blob/master/README_EN.md)
|
||||
|
||||
自动获得你的公网 IPv4 或 IPv6 地址,并解析到对应的域名服务。
|
||||
|
||||
- [特性](#特性)
|
||||
@ -16,7 +18,7 @@
|
||||
## 特性
|
||||
|
||||
- 支持Mac、Windows、Linux系统,支持ARM、x86架构
|
||||
- 支持的域名服务商 `Alidns(阿里云)` `Dnspod(腾讯云)` `Cloudflare` `华为云` `Callback` `百度云` `Porkbun` `GoDaddy` `Google Domain`
|
||||
- 支持的域名服务商 `阿里云` `腾讯云` `Dnspod` `Cloudflare` `华为云` `Callback` `百度云` `Porkbun` `GoDaddy` `Google Domain`
|
||||
- 支持接口/网卡/[命令](https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考)获取IP
|
||||
- 支持以服务的方式运行
|
||||
- 默认间隔5分钟同步一次
|
||||
@ -35,20 +37,18 @@
|
||||
## 系统中使用
|
||||
|
||||
- 从 [Releases](https://github.com/jeessy2/ddns-go/releases) 下载并解压 ddns-go
|
||||
- [可选] 使用 [Homebrew](https://brew.sh) 安装 [ddns-go](https://formulae.brew.sh/formula/ddns-go):
|
||||
|
||||
```bash
|
||||
brew install ddns-go
|
||||
```
|
||||
|
||||
- 双击运行, 如没有找到配置, 程序将自动打开 http://127.0.0.1:9876
|
||||
- [可选] 安装服务
|
||||
- 安装服务
|
||||
- Mac/Linux: `sudo ./ddns-go -s install`
|
||||
- Win(以管理员打开cmd): `.\ddns-go.exe -s install`
|
||||
- [可选] 服务卸载
|
||||
- Mac/Linux: `sudo ./ddns-go -s uninstall`
|
||||
- Win(以管理员打开cmd): `.\ddns-go.exe -s uninstall`
|
||||
- [可选] 支持安装或启动时带参数 `-l`监听地址 `-f`同步间隔时间(秒) `-cacheTimes`间隔N次与服务商比对 `-c`自定义配置文件路径 `-noweb`不启动web服务 `-skipVerify`跳过证书验证 `-dns` 自定义 DNS 服务器。如:`./ddns-go -s install -l :9877 -f 600 -c /Users/name/ddns-go.yaml`
|
||||
- [可选] 支持安装带参数 `-l`监听地址 `-f`同步间隔时间(秒) `-cacheTimes`间隔N次与服务商比对 `-c`自定义配置文件路径 `-noweb`不启动web服务 `-skipVerify`跳过证书验证 `-dns` 自定义 DNS 服务器。如:`./ddns-go -s install -l :9876 -f 600 -c /Users/name/ddns-go.yaml`
|
||||
- [可选] 使用 [Homebrew](https://brew.sh) 安装 [ddns-go](https://formulae.brew.sh/formula/ddns-go):
|
||||
|
||||
```bash
|
||||
brew install ddns-go
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> 通过合理的配置 `-f` 和 `-cacheTimes` 可以实现 IP 变化即时触发更新且不会被 DDNS 服务商限流, 例如 `-f 10 -cacheTimes 360` 效果为每 10 秒检查一次本地 IP 变化, 每小时去公网对比一下 IP 变化
|
||||
@ -61,7 +61,7 @@
|
||||
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go
|
||||
```
|
||||
|
||||
- 在浏览器中打开`http://主机IP:9876`,修改你的配置,成功
|
||||
- 在浏览器中打开`http://主机IP:9876`,并修改你的配置
|
||||
|
||||
- [可选] 使用 `ghcr.io` 镜像
|
||||
|
||||
|
140
README_EN.md
Normal file
140
README_EN.md
Normal file
@ -0,0 +1,140 @@
|
||||
# ddns-go
|
||||
|
||||
[![GitHub release](https://img.shields.io/github/release/jeessy2/ddns-go.svg?logo=github&style=flat-square) ![GitHub release downloads](https://img.shields.io/github/downloads/jeessy2/ddns-go/total?logo=github)](https://github.com/jeessy2/ddns-go/releases/latest) [![Go version](https://img.shields.io/github/go-mod/go-version/jeessy2/ddns-go)](https://github.com/jeessy2/ddns-go/blob/master/go.mod) [![](https://goreportcard.com/badge/github.com/jeessy2/ddns-go/v5)](https://goreportcard.com/report/github.com/jeessy2/ddns-go/v5) [![](https://img.shields.io/docker/image-size/jeessy/ddns-go)](https://registry.hub.docker.com/r/jeessy/ddns-go) [![](https://img.shields.io/docker/pulls/jeessy/ddns-go)](https://registry.hub.docker.com/r/jeessy/ddns-go)
|
||||
|
||||
[中文](https://github.com/jeessy2/ddns-go/blob/master/README.md) | English
|
||||
|
||||
Automatically obtain your public IPv4 or IPv6 address and resolve it to the corresponding domain name service.
|
||||
|
||||
- [Features](#Features)
|
||||
- [Use in system](#Use-in-system)
|
||||
- [Use in docker](#Use-in-docker)
|
||||
- [Webhook](#webhook)
|
||||
- [Callback](#callback)
|
||||
- [Web interfaces](#Web-interfaces)
|
||||
|
||||
## Features
|
||||
|
||||
- Support Mac, Windows, Linux system, support ARM, x86 architecture
|
||||
- Support domain service providers `Aliyun` `Tencent` `Dnspod` `Cloudflare` `Huawei` `Callback` `Baidu` `Porkbun` `GoDaddy` `Google Domain` `Namecheap` `NameSilo`
|
||||
- Support interface / netcard / command to get IP
|
||||
- Support running as a service
|
||||
- Default interval is 5 minutes
|
||||
- Support configuring multiple DNS service providers at the same time
|
||||
- Support multiple domain name resolution at the same time
|
||||
- Support multi-level domain name
|
||||
- Configured on the web page, simple and convenient
|
||||
- In the web page, you can quickly view the latest 50 logs
|
||||
- Support Webhook notification
|
||||
- Support TTL
|
||||
|
||||
> [!NOTE]
|
||||
> If you enable public network access, it is recommended to use Nginx and other reverse proxy software to enable HTTPS access to ensure security.
|
||||
|
||||
## Use in system
|
||||
|
||||
- Download and unzip ddns-go from [Releases](https://github.com/jeessy2/ddns-go/releases)
|
||||
- Run in service mode
|
||||
- Mac/Linux: `sudo ./ddns-go -s install`
|
||||
- Win(Run as administrator): `.\ddns-go.exe -s install`
|
||||
- [Optional] Uninstall service
|
||||
- Mac/Linux: `sudo ./ddns-go -s uninstall`
|
||||
- Win(Run as administrator): `.\ddns-go.exe -s uninstall`
|
||||
- [Optional] Support installation with parameters `-l` listen address `-f` Sync frequency(seconds) `-cacheTimes` interval N times compared with service providers `-c` custom configuration file path `-noweb` does not start web service `-skipVerify` skip certificate verification `-dns` custom DNS server. example:`./ddns-go -s install -l :9876 -f 600 -c /Users/name/ddns-go.yaml`
|
||||
- [Optional] You can use [Homebrew](https://brew.sh) to install [ddns-go](https://formulae.brew.sh/formula/ddns-go)
|
||||
|
||||
```bash
|
||||
brew install ddns-go
|
||||
```
|
||||
|
||||
## Use in docker
|
||||
|
||||
- Mount the host directory, use the docker host mode. You can replace `/opt/ddns-go` with any directory on your host, the configuration file is a hidden file
|
||||
|
||||
```bash
|
||||
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go
|
||||
```
|
||||
|
||||
- Open `http://DOCKER_IP:9876` in the browser, modify your configuration
|
||||
|
||||
- [Optional] Use `ghcr.io` mirror
|
||||
|
||||
```bash
|
||||
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root ghcr.io/jeessy2/ddns-go
|
||||
```
|
||||
|
||||
- [Optional] Support startup with parameters `-l`listen address `-f`Sync frequency(seconds)
|
||||
|
||||
```bash
|
||||
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go -l :9877 -f 600
|
||||
```
|
||||
|
||||
- [Optional] Without using docker host mode
|
||||
|
||||
```bash
|
||||
docker run -d --name ddns-go --restart=always -p 9876:9876 -v /opt/ddns-go:/root jeessy/ddns-go
|
||||
```
|
||||
|
||||
## Webhook
|
||||
|
||||
- Support webhook, when the domain name is updated successfully or not, the URL filled in will be called back
|
||||
- Support variables
|
||||
|
||||
| Variable name | Comments |
|
||||
| ---- | ---- |
|
||||
| #{ipv4Addr} | The new IPv4 |
|
||||
| #{ipv4Result} | IPv4 update result: `no changed` `success` `failed`|
|
||||
| #{ipv4Domains} | IPv4 domains,Split by `,` |
|
||||
| #{ipv6Addr} | The new IPv6 |
|
||||
| #{ipv6Result} | IPv6 update result: `no changed` `success` `failed`|
|
||||
| #{ipv6Domains} | IPv6 domains,Split by `,` |
|
||||
|
||||
- If RequestBody is empty, it is a `GET` request, otherwise it is a `POST` request
|
||||
|
||||
- <details><summary>Telegram</summary>
|
||||
|
||||
[ddns-telegram-bot](https://github.com/WingLim/ddns-telegram-bot)
|
||||
</details>
|
||||
- <details><summary>Discord</summary>
|
||||
|
||||
- Discord client -> Server -> Channel Settings -> Integration -> View Webhook -> New Webhook -> Copy Webhook URL
|
||||
- Input the `Webhook URL` copied from Discord in the URL
|
||||
- Input in RequestBody
|
||||
```json
|
||||
{
|
||||
"content": "The domain name #{ipv4Domains} dynamically resolves to #{ipv4Result}.",
|
||||
"embeds": [
|
||||
{
|
||||
"description": "Domains: #{ipv4Domains}, Result: #{ipv4Result}, IP: #{ipv4Addr}",
|
||||
"color": 15258703,
|
||||
"author": {
|
||||
"name": "DDNS"
|
||||
},
|
||||
"footer": {
|
||||
"text": "DDNS #{ipv4Result}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
- [More webhook configuration reference](https://github.com/jeessy2/ddns-go/issues/327)
|
||||
|
||||
## Callback
|
||||
|
||||
- Support more third-party DNS service providers through custom callback
|
||||
- Callback will be called as many times as there are lines in the configured domain name
|
||||
- Support variables
|
||||
|
||||
| Variable name | Comments |
|
||||
| ---- | ---- |
|
||||
| #{ip} | The new IPv4/IPv6 address|
|
||||
| #{domain} | Current domain |
|
||||
| #{recordType} | Record type `A` or `AAAA` |
|
||||
| #{ttl} | TTL |
|
||||
- If RequestBody is empty, it is a `GET` request, otherwise it is a `POST` request
|
||||
|
||||
## Web interfaces
|
||||
|
||||
![screenshots](https://raw.githubusercontent.com/jeessy2/ddns-go/master/ddns-web.png)
|
@ -60,6 +60,8 @@ type Config struct {
|
||||
Webhook
|
||||
// 禁止公网访问
|
||||
NotAllowWanAccess bool
|
||||
// 语言
|
||||
Lang string
|
||||
}
|
||||
|
||||
// ConfigCache ConfigCache
|
||||
@ -92,14 +94,14 @@ func GetConfigCached() (conf Config, err error) {
|
||||
|
||||
byt, err := os.ReadFile(configFilePath)
|
||||
if err != nil {
|
||||
log.Println(configFilePath + " 读取失败")
|
||||
util.Log("异常信息: %s", err)
|
||||
cache.Err = err
|
||||
return *cache.ConfigSingle, err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(byt, cache.ConfigSingle)
|
||||
if err != nil {
|
||||
log.Println("反序列化配置文件失败", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
cache.Err = err
|
||||
return *cache.ConfigSingle, err
|
||||
}
|
||||
@ -109,6 +111,9 @@ func GetConfigCached() (conf Config, err error) {
|
||||
cache.ConfigSingle.NotAllowWanAccess = true
|
||||
}
|
||||
|
||||
// 初始化语言
|
||||
util.InitLogLang(cache.ConfigSingle.Lang)
|
||||
|
||||
// remove err
|
||||
cache.Err = nil
|
||||
return *cache.ConfigSingle, err
|
||||
@ -161,7 +166,7 @@ func (conf *Config) SaveConfig() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("配置文件已保存在: %s\n", configFilePath)
|
||||
util.Log("配置文件已保存在: %s", configFilePath)
|
||||
|
||||
// 清空配置缓存
|
||||
cache.ConfigSingle = nil
|
||||
@ -172,7 +177,7 @@ func (conf *Config) SaveConfig() (err error) {
|
||||
func (conf *DnsConfig) getIpv4AddrFromInterface() string {
|
||||
ipv4, _, err := GetNetInterface()
|
||||
if err != nil {
|
||||
log.Println("从网卡获得IPv4失败!")
|
||||
util.Log("从网卡获得IPv4失败")
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -182,7 +187,7 @@ func (conf *DnsConfig) getIpv4AddrFromInterface() string {
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("从网卡中获得IPv4失败! 网卡名: ", conf.Ipv4.NetInterface)
|
||||
util.Log("从网卡中获得IPv4失败! 网卡名: %s", conf.Ipv4.NetInterface)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -193,20 +198,20 @@ func (conf *DnsConfig) getIpv4AddrFromUrl() string {
|
||||
url = strings.TrimSpace(url)
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("连接失败! <a target='blank' href='%s'>点击查看接口能否返回IPv4地址</a>\n", url)
|
||||
log.Printf("错误信息: %s\n", err)
|
||||
util.Log("通过接口获取IPv4失败! 接口地址: %s", url)
|
||||
util.Log("异常信息: %s", err)
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
lr := io.LimitReader(resp.Body, 1024000)
|
||||
body, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
log.Println("读取IPv4结果失败! 接口: ", url)
|
||||
util.Log("异常信息: %s", err)
|
||||
continue
|
||||
}
|
||||
result := Ipv4Reg.FindString(string(body))
|
||||
if result == "" {
|
||||
log.Printf("获取IPv4结果失败! 接口: %s ,返回值: %s\n", url, result)
|
||||
util.Log("获取IPv4结果失败! 接口: %s ,返回值: %s", url, string(body))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -243,14 +248,14 @@ func (conf *DnsConfig) getAddrFromCmd(addrType string) string {
|
||||
// run cmd
|
||||
out, err := execCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("获取%s结果失败! 未能成功执行命令:%s,错误:%q,退出状态码:%s\n", addrType, execCmd.String(), out, err)
|
||||
util.Log("获取%s结果失败! 未能成功执行命令:%s, 错误:%q, 退出状态码:%s", addrType, execCmd.String(), out, err)
|
||||
return ""
|
||||
}
|
||||
str := string(out)
|
||||
// get result
|
||||
result := comp.FindString(str)
|
||||
if result == "" {
|
||||
log.Printf("获取%s结果失败! 命令:%s,标准输出:%q\n", addrType, execCmd.String(), str)
|
||||
util.Log("获取%s结果失败! 命令: %s, 标准输出: %q", addrType, execCmd.String(), str)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -269,7 +274,7 @@ func (conf *DnsConfig) GetIpv4Addr() string {
|
||||
// 从命令行获取 IP
|
||||
return conf.getAddrFromCmd("IPv4")
|
||||
default:
|
||||
log.Println("IPv4 的 获取 IP 方式 未知!")
|
||||
log.Println("IPv4's get IP method is unknown")
|
||||
return "" // unknown type
|
||||
}
|
||||
}
|
||||
@ -277,7 +282,7 @@ func (conf *DnsConfig) GetIpv4Addr() string {
|
||||
func (conf *DnsConfig) getIpv6AddrFromInterface() string {
|
||||
_, ipv6, err := GetNetInterface()
|
||||
if err != nil {
|
||||
log.Println("从网卡获得IPv6失败!")
|
||||
util.Log("从网卡获得IPv6失败")
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -289,34 +294,32 @@ func (conf *DnsConfig) getIpv6AddrFromInterface() string {
|
||||
num, err := strconv.Atoi(conf.Ipv6.IPv6Reg[1:])
|
||||
if err == nil {
|
||||
if num > 0 {
|
||||
log.Printf("IPv6将使用第 %d 个IPv6地址\n", num)
|
||||
if num <= len(netInterface.Address) {
|
||||
return netInterface.Address[num-1]
|
||||
}
|
||||
log.Printf("未找到第 %d 个IPv6地址! 将使用第一个IPv6地址\n", num)
|
||||
util.Log("未找到第 %d 个IPv6地址! 将使用第一个IPv6地址", num)
|
||||
return netInterface.Address[0]
|
||||
}
|
||||
log.Printf("IPv6匹配表达式 %s 不正确! 最小从1开始\n", conf.Ipv6.IPv6Reg)
|
||||
util.Log("IPv6匹配表达式 %s 不正确! 最小从1开始", conf.Ipv6.IPv6Reg)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
// 正则表达式匹配
|
||||
log.Printf("IPv6将使用正则表达式 %s 进行匹配\n", conf.Ipv6.IPv6Reg)
|
||||
util.Log("IPv6将使用正则表达式 %s 进行匹配", conf.Ipv6.IPv6Reg)
|
||||
for i := 0; i < len(netInterface.Address); i++ {
|
||||
matched, err := regexp.MatchString(conf.Ipv6.IPv6Reg, netInterface.Address[i])
|
||||
if matched && err == nil {
|
||||
log.Println("匹配成功! 匹配到地址: ", netInterface.Address[i])
|
||||
util.Log("匹配成功! 匹配到地址: ", netInterface.Address[i])
|
||||
return netInterface.Address[i]
|
||||
}
|
||||
log.Printf("第 %d 个地址 %s 不匹配, 将匹配下一个地址\n", i+1, netInterface.Address[i])
|
||||
}
|
||||
log.Println("没有匹配到任何一个IPv6地址, 将使用第一个地址")
|
||||
util.Log("没有匹配到任何一个IPv6地址, 将使用第一个地址")
|
||||
}
|
||||
return netInterface.Address[0]
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("从网卡中获得IPv6失败! 网卡名: ", conf.Ipv6.NetInterface)
|
||||
util.Log("从网卡中获得IPv6失败! 网卡名: %s", conf.Ipv6.NetInterface)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -327,8 +330,8 @@ func (conf *DnsConfig) getIpv6AddrFromUrl() string {
|
||||
url = strings.TrimSpace(url)
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("连接失败! <a target='blank' href='%s'>点击查看接口能否返回IPv6地址</a>, 参考说明:<a target='blank' href='%s'>点击访问</a>\n", url, "https://github.com/jeessy2/ddns-go#使用ipv6")
|
||||
log.Printf("错误信息: %s\n", err)
|
||||
util.Log("通过接口获取IPv6失败! 接口地址: %s", url)
|
||||
util.Log("异常信息: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -336,12 +339,12 @@ func (conf *DnsConfig) getIpv6AddrFromUrl() string {
|
||||
lr := io.LimitReader(resp.Body, 1024000)
|
||||
body, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
log.Println("读取IPv6结果失败! 接口: ", url)
|
||||
util.Log("异常信息: %s", err)
|
||||
continue
|
||||
}
|
||||
result := Ipv6Reg.FindString(string(body))
|
||||
if result == "" {
|
||||
log.Printf("获取IPv6结果失败! 接口: %s ,返回值: %s\n", url, result)
|
||||
util.Log("获取IPv6结果失败! 接口: %s ,返回值: %s", url, result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -362,7 +365,7 @@ func (conf *DnsConfig) GetIpv6Addr() (result string) {
|
||||
// 从命令行获取 IP
|
||||
return conf.getAddrFromCmd("IPv6")
|
||||
default:
|
||||
log.Println("IPv6 的 获取 IP 方式 未知!")
|
||||
log.Println("IPv6's get IP method is unknown")
|
||||
return "" // unknown type
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
@ -81,7 +80,7 @@ func (domains *Domains) GetNewIp(dnsConf *DnsConfig) {
|
||||
if domains.Ipv4Cache.TimesFailedIP == 3 {
|
||||
domains.Ipv4Domains[0].UpdateStatus = UpdatedFailed
|
||||
}
|
||||
log.Println("未能获取IPv4地址, 将不会更新")
|
||||
util.Log("未能获取IPv4地址, 将不会更新")
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +96,7 @@ func (domains *Domains) GetNewIp(dnsConf *DnsConfig) {
|
||||
if domains.Ipv6Cache.TimesFailedIP == 3 {
|
||||
domains.Ipv6Domains[0].UpdateStatus = UpdatedFailed
|
||||
}
|
||||
log.Println("未能获取IPv6地址, 将不会更新")
|
||||
util.Log("未能获取IPv6地址, 将不会更新")
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,7 +123,8 @@ func checkParseDomains(domainArr []string) (domains []*Domain) {
|
||||
case 1: // 不使用冒号分割,自动识别域名
|
||||
domainName, err := publicsuffix.EffectiveTLDPlusOne(domainStr)
|
||||
if err != nil {
|
||||
log.Println(domainStr, "域名不正确:", err)
|
||||
util.Log("域名: %s 不正确", domainStr)
|
||||
util.Log("异常信息: %s", err)
|
||||
continue
|
||||
}
|
||||
domain.DomainName = domainName
|
||||
@ -136,21 +136,21 @@ func checkParseDomains(domainArr []string) (domains []*Domain) {
|
||||
case 2: // 使用冒号分隔,为 子域名:根域名 格式
|
||||
sp := strings.Split(dp[1], ".")
|
||||
if len(sp) <= 1 {
|
||||
log.Println(domainStr, "域名不正确")
|
||||
util.Log("域名: %s 不正确", domainStr)
|
||||
continue
|
||||
}
|
||||
domain.DomainName = dp[1]
|
||||
domain.SubDomain = dp[0]
|
||||
default:
|
||||
log.Println(domainStr, "域名不正确")
|
||||
util.Log("域名: %s 不正确", domainStr)
|
||||
continue
|
||||
}
|
||||
|
||||
// 参数条件
|
||||
if len(qp) == 2 {
|
||||
u, err := url.Parse("http://baidu.com?" + qp[1])
|
||||
u, err := url.Parse("https://baidu.com?" + qp[1])
|
||||
if err != nil {
|
||||
log.Println(domainStr, "域名解析失败")
|
||||
util.Log("域名: %s 解析失败", domainStr)
|
||||
continue
|
||||
}
|
||||
domain.CustomParams = u.Query().Encode()
|
||||
@ -166,7 +166,7 @@ func (domains *Domains) GetNewIpResult(recordType string) (ipAddr string, retDom
|
||||
if domains.Ipv6Cache.Check(domains.Ipv6Addr) {
|
||||
return domains.Ipv6Addr, domains.Ipv6Domains
|
||||
} else {
|
||||
log.Printf("IPv6未改变,将等待 %d 次后与DNS服务商进行比对\n", domains.Ipv6Cache.Times)
|
||||
util.Log("IPv6未改变, 将等待 %d 次后与DNS服务商进行比对", domains.Ipv6Cache.Times)
|
||||
return "", domains.Ipv6Domains
|
||||
}
|
||||
}
|
||||
@ -174,7 +174,7 @@ func (domains *Domains) GetNewIpResult(recordType string) (ipAddr string, retDom
|
||||
if domains.Ipv4Cache.Check(domains.Ipv4Addr) {
|
||||
return domains.Ipv4Addr, domains.Ipv4Domains
|
||||
} else {
|
||||
log.Printf("IPv4未改变,将等待 %d 次后与DNS服务商进行比对\n", domains.Ipv4Cache.Times)
|
||||
util.Log("IPv4未改变, 将等待 %d 次后与DNS服务商进行比对", domains.Ipv4Cache.Times)
|
||||
return "", domains.Ipv4Domains
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -48,7 +47,7 @@ func ExecWebhook(domains *Domains, conf *Config) (v4Status updateStatusType, v6S
|
||||
if v4Status == UpdatedFailed || v6Status == UpdatedFailed {
|
||||
updatedFailedTimes++
|
||||
if updatedFailedTimes != 3 {
|
||||
log.Println("将不会触发Webhook,仅在第 3 次失败时触发一次Webhook,当前失败次数:", updatedFailedTimes)
|
||||
util.Log("将不会触发Webhook, 仅在第 3 次失败时触发一次Webhook, 当前失败次数:%d", updatedFailedTimes)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -66,18 +65,18 @@ func ExecWebhook(domains *Domains, conf *Config) (v4Status updateStatusType, v6S
|
||||
contentType = "application/json"
|
||||
} else if hasJSONPrefix(postPara) {
|
||||
// 如果 RequestBody 的 JSON 无效但前缀为 JSON,提示无效
|
||||
log.Println("RequestBody 的 JSON 无效!")
|
||||
util.Log("Webhook中的 RequestBody JSON 无效")
|
||||
}
|
||||
}
|
||||
requestURL := replacePara(domains, conf.WebhookURL, v4Status, v6Status)
|
||||
u, err := url.Parse(requestURL)
|
||||
if err != nil {
|
||||
log.Println("Webhook配置中的URL不正确")
|
||||
util.Log("Webhook配置中的URL不正确")
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(method, fmt.Sprintf("%s://%s%s?%s", u.Scheme, u.Host, u.Path, u.Query().Encode()), strings.NewReader(postPara))
|
||||
if err != nil {
|
||||
log.Println("创建Webhook请求异常, Err:", err)
|
||||
util.Log("Webhook调用失败! 异常信息:%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -89,11 +88,11 @@ func ExecWebhook(domains *Domains, conf *Config) (v4Status updateStatusType, v6S
|
||||
|
||||
clt := util.CreateHTTPClient()
|
||||
resp, err := clt.Do(req)
|
||||
body, err := util.GetHTTPResponseOrg(resp, requestURL, err)
|
||||
body, err := util.GetHTTPResponseOrg(resp, err)
|
||||
if err == nil {
|
||||
log.Printf("Webhook调用成功, 返回数据: %q\n", string(body))
|
||||
util.Log("Webhook调用成功! 返回数据:%s", string(body))
|
||||
} else {
|
||||
log.Printf("Webhook调用失败,Err:%s\n", err)
|
||||
util.Log("Webhook调用失败! 异常信息:%s", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -122,11 +121,11 @@ func getDomainsStatus(domains []*Domain) updateStatusType {
|
||||
// replacePara 替换参数
|
||||
func replacePara(domains *Domains, orgPara string, ipv4Result updateStatusType, ipv6Result updateStatusType) (newPara string) {
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv4Addr}", domains.Ipv4Addr)
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv4Result}", string(ipv4Result))
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv4Result}", util.LogStr(string(ipv4Result))) // i18n
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv4Domains}", getDomainsStr(domains.Ipv4Domains))
|
||||
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv6Addr}", domains.Ipv6Addr)
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv6Result}", string(ipv6Result))
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv6Result}", util.LogStr(string(ipv6Result))) // i18n
|
||||
orgPara = strings.ReplaceAll(orgPara, "#{ipv6Domains}", getDomainsStr(domains.Ipv6Domains))
|
||||
|
||||
return orgPara
|
||||
@ -153,7 +152,7 @@ func checkParseHeaders(headerStr string) (headers map[string]string) {
|
||||
if headerStr != "" {
|
||||
parts := strings.Split(headerStr, ":")
|
||||
if len(parts) != 2 {
|
||||
log.Println(headerStr, "Header不正确")
|
||||
util.Log("Webhook Header不正确: %s", headerStr)
|
||||
continue
|
||||
}
|
||||
headers[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
|
BIN
ddns-web.png
BIN
ddns-web.png
Binary file not shown.
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 54 KiB |
@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@ -82,6 +81,7 @@ func (ali *Alidns) addUpdateDomainRecords(recordType string) {
|
||||
err := ali.request(params, &records)
|
||||
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -120,10 +120,10 @@ func (ali *Alidns) create(domain *config.Domain, recordType string, ipAddr strin
|
||||
err := ali.request(params, &result)
|
||||
|
||||
if err == nil && result.RecordID != "" {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!", domain)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -133,7 +133,7 @@ func (ali *Alidns) modify(recordSelected AlidnsRecord, domain *config.Domain, re
|
||||
|
||||
// 相同不修改
|
||||
if recordSelected.Value == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
|
||||
@ -149,10 +149,10 @@ func (ali *Alidns) modify(recordSelected AlidnsRecord, domain *config.Domain, re
|
||||
err := ali.request(params, &result)
|
||||
|
||||
if err == nil && result.RecordID != "" {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -170,13 +170,13 @@ func (ali *Alidns) request(params url.Values, result interface{}) (err error) {
|
||||
req.URL.RawQuery = params.Encode()
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, alidnsEndpoint, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
16
dns/baidu.go
16
dns/baidu.go
@ -3,7 +3,6 @@ package dns
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@ -110,6 +109,7 @@ func (baidu *BaiduCloud) addUpdateDomainRecords(recordType string) {
|
||||
|
||||
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/list", requestBody, &records)
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -143,10 +143,10 @@ func (baidu *BaiduCloud) create(domain *config.Domain, recordType string, ipAddr
|
||||
|
||||
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/add", baiduCreateRequest, &result)
|
||||
if err == nil {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!", domain)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -155,7 +155,7 @@ func (baidu *BaiduCloud) create(domain *config.Domain, recordType string, ipAddr
|
||||
func (baidu *BaiduCloud) modify(record BaiduRecord, domain *config.Domain, rdType string, ipAddr string) {
|
||||
//没有变化直接跳过
|
||||
if record.Rdata == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
var baiduModifyRequest = BaiduModifyRequest{
|
||||
@ -171,10 +171,10 @@ func (baidu *BaiduCloud) modify(record BaiduRecord, domain *config.Domain, rdTyp
|
||||
|
||||
err := baidu.request("POST", baiduEndpoint+"/v1/domain/resolve/edit", baiduModifyRequest, &result)
|
||||
if err == nil {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,7 @@ func (baidu *BaiduCloud) request(method string, url string, data interface{}, re
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ func (baidu *BaiduCloud) request(method string, url string, data interface{}, re
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, url, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -53,12 +52,12 @@ func (cb *Callback) addUpdateDomainRecords(recordType string) {
|
||||
// 防止多次发送Webhook通知
|
||||
if recordType == "A" {
|
||||
if cb.lastIpv4 == ipAddr {
|
||||
log.Println("你的IPv4未变化, 未触发Callback")
|
||||
util.Log("你的IPv4未变化, 未触发 %s 请求", "Callback")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if cb.lastIpv6 == ipAddr {
|
||||
log.Println("你的IPv6未变化, 未触发Callback")
|
||||
util.Log("你的IPv6未变化, 未触发 %s 请求", "Callback")
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -77,24 +76,24 @@ func (cb *Callback) addUpdateDomainRecords(recordType string) {
|
||||
requestURL := replacePara(cb.DNS.ID, ipAddr, domain, recordType, cb.TTL)
|
||||
u, err := url.Parse(requestURL)
|
||||
if err != nil {
|
||||
log.Println("Callback的URL不正确")
|
||||
util.Log("Callback的URL不正确")
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(method, u.String(), strings.NewReader(postPara))
|
||||
if err != nil {
|
||||
log.Println("创建Callback请求异常, Err:", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
req.Header.Add("content-type", contentType)
|
||||
|
||||
clt := util.CreateHTTPClient()
|
||||
resp, err := clt.Do(req)
|
||||
body, err := util.GetHTTPResponseOrg(resp, requestURL, err)
|
||||
body, err := util.GetHTTPResponseOrg(resp, err)
|
||||
if err == nil {
|
||||
log.Printf("Callback调用成功, 域名: %s, IP: %s, 返回数据: %s, \n", domain, ipAddr, string(body))
|
||||
util.Log("Callback调用成功, 域名: %s, IP: %s, 返回数据: %s", domain, ipAddr, string(body))
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("Callback调用失败,Err:%s\n", err)
|
||||
util.Log("Callback调用失败, 异常信息: %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@ -93,6 +92,7 @@ func (cf *Cloudflare) addUpdateDomainRecords(recordType string) {
|
||||
// get zone
|
||||
result, err := cf.getZones(domain)
|
||||
if err != nil || len(result.Result) != 1 {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -108,6 +108,7 @@ func (cf *Cloudflare) addUpdateDomainRecords(recordType string) {
|
||||
)
|
||||
|
||||
if err != nil || !records.Success {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -139,10 +140,10 @@ func (cf *Cloudflare) create(zoneID string, domain *config.Domain, recordType st
|
||||
&status,
|
||||
)
|
||||
if err == nil && status.Success {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!Messages: %s", domain, status.Messages)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -152,7 +153,7 @@ func (cf *Cloudflare) modify(result CloudflareRecordsResp, zoneID string, domain
|
||||
for _, record := range result.Result {
|
||||
// 相同不修改
|
||||
if record.Content == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
continue
|
||||
}
|
||||
var status CloudflareStatus
|
||||
@ -169,10 +170,10 @@ func (cf *Cloudflare) modify(result CloudflareRecordsResp, zoneID string, domain
|
||||
&status,
|
||||
)
|
||||
if err == nil && status.Success {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!Messages: %s", domain, status.Messages)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -202,7 +203,7 @@ func (cf *Cloudflare) request(method string, url string, data interface{}, resul
|
||||
bytes.NewBuffer(jsonStr),
|
||||
)
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+cf.DNS.Secret)
|
||||
@ -210,7 +211,7 @@ func (cf *Cloudflare) request(method string, url string, data interface{}, resul
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, url, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
"github.com/jeessy2/ddns-go/v5/config"
|
||||
@ -76,6 +75,7 @@ func (dnspod *Dnspod) addUpdateDomainRecords(recordType string) {
|
||||
for _, domain := range domains {
|
||||
result, err := dnspod.getRecordList(domain, recordType)
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -117,10 +117,10 @@ func (dnspod *Dnspod) create(domain *config.Domain, recordType string, ipAddr st
|
||||
|
||||
status, err := dnspod.commonRequest(recordCreateAPI, params, domain)
|
||||
if err == nil && status.Status.Code == "1" {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!Code: %s, Message: %s", domain, status.Status.Code, status.Status.Message)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, status.Status.Message)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -130,7 +130,7 @@ func (dnspod *Dnspod) modify(record DnspodRecord, domain *config.Domain, recordT
|
||||
|
||||
// 相同不修改
|
||||
if record.Value == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
|
||||
@ -149,10 +149,10 @@ func (dnspod *Dnspod) modify(record DnspodRecord, domain *config.Domain, recordT
|
||||
}
|
||||
status, err := dnspod.commonRequest(recordModifyURL, params, domain)
|
||||
if err == nil && status.Status.Code == "1" {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!Code: %s, Message: %s", domain, status.Status.Code, status.Status.Message)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, status.Status.Message)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -165,7 +165,7 @@ func (dnspod *Dnspod) commonRequest(apiAddr string, values url.Values, domain *c
|
||||
values,
|
||||
)
|
||||
|
||||
err = util.GetHTTPResponse(resp, apiAddr, err, &status)
|
||||
err = util.GetHTTPResponse(resp, err, &status)
|
||||
|
||||
return
|
||||
}
|
||||
@ -186,7 +186,7 @@ func (dnspod *Dnspod) getRecordList(domain *config.Domain, typ string) (result D
|
||||
params,
|
||||
)
|
||||
|
||||
err = util.GetHTTPResponse(resp, recordListAPI, err, &result)
|
||||
err = util.GetHTTPResponse(resp, err, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@ -59,12 +58,12 @@ func (g *GoDaddyDNS) updateDomainRecord(recordType string, ipAddr string, domain
|
||||
// 防止多次发送Webhook通知
|
||||
if recordType == "A" {
|
||||
if g.lastIpv4 == ipAddr {
|
||||
log.Println("你的IPv4未变化, 未触发Godaddy请求")
|
||||
util.Log("你的IPv4未变化, 未触发 %s 请求", "godaddy")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if g.lastIpv6 == ipAddr {
|
||||
log.Println("你的IPv6未变化, 未触发Godaddy请求")
|
||||
util.Log("你的IPv6未变化, 未触发 %s 请求", "godaddy")
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -77,10 +76,10 @@ func (g *GoDaddyDNS) updateDomainRecord(recordType string, ipAddr string, domain
|
||||
Type: recordType,
|
||||
}})
|
||||
if err == nil {
|
||||
log.Printf("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -115,6 +114,6 @@ func (g *GoDaddyDNS) sendReq(method string, rType string, domain *config.Domain,
|
||||
}
|
||||
req.Header = g.header
|
||||
resp, err := g.client.Do(req)
|
||||
_, err = util.GetHTTPResponseOrg(resp, path, err)
|
||||
_, err = util.GetHTTPResponseOrg(resp, err)
|
||||
return err
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -55,12 +54,12 @@ func (gd *GoogleDomain) addUpdateDomainRecords(recordType string) {
|
||||
// 防止多次发送Webhook通知
|
||||
if recordType == "A" {
|
||||
if gd.lastIpv4 == ipAddr {
|
||||
log.Println("你的IPv4未变化, 未触发Google请求")
|
||||
util.Log("你的IPv4未变化, 未触发 %s 请求", "GoogleDomain")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if gd.lastIpv6 == ipAddr {
|
||||
log.Println("你的IPv6未变化, 未触发Google请求")
|
||||
util.Log("你的IPv6未变化, 未触发 %s 请求", "GoogleDomain")
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -80,19 +79,19 @@ func (gd *GoogleDomain) modify(domain *config.Domain, recordType string, ipAddr
|
||||
err := gd.request(params, &result)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("修改域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
|
||||
switch result.Status {
|
||||
case "nochg":
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
case "good":
|
||||
log.Printf("修改域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
default:
|
||||
log.Printf("修改域名解析 %s 失败!Status: %s", domain, result.Status)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, result)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -107,7 +106,7 @@ func (gd *GoogleDomain) request(params url.Values, result *GoogleDomainResp) (er
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -117,7 +116,7 @@ func (gd *GoogleDomain) request(params url.Values, result *GoogleDomainResp) (er
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("client.Do失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@ -94,6 +93,7 @@ func (hw *Huaweicloud) addUpdateDomainRecords(recordType string) {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -124,7 +124,7 @@ func (hw *Huaweicloud) create(domain *config.Domain, recordType string, ipAddr s
|
||||
return
|
||||
}
|
||||
if len(zone.Zones) == 0 {
|
||||
log.Println("未能找到公网域名, 请检查域名是否添加")
|
||||
util.Log("在DNS服务商中未找到域名: %s", domain.String())
|
||||
return
|
||||
}
|
||||
|
||||
@ -150,10 +150,10 @@ func (hw *Huaweicloud) create(domain *config.Domain, recordType string, ipAddr s
|
||||
&result,
|
||||
)
|
||||
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!Status: %s", domain, result.Status)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -163,7 +163,7 @@ func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *config.Domai
|
||||
|
||||
// 相同不修改
|
||||
if len(record.Records) > 0 && record.Records[0] == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
|
||||
@ -181,10 +181,10 @@ func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *config.Domai
|
||||
)
|
||||
|
||||
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s, 状态: %s", domain, ipAddr, result.Status)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!Status: %s", domain, result.Status)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -215,7 +215,7 @@ func (hw *Huaweicloud) request(method string, url string, data interface{}, resu
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ func (hw *Huaweicloud) request(method string, url string, data interface{}, resu
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, url, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -28,15 +27,14 @@ func WaitForNetworkConnected(addresses []string) {
|
||||
// 如果 err 包含回环地址([::1]:53)则表示没有 DNS 服务器,设置 DNS 服务器
|
||||
if strings.Contains(err.Error(), loopbackServer) && !find {
|
||||
server := "1.1.1.1:53"
|
||||
log.Printf("解析回环地址 %s 失败!将默认使用 %s,可参考文档通过 -dns 自定义 DNS 服务器",
|
||||
loopbackServer, server)
|
||||
|
||||
util.Log("本机DNS异常! 将默认使用 %s, 可参考文档通过 -dns 自定义 DNS 服务器", loopbackServer, server)
|
||||
util.NewDialerResolver(server)
|
||||
find = true
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("等待网络连接:%s。%s 后重试...", err, timeout)
|
||||
util.Log("等待网络连接: %s", err)
|
||||
util.Log("%s 后重试...", timeout)
|
||||
// 等待 5 秒后重试
|
||||
time.Sleep(timeout)
|
||||
continue
|
||||
|
@ -2,7 +2,6 @@ package dns
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -56,17 +55,13 @@ func (nc *NameCheap) addUpdateDomainRecords(recordType string) {
|
||||
// 防止多次发送Webhook通知
|
||||
if recordType == "A" {
|
||||
if nc.lastIpv4 == ipAddr {
|
||||
log.Println("你的IPv4未变化, 未触发Namecheap请求")
|
||||
util.Log("你的IPv4未变化, 未触发 %s 请求", "NameCheap")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// https://www.namecheap.com/support/knowledgebase/article.aspx/29/11/how-to-dynamically-update-the-hosts-ip-with-an-http-request/
|
||||
log.Println("Namecheap DDNS 不支持更新 IPv6!")
|
||||
util.Log("Namecheap 不支持更新 IPv6")
|
||||
return
|
||||
// if nc.lastIpv6 == ipAddr {
|
||||
// log.Println("你的IPv6未变化, 未触发Namecheap请求")
|
||||
// return
|
||||
// }
|
||||
}
|
||||
|
||||
for _, domain := range domains {
|
||||
@ -80,17 +75,17 @@ func (nc *NameCheap) modify(domain *config.Domain, recordType string, ipAddr str
|
||||
err := nc.request(&result, ipAddr, domain)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("修改域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, result)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
|
||||
switch result.Status {
|
||||
case "Success":
|
||||
log.Printf("修改域名解析 %s 成功!IP: %s\n", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
default:
|
||||
log.Printf("修改域名解析 %s 失败!Status: %s\n", domain, result.Status)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, result)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -110,21 +105,21 @@ func (nc *NameCheap) request(result *NameCheapResp, ipAddr string, domain *confi
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("client.Do失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Println("请求namecheap失败")
|
||||
util.Log("异常信息: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package dns
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -97,7 +96,7 @@ func (ns *NameSilo) addUpdateDomainRecords(recordType string) {
|
||||
// 拿到DNS记录列表,从列表中去取对应域名的id,有id进行修改,没ID进行新增
|
||||
records, err := ns.listRecords(domain)
|
||||
if err != nil {
|
||||
log.Printf("获取域名列表 %s 失败!", domain)
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -110,7 +109,7 @@ func (ns *NameSilo) addUpdateDomainRecords(recordType string) {
|
||||
} else {
|
||||
recordID = record.RecordID
|
||||
if record.Value == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -127,21 +126,21 @@ func (ns *NameSilo) modify(domain *config.Domain, recordID, recordType, ipAddr s
|
||||
requestType = "新增"
|
||||
result, err = ns.request(ipAddr, domain, "", recordType, nameSiloAddRecordEndpoint)
|
||||
} else {
|
||||
requestType = "修改"
|
||||
requestType = "更新"
|
||||
result, err = ns.request(ipAddr, domain, recordID, "", nameSiloUpdateRecordEndpoint)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("修改域名解析 %s 失败!", domain)
|
||||
util.Log("异常信息: %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
var resp NameSiloResp
|
||||
xml.Unmarshal([]byte(result), &resp)
|
||||
if resp.Reply.Code == 300 {
|
||||
log.Printf("%s 域名解析 %s 成功!IP: %s\n", requestType, domain, ipAddr)
|
||||
util.Log(requestType+"域名解析 %s 成功! IP: %s\n", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("%s 域名解析 %s 失败!Deatil: %s\n", requestType, domain, resp.Reply.Detail)
|
||||
util.Log(requestType+"域名解析 %s 失败! 异常信息: %s", domain, resp.Reply.Detail)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -172,14 +171,14 @@ func (ns *NameSilo) request(ipAddr string, domain *config.Domain, recordID, reco
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("client.Do失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/jeessy2/ddns-go/v5/config"
|
||||
@ -87,26 +86,27 @@ func (pb *Porkbun) addUpdateDomainRecords(recordType string) {
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
if record.Status == "SUCCESS" {
|
||||
if len(record.Records) > 0 {
|
||||
// 存在,更新
|
||||
pb.modify(&record, domain, &recordType, &ipAddr)
|
||||
pb.modify(&record, domain, recordType, ipAddr)
|
||||
} else {
|
||||
// 不存在,创建
|
||||
pb.create(domain, &recordType, &ipAddr)
|
||||
pb.create(domain, recordType, ipAddr)
|
||||
}
|
||||
} else {
|
||||
log.Printf("查询现有域名记录失败")
|
||||
util.Log("在DNS服务商中未找到域名: %s", domain.String())
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建
|
||||
func (pb *Porkbun) create(domain *config.Domain, recordType *string, ipAddr *string) {
|
||||
func (pb *Porkbun) create(domain *config.Domain, recordType string, ipAddr string) {
|
||||
var response PorkbunResponse
|
||||
|
||||
err := pb.request(
|
||||
@ -118,8 +118,8 @@ func (pb *Porkbun) create(domain *config.Domain, recordType *string, ipAddr *str
|
||||
},
|
||||
PorkbunDomainRecord: &PorkbunDomainRecord{
|
||||
Name: &domain.SubDomain,
|
||||
Type: recordType,
|
||||
Content: ipAddr,
|
||||
Type: &recordType,
|
||||
Content: &ipAddr,
|
||||
Ttl: &pb.TTL,
|
||||
},
|
||||
},
|
||||
@ -127,34 +127,34 @@ func (pb *Porkbun) create(domain *config.Domain, recordType *string, ipAddr *str
|
||||
)
|
||||
|
||||
if err == nil && response.Status == "SUCCESS" {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, *ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!", domain)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
|
||||
// 修改
|
||||
func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *config.Domain, recordType *string, ipAddr *string) {
|
||||
func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *config.Domain, recordType string, ipAddr string) {
|
||||
|
||||
// 相同不修改
|
||||
if len(record.Records) > 0 && *record.Records[0].Content == *ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", *ipAddr, domain)
|
||||
if len(record.Records) > 0 && *record.Records[0].Content == ipAddr {
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
|
||||
var response PorkbunResponse
|
||||
|
||||
err := pb.request(
|
||||
porkbunEndpoint+fmt.Sprintf("/editByNameType/%s/%s/%s", domain.DomainName, *recordType, domain.SubDomain),
|
||||
porkbunEndpoint+fmt.Sprintf("/editByNameType/%s/%s/%s", domain.DomainName, recordType, domain.SubDomain),
|
||||
&PorkbunDomainCreateOrUpdateVO{
|
||||
PorkbunApiKey: &PorkbunApiKey{
|
||||
AccessKey: pb.DNSConfig.ID,
|
||||
SecretKey: pb.DNSConfig.Secret,
|
||||
},
|
||||
PorkbunDomainRecord: &PorkbunDomainRecord{
|
||||
Content: ipAddr,
|
||||
Content: &ipAddr,
|
||||
Ttl: &pb.TTL,
|
||||
},
|
||||
},
|
||||
@ -162,10 +162,10 @@ func (pb *Porkbun) modify(record *PorkbunDomainQueryResponse, domain *config.Dom
|
||||
)
|
||||
|
||||
if err == nil && response.Status == "SUCCESS" {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, *ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!", domain)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -182,14 +182,14 @@ func (pb *Porkbun) request(url string, data interface{}, result interface{}) (er
|
||||
bytes.NewBuffer(jsonStr),
|
||||
)
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, url, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package dns
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@ -99,6 +98,7 @@ func (tc *TencentCloud) addUpdateDomainRecords(recordType string) {
|
||||
for _, domain := range domains {
|
||||
result, err := tc.getRecordList(domain, recordType)
|
||||
if err != nil {
|
||||
util.Log("查询域名信息发生异常! %s", err)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
return
|
||||
}
|
||||
@ -143,10 +143,10 @@ func (tc *TencentCloud) create(domain *config.Domain, recordType string, ipAddr
|
||||
&status,
|
||||
)
|
||||
if err == nil && status.Response.Error.Code == "" {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("新增域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!Code: %s, Message: %s", domain, status.Response.Error.Code, status.Response.Error.Message)
|
||||
util.Log("新增域名解析 %s 失败! 异常信息: %s", domain, status.Response.Error.Message)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -156,7 +156,7 @@ func (tc *TencentCloud) create(domain *config.Domain, recordType string, ipAddr
|
||||
func (tc *TencentCloud) modify(record TencentCloudRecord, domain *config.Domain, recordType string, ipAddr string) {
|
||||
// 相同不修改
|
||||
if record.Value == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
util.Log("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
var status TencentCloudStatus
|
||||
@ -172,10 +172,10 @@ func (tc *TencentCloud) modify(record TencentCloudRecord, domain *config.Domain,
|
||||
&status,
|
||||
)
|
||||
if err == nil && status.Response.Error.Code == "" {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
|
||||
domain.UpdateStatus = config.UpdatedSuccess
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!Code: %s, Message: %s", domain, status.Response.Error.Code, status.Response.Error.Message)
|
||||
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, status.Response.Error.Message)
|
||||
domain.UpdateStatus = config.UpdatedFailed
|
||||
}
|
||||
}
|
||||
@ -218,7 +218,7 @@ func (tc *TencentCloud) request(action string, data interface{}, result interfac
|
||||
bytes.NewBuffer(jsonStr),
|
||||
)
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest 失败. Error: ", err)
|
||||
util.Log("异常信息: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ func (tc *TencentCloud) request(action string, data interface{}, result interfac
|
||||
|
||||
client := util.CreateHTTPClient()
|
||||
resp, err := client.Do(req)
|
||||
err = util.GetHTTPResponse(resp, tencentCloudEndPoint, err, result)
|
||||
err = util.GetHTTPResponse(resp, err, result)
|
||||
|
||||
return
|
||||
}
|
||||
|
5
go.mod
5
go.mod
@ -9,4 +9,7 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.16.0 // indirect
|
||||
require (
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -7,6 +7,8 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
52
main.go
52
main.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
@ -24,34 +25,34 @@ import (
|
||||
|
||||
// ddns-go 版本
|
||||
// ddns-go version
|
||||
var versionFlag = flag.Bool("v", false, "ddns-go 版本")
|
||||
var versionFlag = flag.Bool("v", false, "ddns-go version")
|
||||
|
||||
// 更新 ddns-go
|
||||
var updateFlag = flag.Bool("u", false, "更新 ddns-go")
|
||||
var updateFlag = flag.Bool("u", false, "Upgrade ddns-go to the latest version")
|
||||
|
||||
// 监听地址
|
||||
var listen = flag.String("l", ":9876", "监听地址")
|
||||
var listen = flag.String("l", ":9876", "Listen address")
|
||||
|
||||
// 更新频率(秒)
|
||||
var every = flag.Int("f", 300, "同步间隔时间(秒)")
|
||||
var every = flag.Int("f", 300, "Sync frequency(seconds)")
|
||||
|
||||
// 缓存次数
|
||||
var ipCacheTimes = flag.Int("cacheTimes", 5, "间隔N次与服务商比对")
|
||||
var ipCacheTimes = flag.Int("cacheTimes", 5, "Interval N times compared with service providers")
|
||||
|
||||
// 服务管理
|
||||
var serviceType = flag.String("s", "", "服务管理, 支持install, uninstall, restart")
|
||||
var serviceType = flag.String("s", "", "Service management (install|uninstall|restart)")
|
||||
|
||||
// 配置文件路径
|
||||
var configFilePath = flag.String("c", util.GetConfigFilePathDefault(), "自定义配置文件路径")
|
||||
var configFilePath = flag.String("c", util.GetConfigFilePathDefault(), "config file path")
|
||||
|
||||
// Web 服务
|
||||
var noWebService = flag.Bool("noweb", false, "不启动 web 服务")
|
||||
var noWebService = flag.Bool("noweb", false, "No web service")
|
||||
|
||||
// 跳过验证证书
|
||||
var skipVerify = flag.Bool("skipVerify", false, "跳过验证证书, 适合不能升级的老系统")
|
||||
var skipVerify = flag.Bool("skipVerify", false, "Skip certificate verification")
|
||||
|
||||
// 自定义 DNS 服务器
|
||||
var customDNSServer = flag.String("dns", "", "自定义 DNS 服务器(例如 1.1.1.1)")
|
||||
var customDNSServer = flag.String("dns", "", "Custom DNS server, example: 8.8.8.8")
|
||||
|
||||
//go:embed static
|
||||
var staticEmbeddedFiles embed.FS
|
||||
@ -73,7 +74,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
if _, err := net.ResolveTCPAddr("tcp", *listen); err != nil {
|
||||
log.Fatalf("解析监听地址异常,%s", err)
|
||||
log.Fatalf("Parse listen address failed! Exception: %s", err)
|
||||
}
|
||||
os.Setenv(web.VersionEnv, version)
|
||||
if *configFilePath != "" {
|
||||
@ -111,9 +112,9 @@ func main() {
|
||||
// 非服务方式运行
|
||||
switch s.Platform() {
|
||||
case "windows-service":
|
||||
log.Println("可使用 .\\ddns-go.exe -s install 安装服务运行")
|
||||
util.Log("可使用 .\\ddns-go.exe -s install 安装服务运行")
|
||||
default:
|
||||
log.Println("可使用 sudo ./ddns-go -s install 安装服务运行")
|
||||
util.Log("可使用 sudo ./ddns-go -s install 安装服务运行")
|
||||
}
|
||||
run()
|
||||
}
|
||||
@ -163,11 +164,11 @@ func runWebServer() error {
|
||||
http.HandleFunc("/ipv6NetInterface", web.BasicAuth(web.Ipv6NetInterfaces))
|
||||
http.HandleFunc("/webhookTest", web.BasicAuth(web.WebhookTest))
|
||||
|
||||
log.Println("监听", *listen, "...")
|
||||
util.Log("监听 %s", *listen)
|
||||
|
||||
l, err := net.Listen("tcp", *listen)
|
||||
if err != nil {
|
||||
return fmt.Errorf("监听端口发生异常, 请检查端口是否被占用: %w", err)
|
||||
return errors.New(util.LogStr("监听端口发生异常, 请检查端口是否被占用! %s", err))
|
||||
}
|
||||
|
||||
// 没有配置, 自动打开浏览器
|
||||
@ -211,7 +212,7 @@ func getService() service.Service {
|
||||
svcConfig := &service.Config{
|
||||
Name: "ddns-go",
|
||||
DisplayName: "ddns-go",
|
||||
Description: "简单好用的DDNS。自动更新域名解析到公网IP(支持阿里云、腾讯云dnspod、Cloudflare、Callback、华为云、百度云、Porkbun、GoDaddy、Google Domain)",
|
||||
Description: "Simple and easy to use DDNS. Automatically update domain name resolution to public IP (Support Aliyun, Tencent Cloud, Dnspod, Cloudflare, Callback, Huawei Cloud, Baidu Cloud, Porkbun, GoDaddy...)",
|
||||
Arguments: []string{"-l", *listen, "-f", strconv.Itoa(*every), "-cacheTimes", strconv.Itoa(*ipCacheTimes), "-c", *configFilePath},
|
||||
Dependencies: depends,
|
||||
Option: options,
|
||||
@ -247,9 +248,9 @@ func uninstallService() {
|
||||
}
|
||||
}
|
||||
if err := s.Uninstall(); err == nil {
|
||||
log.Println("ddns-go 服务卸载成功!")
|
||||
util.Log("ddns-go 服务卸载成功")
|
||||
} else {
|
||||
log.Printf("ddns-go 服务卸载失败, ERR: %s\n", err)
|
||||
util.Log("ddns-go 服务卸载失败, 异常信息: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,7 +263,7 @@ func installService() {
|
||||
// 服务未知,创建服务
|
||||
if err = s.Install(); err == nil {
|
||||
s.Start()
|
||||
log.Println("安装 ddns-go 服务成功! 请打开浏览器并进行配置。")
|
||||
util.Log("安装 ddns-go 服务成功! 请打开浏览器并进行配置")
|
||||
if service.ChosenSystem().String() == "unix-systemv" {
|
||||
if _, err := exec.Command("/etc/init.d/ddns-go", "enable").Output(); err != nil {
|
||||
log.Println(err)
|
||||
@ -273,12 +274,11 @@ func installService() {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("安装 ddns-go 服务失败, ERR: %s\n", err)
|
||||
util.Log("安装 ddns-go 服务失败, 异常信息: %s", err)
|
||||
}
|
||||
|
||||
if status != service.StatusUnknown {
|
||||
log.Println("ddns-go 服务已安装, 无需再次安装")
|
||||
util.Log("ddns-go 服务已安装, 无需再次安装")
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,15 +289,15 @@ func restartService() {
|
||||
if err == nil {
|
||||
if status == service.StatusRunning {
|
||||
if err = s.Restart(); err == nil {
|
||||
log.Println("重启 ddns-go 服务成功!")
|
||||
util.Log("重启 ddns-go 服务成功")
|
||||
}
|
||||
} else if status == service.StatusStopped {
|
||||
if err = s.Start(); err == nil {
|
||||
log.Println("启动 ddns-go 服务成功!")
|
||||
util.Log("启动 ddns-go 服务成功")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Println("ddns-go 服务未安装, 请先安装服务")
|
||||
util.Log("ddns-go 服务未安装, 请先安装服务")
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@ func autoOpenExplorer() {
|
||||
if err != nil {
|
||||
if util.IsRunInDocker() {
|
||||
// docker中运行, 提示
|
||||
fmt.Println("Docker中运行, 请在浏览器中打开 http://docker主机IP:端口 进行配置")
|
||||
util.Log("Docker中运行, 请在浏览器中打开 http://docker主机IP:9876 进行配置")
|
||||
} else {
|
||||
// 主机运行, 打开浏览器
|
||||
addr, err := net.ResolveTCPAddr("tcp", *listen)
|
||||
|
@ -226,6 +226,5 @@ main {
|
||||
margin-right: 8px;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
vertical-align: text-bottom;
|
||||
font-size: 16px;
|
||||
}
|
@ -4,21 +4,17 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GetHTTPResponse 处理HTTP结果,返回序列化的json
|
||||
func GetHTTPResponse(resp *http.Response, url string, err error, result interface{}) error {
|
||||
body, err := GetHTTPResponseOrg(resp, url, err)
|
||||
func GetHTTPResponse(resp *http.Response, err error, result interface{}) error {
|
||||
body, err := GetHTTPResponseOrg(resp, err)
|
||||
|
||||
if err == nil {
|
||||
// log.Println(string(body))
|
||||
if len(body) != 0 {
|
||||
err = json.Unmarshal(body, &result)
|
||||
if err != nil {
|
||||
log.Printf("请求接口%s解析json结果失败! ERROR: %s\n", url, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,9 +23,8 @@ func GetHTTPResponse(resp *http.Response, url string, err error, result interfac
|
||||
}
|
||||
|
||||
// GetHTTPResponseOrg 处理HTTP结果,返回byte
|
||||
func GetHTTPResponseOrg(resp *http.Response, url string, err error) ([]byte, error) {
|
||||
func GetHTTPResponseOrg(resp *http.Response, err error) ([]byte, error) {
|
||||
if err != nil {
|
||||
log.Printf("请求接口%s失败! ERROR: %s\n", url, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -38,14 +33,12 @@ func GetHTTPResponseOrg(resp *http.Response, url string, err error) ([]byte, err
|
||||
body, err := io.ReadAll(lr)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("请求接口%s失败! ERROR: %s\n", url, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 300及以上状态码都算异常
|
||||
if resp.StatusCode >= 300 {
|
||||
errMsg := fmt.Sprintf("请求接口 %s 失败! 返回内容: %s ,返回状态码: %d\n", url, string(body), resp.StatusCode)
|
||||
log.Println(errMsg)
|
||||
err = fmt.Errorf(errMsg)
|
||||
err = fmt.Errorf(LogStr("返回内容: %s ,返回状态码: %d", string(body), resp.StatusCode))
|
||||
}
|
||||
|
||||
return body, err
|
||||
|
128
util/messages.go
Normal file
128
util/messages.go
Normal file
@ -0,0 +1,128 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
var logPrinter = message.NewPrinter(language.English)
|
||||
|
||||
func init() {
|
||||
|
||||
message.SetString(language.English, "可使用 .\\ddns-go.exe -s install 安装服务运行", "You can use 'sudo .\\ddns-go -s install' to install service")
|
||||
message.SetString(language.English, "可使用 sudo ./ddns-go -s install 安装服务运行", "You can use 'sudo ./ddns-go -s install' to install service")
|
||||
message.SetString(language.English, "监听 %s", "Listen on %s")
|
||||
message.SetString(language.English, "配置文件已保存在: %s", "Config file has been saved to: %s")
|
||||
|
||||
message.SetString(language.English, "你的IP %s 没有变化, 域名 %s", "Your's IP %s has not changed! Domain: %s")
|
||||
message.SetString(language.English, "新增域名解析 %s 成功! IP: %s", "Added domain %s successfully! IP: %s")
|
||||
message.SetString(language.English, "新增域名解析 %s 失败! 异常信息: %s", "Added domain %s failed! Result: %s")
|
||||
|
||||
message.SetString(language.English, "更新域名解析 %s 成功! IP: %s", "Updated domain %s successfully! IP: %s")
|
||||
message.SetString(language.English, "更新域名解析 %s 失败! 异常信息: %s", "Updated domain %s failed! Result: %s")
|
||||
|
||||
message.SetString(language.English, "你的IPv4未变化, 未触发 %s 请求", "Your's IPv4 has not changed, %s request has not been triggered")
|
||||
message.SetString(language.English, "你的IPv6未变化, 未触发 %s 请求", "Your's IPv6 has not changed, %s request has not been triggered")
|
||||
message.SetString(language.English, "Namecheap 不支持更新 IPv6", "Namecheap don't supports IPv6")
|
||||
|
||||
// http_util
|
||||
message.SetString(language.English, "异常信息: %s", "Exception: %s")
|
||||
message.SetString(language.English, "查询域名信息发生异常! %s", "Query domain info failed! %s")
|
||||
message.SetString(language.English, "返回内容: %s ,返回状态码: %d", "Response body: %s ,Response status code: %d")
|
||||
message.SetString(language.English, "通过接口获取IPv4失败! 接口地址: %s", "Get IPv4 from %s failed")
|
||||
message.SetString(language.English, "通过接口获取IPv6失败! 接口地址: %s", "Get IPv6 from %s failed")
|
||||
message.SetString(language.English, "将不会触发Webhook, 仅在第 3 次失败时触发一次Webhook, 当前失败次数:%d", "Webhook will not be triggered, only trigger once when the third failure, current failure times: %d")
|
||||
message.SetString(language.English, "在DNS服务商中未找到域名: %s", "Domain %s not found in DNS provider")
|
||||
|
||||
// webhook
|
||||
message.SetString(language.English, "Webhook配置中的URL不正确", "Webhook url is incorrect")
|
||||
message.SetString(language.English, "Webhook中的 RequestBody JSON 无效", "Webhook RequestBody JSON is invalid")
|
||||
message.SetString(language.English, "Webhook调用成功! 返回数据:%s", "Webhook called successfully! Response body: %s")
|
||||
message.SetString(language.English, "Webhook调用失败! 异常信息:%s", "Webhook called failed! Exception: %s")
|
||||
message.SetString(language.English, "Webhook Header不正确: %s", "Webhook header is invalid: %s")
|
||||
message.SetString(language.English, "请输入Webhook的URL", "Please enter the Webhook url")
|
||||
|
||||
// callback
|
||||
message.SetString(language.English, "Callback的URL不正确", "Callback url is incorrect")
|
||||
message.SetString(language.English, "Callback调用成功, 域名: %s, IP: %s, 返回数据: %s", "Webhook called successfully! Domain: %s, IP: %s, Response body: %s")
|
||||
message.SetString(language.English, "Callback调用失败, 异常信息: %s", "Webhook called failed! Exception: %s")
|
||||
|
||||
// save
|
||||
message.SetString(language.English, "若通过公网访问, 仅允许在ddns-go启动后 5 分钟内完成首次配置", "If accessed via the public network, only allow the first configuration to be completed within 5 minutes after ddns-go starts")
|
||||
message.SetString(language.English, "若从未设置过帐号密码, 仅允许在ddns-go启动后 5 分钟内设置, 请重启ddns-go", "If you have never set an account password, you can only set it within 5 minutes after ddns-go starts, please restart ddns-go")
|
||||
message.SetString(language.English, "启用外网访问, 必须输入登录用户名/密码", "Enable external network access, you must enter the login username/password")
|
||||
message.SetString(language.English, "修改 '通过命令获取' 必须设置帐号密码,请先设置帐号密码", "Modify 'Get by command' must set username/password, please set username/password first")
|
||||
message.SetString(language.English, "密码不安全!尝试使用更长的密码", "insecure password, try using a longer password")
|
||||
|
||||
// config
|
||||
message.SetString(language.English, "从网卡获得IPv4失败", "Get IPv4 from network card failed")
|
||||
message.SetString(language.English, "从网卡中获得IPv4失败! 网卡名: %s", "Get IPv4 from network card failed! Network card name: %s")
|
||||
message.SetString(language.English, "获取IPv4结果失败! 接口: %s ,返回值: %s", "Get IPv4 result failed! Interface: %s ,Result: %s")
|
||||
message.SetString(language.English, "获取%s结果失败! 未能成功执行命令:%s, 错误:%q, 退出状态码:%s", "Get %s result failed! Command: %s, Error: %q, Exit status code: %s")
|
||||
message.SetString(language.English, "获取%s结果失败! 命令: %s, 标准输出: %q", "Get %s result failed! Command: %s, Stdout: %q")
|
||||
message.SetString(language.English, "从网卡获得IPv6失败", "Get IPv6 from network card failed")
|
||||
message.SetString(language.English, "从网卡中获得IPv6失败! 网卡名: %s", "Get IPv6 from network card failed! Network card name: %s")
|
||||
message.SetString(language.English, "获取IPv6结果失败! 接口: %s ,返回值: %s", "Get IPv6 result failed! Interface: %s ,Result: %s")
|
||||
message.SetString(language.English, "未找到第 %d 个IPv6地址! 将使用第一个IPv6地址", "%dth IPv6 address not found! Will use the first IPv6 address")
|
||||
message.SetString(language.English, "IPv6匹配表达式 %s 不正确! 最小从1开始", "IPv6 match expression %s is incorrect! Minimum start from 1")
|
||||
message.SetString(language.English, "IPv6将使用正则表达式 %s 进行匹配", "IPv6 will use regular expression %s for matching")
|
||||
message.SetString(language.English, "匹配成功! 匹配到地址: %s", "Match successfully! Matched address: %s")
|
||||
message.SetString(language.English, "没有匹配到任何一个IPv6地址, 将使用第一个地址", "No IPv6 address matched, will use the first address")
|
||||
message.SetString(language.English, "未能获取IPv4地址, 将不会更新", "Failed to get IPv4 address, will not update")
|
||||
message.SetString(language.English, "未能获取IPv6地址, 将不会更新", "Failed to get IPv6 address, will not update")
|
||||
|
||||
// domains
|
||||
message.SetString(language.English, "域名: %s 不正确", "The domain %s is incorrect")
|
||||
message.SetString(language.English, "域名: %s 解析失败", "The domain %s resolution failed")
|
||||
message.SetString(language.English, "IPv6未改变, 将等待 %d 次后与DNS服务商进行比对", "IPv6 has not changed, will wait %d times to compare with DNS provider")
|
||||
message.SetString(language.English, "IPv4未改变, 将等待 %d 次后与DNS服务商进行比对", "IPv4 has not changed, will wait %d times to compare with DNS provider")
|
||||
|
||||
message.SetString(language.English, "本机DNS异常! 将默认使用 %s, 可参考文档通过 -dns 自定义 DNS 服务器", "Local DNS exception! Will use %s by default, you can use -dns to customize DNS server")
|
||||
message.SetString(language.English, "等待网络连接: %s", "Waiting for network connection: %s")
|
||||
message.SetString(language.English, "%s 后重试...", "Retry after %s")
|
||||
|
||||
// main
|
||||
message.SetString(language.English, "监听端口发生异常, 请检查端口是否被占用! %s", "Listen port failed, please check if the port is occupied! %s")
|
||||
message.SetString(language.English, "Docker中运行, 请在浏览器中打开 http://docker主机IP:9876 进行配置", "Running in Docker, please open http://docker-host-ip:9876 in the browser for configuration")
|
||||
message.SetString(language.English, "ddns-go 服务卸载成功", "ddns-go service uninstalled successfully")
|
||||
message.SetString(language.English, "ddns-go 服务卸载失败, 异常信息: %s", "ddns-go service uninstalled failed, Exception: %s")
|
||||
message.SetString(language.English, "安装 ddns-go 服务成功! 请打开浏览器并进行配置", "Install ddns-go service successfully! Please open the browser and configure it")
|
||||
message.SetString(language.English, "安装 ddns-go 服务失败, 异常信息: %s", "Install ddns-go service failed, Exception: %s")
|
||||
message.SetString(language.English, "ddns-go 服务已安装, 无需再次安装", "ddns-go service has been installed, no need to install again")
|
||||
message.SetString(language.English, "重启 ddns-go 服务成功", "restart ddns-go service successfully")
|
||||
message.SetString(language.English, "启动 ddns-go 服务成功", "start ddns-go service successfully")
|
||||
message.SetString(language.English, "ddns-go 服务未安装, 请先安装服务", "ddns-go service is not installed, please install the service first")
|
||||
|
||||
// login
|
||||
message.SetString(language.English, "%q 配置文件为空, 超过3小时禁止从公网访问", "%q configuration file is empty, public network access is prohibited for more than 3 hours")
|
||||
message.SetString(language.English, "%q 被禁止从公网访问", "%q is prohibited from accessing the public network")
|
||||
message.SetString(language.English, "%q 登陆失败超过5次! 并延时5分钟响应", "%q login failed more than 5 times! And delay 5 minutes to respond")
|
||||
message.SetString(language.English, "%q 帐号密码不正确", "%q username or password is incorrect")
|
||||
message.SetString(language.English, "%q 请求登陆", "%q request login")
|
||||
|
||||
// webhook通知
|
||||
message.SetString(language.English, "未改变", "no changed")
|
||||
message.SetString(language.English, "失败", "failed")
|
||||
message.SetString(language.English, "成功", "success")
|
||||
|
||||
}
|
||||
|
||||
func Log(key string, args ...interface{}) {
|
||||
log.Println(LogStr(key, args...))
|
||||
}
|
||||
|
||||
func LogStr(key string, args ...interface{}) string {
|
||||
return logPrinter.Sprintf(key, args...)
|
||||
}
|
||||
|
||||
func InitLogLang(lang string) string {
|
||||
logLang := language.English
|
||||
if strings.HasPrefix(lang, "zh") {
|
||||
logLang = language.Chinese
|
||||
}
|
||||
logPrinter = message.NewPrinter(logLang)
|
||||
return logLang.String()
|
||||
}
|
@ -41,8 +41,9 @@ func getLatest(repo string) (*Release, error) {
|
||||
}
|
||||
|
||||
var result ReleaseResp
|
||||
err = util.GetHTTPResponse(resp, u, err, &result)
|
||||
err = util.GetHTTPResponse(resp, err, &result)
|
||||
if err != nil {
|
||||
util.Log("异常信息: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package web
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@ -30,7 +29,7 @@ func BasicAuth(f ViewFunc) ViewFunc {
|
||||
if err != nil && time.Now().Unix()-startTime > 3*60*60 &&
|
||||
(!util.IsPrivateNetwork(r.RemoteAddr) || !util.IsPrivateNetwork(r.Host)) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
log.Printf("%q 配置文件为空, 超过3小时禁止从公网访问。\n", util.GetRequestIPStr(r))
|
||||
util.Log("%q 配置文件为空, 超过3小时禁止从公网访问", util.GetRequestIPStr(r))
|
||||
return
|
||||
}
|
||||
|
||||
@ -38,7 +37,7 @@ func BasicAuth(f ViewFunc) ViewFunc {
|
||||
if conf.NotAllowWanAccess {
|
||||
if !util.IsPrivateNetwork(r.RemoteAddr) || !util.IsPrivateNetwork(r.Host) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
log.Printf("%q 被禁止从公网访问!\n", util.GetRequestIPStr(r))
|
||||
util.Log("%q 被禁止从公网访问", util.GetRequestIPStr(r))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -51,7 +50,7 @@ func BasicAuth(f ViewFunc) ViewFunc {
|
||||
}
|
||||
|
||||
if ld.FailTimes >= 5 {
|
||||
log.Printf("%q 登陆失败超过5次! 并延时5分钟响应!\n", util.GetRequestIPStr(r))
|
||||
util.Log("%q 登陆失败超过5次! 并延时5分钟响应", util.GetRequestIPStr(r))
|
||||
time.Sleep(5 * time.Minute)
|
||||
if ld.FailTimes >= 5 {
|
||||
ld.FailTimes = 0
|
||||
@ -84,7 +83,7 @@ func BasicAuth(f ViewFunc) ViewFunc {
|
||||
}
|
||||
|
||||
ld.FailTimes = ld.FailTimes + 1
|
||||
log.Printf("%q 帐号密码不正确!\n", util.GetRequestIPStr(r))
|
||||
util.Log("%q 帐号密码不正确", util.GetRequestIPStr(r))
|
||||
}
|
||||
|
||||
// 认证失败,提示 401 Unauthorized
|
||||
@ -92,6 +91,6 @@ func BasicAuth(f ViewFunc) ViewFunc {
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||
// 401 状态码
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
log.Printf("%q 请求登陆!\n", util.GetRequestIPStr(r))
|
||||
util.Log("%q 请求登陆", util.GetRequestIPStr(r))
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
passwordvalidator "github.com/wagslane/go-password-validator"
|
||||
)
|
||||
|
||||
const (
|
||||
replaceChars = `!@$&*`
|
||||
sepChars = `_-., `
|
||||
otherSpecialChars = `"#%'()+/:;<=>?[\]^{|}~`
|
||||
lowerChars = `abcdefghijklmnopqrstuvwxyz`
|
||||
upperChars = `ABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
digitsChars = `0123456789`
|
||||
)
|
||||
|
||||
// validatePassword 在密码大于或等于 minEntropy 时返回 nil。如果不是则返回错误。
|
||||
// 这解释了如何加强密码。向客户端显示此错误是安全的。
|
||||
//
|
||||
// https://github.com/wagslane/go-password-validator/blob/v0.3.0/validate.go#L13
|
||||
func validatePassword(password string, minEntropy float64) error {
|
||||
entropy := passwordvalidator.GetEntropy(password)
|
||||
if entropy >= minEntropy {
|
||||
return nil
|
||||
}
|
||||
|
||||
hasReplace := false
|
||||
hasSep := false
|
||||
hasOtherSpecial := false
|
||||
hasLower := false
|
||||
hasUpper := false
|
||||
hasDigits := false
|
||||
for _, c := range password {
|
||||
if strings.ContainsRune(replaceChars, c) {
|
||||
hasReplace = true
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(sepChars, c) {
|
||||
hasSep = true
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(otherSpecialChars, c) {
|
||||
hasOtherSpecial = true
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(lowerChars, c) {
|
||||
hasLower = true
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(upperChars, c) {
|
||||
hasUpper = true
|
||||
continue
|
||||
}
|
||||
if strings.ContainsRune(digitsChars, c) {
|
||||
hasDigits = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
allMessages := []string{}
|
||||
|
||||
if !hasOtherSpecial || !hasSep || !hasReplace {
|
||||
allMessages = append(allMessages, "包含更多特殊字符")
|
||||
}
|
||||
if !hasLower {
|
||||
allMessages = append(allMessages, "使用小写字母")
|
||||
}
|
||||
if !hasUpper {
|
||||
allMessages = append(allMessages, "使用大写字母")
|
||||
}
|
||||
if !hasDigits {
|
||||
allMessages = append(allMessages, "使用数字")
|
||||
}
|
||||
|
||||
if len(allMessages) > 0 {
|
||||
return fmt.Errorf(
|
||||
"密码不安全!尝试%v或使用更长的密码",
|
||||
strings.Join(allMessages, ","),
|
||||
)
|
||||
}
|
||||
|
||||
return errors.New("密码不安全!尝试使用更长的密码")
|
||||
}
|
19
web/save.go
19
web/save.go
@ -9,6 +9,7 @@ import (
|
||||
"github.com/jeessy2/ddns-go/v5/config"
|
||||
"github.com/jeessy2/ddns-go/v5/dns"
|
||||
"github.com/jeessy2/ddns-go/v5/util"
|
||||
passwordvalidator "github.com/wagslane/go-password-validator"
|
||||
)
|
||||
|
||||
var startTime = time.Now().Unix()
|
||||
@ -31,6 +32,10 @@ func checkAndSave(request *http.Request) string {
|
||||
usernameNew := strings.TrimSpace(request.FormValue("Username"))
|
||||
passwordNew := request.FormValue("Password")
|
||||
|
||||
// 国际化
|
||||
accept := request.Header.Get("Accept-Language")
|
||||
conf.Lang = util.InitLogLang(accept)
|
||||
|
||||
// 验证安全性后才允许设置保存配置文件:
|
||||
if time.Now().Unix()-startTime > 5*60 {
|
||||
firstTime := err != nil
|
||||
@ -38,14 +43,14 @@ func checkAndSave(request *http.Request) string {
|
||||
// 首次设置 && 通过外网访问 必需在服务启动的 5 分钟内
|
||||
if firstTime &&
|
||||
(!util.IsPrivateNetwork(request.RemoteAddr) || !util.IsPrivateNetwork(request.Host)) {
|
||||
return "若通过公网访问,仅允许在ddns-go启动后 5 分钟内完成首次配置"
|
||||
return util.LogStr("若通过公网访问, 仅允许在ddns-go启动后 5 分钟内完成首次配置")
|
||||
}
|
||||
|
||||
// 非首次设置 && 从未设置过帐号密码 && 本次设置了帐号或密码 必须在5分钟内
|
||||
if !firstTime &&
|
||||
(conf.Username == "" && conf.Password == "") &&
|
||||
(usernameNew != "" || passwordNew != "") {
|
||||
return "若从未设置过帐号密码,仅允许在ddns-go启动后 5 分钟内设置,请重启ddns-go"
|
||||
return util.LogStr("若从未设置过帐号密码, 仅允许在ddns-go启动后 5 分钟内设置, 请重启ddns-go")
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,7 +64,7 @@ func checkAndSave(request *http.Request) string {
|
||||
|
||||
// 如启用公网访问,帐号密码不能为空
|
||||
if !conf.NotAllowWanAccess && (conf.Username == "" || conf.Password == "") {
|
||||
return "启用外网访问, 必须输入登录用户名/密码"
|
||||
return util.LogStr("启用外网访问, 必须输入登录用户名/密码")
|
||||
}
|
||||
|
||||
// 如果密码不为空则检查是否够强, 内/外网要求强度不同
|
||||
@ -68,16 +73,16 @@ func checkAndSave(request *http.Request) string {
|
||||
if conf.NotAllowWanAccess {
|
||||
minEntropyBits = 25
|
||||
}
|
||||
err = validatePassword(passwordNew, minEntropyBits)
|
||||
err = passwordvalidator.Validate(passwordNew, minEntropyBits)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
return util.LogStr("密码不安全!尝试使用更长的密码")
|
||||
}
|
||||
}
|
||||
|
||||
dnsConfFromJS := []dnsConf4JS{}
|
||||
err = json.Unmarshal([]byte(request.FormValue("DnsConf")), &dnsConfFromJS)
|
||||
if err != nil {
|
||||
return "解析配置失败,请重试"
|
||||
return "Please refresh the browser and try again"
|
||||
}
|
||||
dnsConfArray := []config.DnsConfig{}
|
||||
empty := dnsConf4JS{}
|
||||
@ -125,7 +130,7 @@ func checkAndSave(request *http.Request) string {
|
||||
// 修改cmd需要验证:必须设置帐号密码
|
||||
if (conf.Username == "" && conf.Password == "") &&
|
||||
(c.Ipv4.Cmd != dnsConf.Ipv4.Cmd || c.Ipv6.Cmd != dnsConf.Ipv6.Cmd) {
|
||||
return "修改 \"通过命令获取\" 必须设置帐号密码,请先设置帐号密码"
|
||||
return util.LogStr("修改 '通过命令获取' 必须设置帐号密码,请先设置帐号密码")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"log"
|
||||
"github.com/jeessy2/ddns-go/v5/util"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -38,6 +38,6 @@ func WebhookTest(writer http.ResponseWriter, request *http.Request) {
|
||||
if url != "" {
|
||||
config.ExecWebhook(fakeDomains, fakeConfig)
|
||||
} else {
|
||||
log.Println("请输入Webhook的URL")
|
||||
util.Log("请输入Webhook的URL")
|
||||
}
|
||||
}
|
||||
|
341
web/writing.html
341
web/writing.html
@ -1,4 +1,4 @@
|
||||
<html lang="zh">
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
@ -32,7 +32,7 @@
|
||||
id="logsBtn"
|
||||
onclick="showHideLogs()"
|
||||
>
|
||||
日志
|
||||
Logs
|
||||
</button>
|
||||
<span
|
||||
class="theme-button gg-dark-mode"
|
||||
@ -47,7 +47,7 @@
|
||||
<div id="mask" onclick="showHideLogs()" style="visibility: hidden"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<div class="row" style="margin-top: 15px">
|
||||
<div class="row" style="margin-top: 15px; margin-bottom: 15px">
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<button class="btn btn-primary submit_btn">Save</button>
|
||||
</div>
|
||||
@ -57,7 +57,7 @@
|
||||
style="margin-left: auto; margin-right: 0"
|
||||
>
|
||||
<form class="form-inline" style="margin-top: 5px">
|
||||
<label for="index" style="margin-left: auto">配置切换:</label>
|
||||
<label for="index" style="margin-left: auto">Config:</label>
|
||||
<select
|
||||
class="form-control form-control-sm"
|
||||
style="margin: 0px 5px; width: 155px"
|
||||
@ -70,14 +70,14 @@
|
||||
style="margin: 0px 5px"
|
||||
id="addBtn"
|
||||
>
|
||||
添加
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-sm"
|
||||
style="margin: 0px 0px 0px 5px"
|
||||
id="delBtn"
|
||||
>
|
||||
删除
|
||||
Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@ -85,7 +85,7 @@
|
||||
|
||||
<form id="formDnsConf">
|
||||
<div class="portlet">
|
||||
<h5 class="portlet__head">DNS服务商</h5>
|
||||
<h5 class="portlet__head" id="dnsProvider">DNS Provider</h5>
|
||||
<div class="portlet__body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label"></label>
|
||||
@ -145,20 +145,19 @@
|
||||
id="ttl"
|
||||
value=""
|
||||
>
|
||||
<option value="" selected>自动</option>
|
||||
<option value="1">1秒</option>
|
||||
<option value="5">5秒</option>
|
||||
<option value="10">10秒</option>
|
||||
<option value="60">1分钟</option>
|
||||
<option value="120">2分钟</option>
|
||||
<option value="600">10分钟</option>
|
||||
<option value="1800">30分钟</option>
|
||||
<option value="3600">1小时</option>
|
||||
<option value="" selected>Auto</option>
|
||||
<option value="1">1s</option>
|
||||
<option value="5">5s</option>
|
||||
<option value="10">10s</option>
|
||||
<option value="60">1m</option>
|
||||
<option value="120">2m</option>
|
||||
<option value="600">10m</option>
|
||||
<option value="1800">30m</option>
|
||||
<option value="3600">1h</option>
|
||||
</select>
|
||||
<small id="ttl_help" class="form-text text-muted"
|
||||
>如账号支持更小的 TTL,可修改。IP 有变化时才会更新
|
||||
TTL</small
|
||||
>
|
||||
<small id="ttl_help" class="form-text text-muted">
|
||||
You can modify it if the account supports a smaller TTL. The TTL will only be updated when the IP changes
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -168,7 +167,7 @@
|
||||
<h5 class="portlet__head">IPv4</h5>
|
||||
<div class="portlet__body">
|
||||
<div class="form-group row">
|
||||
<label for="ipv4_enable" class="col-sm-2">是否启用</label>
|
||||
<label for="ipv4_enable" class="col-sm-2" id="enabled_label">Enabled</label>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -182,9 +181,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="ipv4_url" class="col-sm-2 col-form-label"
|
||||
>获取 IP 方式</label
|
||||
>
|
||||
<label for="ipv4_url" class="col-sm-2 col-form-label" id="getIPMethod_label">
|
||||
Get IP method
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
@ -196,8 +195,11 @@
|
||||
checked
|
||||
onclick="urlClick('ipv4')"
|
||||
/>
|
||||
<label class="form-check-label" for="urlRadioIpv4"
|
||||
>通过接口获取</label
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="urlRadioIpv4"
|
||||
id="urlRadio_label"
|
||||
>By api</label
|
||||
>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
@ -212,7 +214,8 @@
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="netInterfaceRadioIpv4"
|
||||
>通过网卡获取</label
|
||||
id="netInterfaceRadio_label"
|
||||
>By network card</label
|
||||
>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
@ -224,8 +227,11 @@
|
||||
value="cmd"
|
||||
onclick="cmdClick('ipv4')"
|
||||
/>
|
||||
<label class="form-check-label" for="cmdRadioIpv4"
|
||||
>通过命令获取</label
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="cmdRadioIpv4"
|
||||
id="cmdRadio_label"
|
||||
>By command</label
|
||||
>
|
||||
</div>
|
||||
<input
|
||||
@ -251,10 +257,7 @@
|
||||
value=""
|
||||
style="display: none"
|
||||
/>
|
||||
<small id="ipv4_url_help" class="form-text text-muted">
|
||||
支持多个接口,使用半角逗号分隔。如:https://myip4.ipip.net,
|
||||
https://ddns.oray.com/checkip, https://ip.3322.net
|
||||
</small>
|
||||
<small id="ipv4_url_help" class="form-text text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -271,14 +274,7 @@
|
||||
aria-describedby="ipv4_domains_help"
|
||||
></textarea>
|
||||
<small id="ipv4_domains_help" class="form-text text-muted">
|
||||
一行一个域名,
|
||||
可使用冒号分隔根域名(example.cn.eu.org)与子域名(www),
|
||||
填写为:<b>www:example.cn.eu.org</b>
|
||||
<a
|
||||
target="blank"
|
||||
href="https://github.com/jeessy2/ddns-go/wiki/传递自定义参数"
|
||||
>支持传递自定义参数</a
|
||||
>
|
||||
One domain per line, you can use colon to separate the root domain (example.cn.eu.org) and the subdomain (www), fill in as: <b>www:example.cn.eu.org</b>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -289,7 +285,7 @@
|
||||
<h5 class="portlet__head">IPv6</h5>
|
||||
<div class="portlet__body">
|
||||
<div class="form-group row">
|
||||
<label for="ipv6_enable" class="col-sm-2">是否启用</label>
|
||||
<label for="ipv6_enable" class="col-sm-2" id="enabled_label">Enabled</label>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -303,9 +299,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="ipv6_url" class="col-sm-2 col-form-label"
|
||||
>获取 IP 方式</label
|
||||
>
|
||||
<label for="ipv6_url" class="col-sm-2 col-form-label" id="getIPMethod_label">
|
||||
Get IP method
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
@ -317,8 +313,11 @@
|
||||
checked
|
||||
onclick="urlClick('ipv6')"
|
||||
/>
|
||||
<label class="form-check-label" for="urlRadioIpv6"
|
||||
>通过接口获取</label
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="urlRadioIpv6"
|
||||
id="urlRadio_label"
|
||||
>By api</label
|
||||
>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
@ -333,7 +332,8 @@
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="netInterfaceRadioIpv6"
|
||||
>通过网卡获取</label
|
||||
id="netInterfaceRadio_label"
|
||||
>By network card</label
|
||||
>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
@ -345,8 +345,11 @@
|
||||
value="cmd"
|
||||
onclick="cmdClick('ipv6')"
|
||||
/>
|
||||
<label class="form-check-label" for="cmdRadioIpv6"
|
||||
>通过命令获取</label
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="cmdRadioIpv6"
|
||||
id="cmdRadio_label"
|
||||
>By command</label
|
||||
>
|
||||
</div>
|
||||
<input
|
||||
@ -372,10 +375,7 @@
|
||||
value=""
|
||||
style="display: none"
|
||||
/>
|
||||
<small id="ipv6_url_help" class="form-text text-muted">
|
||||
支持多个接口,使用半角逗号分隔。如:https://speed.neu6.edu.cn/getIP.php,
|
||||
https://v6.ident.me, https://6.ipw.cn
|
||||
</small>
|
||||
<small id="ipv6_url_help" class="form-text text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -384,8 +384,11 @@
|
||||
id="IPv6RegDiv"
|
||||
style="display: none"
|
||||
>
|
||||
<label for="IPv6Reg" class="col-sm-2 col-form-label"
|
||||
>匹配正则表达式</label
|
||||
<label
|
||||
for="IPv6Reg"
|
||||
class="col-sm-2 col-form-label"
|
||||
id="IPv6RegDivLabel"
|
||||
>Regular exp.</label
|
||||
>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
@ -393,11 +396,14 @@
|
||||
name="IPv6Reg"
|
||||
id="IPv6Reg"
|
||||
value=""
|
||||
aria-describedby="IPv6Reg_help"
|
||||
aria-describedby="IPv6Reg_label"
|
||||
/>
|
||||
<small id="IPv6Reg_help" class="form-text text-muted"
|
||||
>可使用 @1 指定第一个IPv6地址, @2 指定第二个IPv6地址...
|
||||
也可使用正则表达式匹配指定的IPv6地址, 留空不启用</small
|
||||
<small
|
||||
id="IPv6Reg_label"
|
||||
class="form-text text-muted"
|
||||
>You can use @1 to specify the first IPv6 address, @2 to specify the second IPv6 address...
|
||||
You can also use regular expressions to match the specified IPv6 address,
|
||||
leave it blank to disable it</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@ -415,14 +421,7 @@
|
||||
aria-describedby="ipv6_domains_help"
|
||||
></textarea>
|
||||
<small id="ipv6_domains_help" class="form-text text-muted">
|
||||
一行一个域名,
|
||||
可使用冒号分隔根域名(example.cn.eu.org)与子域名(www),
|
||||
填写为:<b>www:example.cn.eu.org</b>
|
||||
<a
|
||||
target="blank"
|
||||
href="https://github.com/jeessy2/ddns-go/wiki/传递自定义参数"
|
||||
>支持传递自定义参数</a
|
||||
>
|
||||
One domain per line, you can use colon to separate the root domain (example.cn.eu.org) and the subdomain (www), fill in as: <b>www:example.cn.eu.org</b>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -432,11 +431,14 @@
|
||||
|
||||
<form id="formGlobal">
|
||||
<div class="portlet">
|
||||
<h5 class="portlet__head">其它配置</h5>
|
||||
<h5 class="portlet__head">Others</h5>
|
||||
<div class="portlet__body">
|
||||
<div class="form-group row">
|
||||
<label for="NotAllowWanAccess" class="col-sm-2 col-form-label"
|
||||
>禁止公网访问</label
|
||||
<label
|
||||
for="NotAllowWanAccess"
|
||||
class="col-sm-2 col-form-label"
|
||||
id="NotAllowWanAccess_label"
|
||||
>Deny from WAN</label
|
||||
>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
@ -450,14 +452,17 @@
|
||||
<small
|
||||
id="NotAllowWanAccess_help"
|
||||
class="form-text text-muted"
|
||||
>默认启用,可禁止从公网访问本页面</small
|
||||
>Default enabled, can prohibit access to this page from the public network</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="Username" class="col-sm-2 col-form-label"
|
||||
>登录用户名</label
|
||||
<label
|
||||
for="Username"
|
||||
class="col-sm-2 col-form-label"
|
||||
id="UsernameLabel"
|
||||
>Username</label
|
||||
>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
@ -468,14 +473,17 @@
|
||||
aria-describedby="Username_help"
|
||||
/>
|
||||
<small id="Username_help" class="form-text text-muted"
|
||||
>为保护你的信息安全,建议输入</small
|
||||
>Please enter to protect your information security</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="Password" class="col-sm-2 col-form-label"
|
||||
>登录密码</label
|
||||
<label
|
||||
for="Password"
|
||||
class="col-sm-2 col-form-label"
|
||||
id="PasswordLabel"
|
||||
>Password</label
|
||||
>
|
||||
<div class="col-sm-10">
|
||||
<input
|
||||
@ -487,7 +495,7 @@
|
||||
aria-describedby="password_help"
|
||||
/>
|
||||
<small id="password_help" class="form-text text-muted"
|
||||
>为保护你的信息安全,建议输入</small
|
||||
>Please enter to protect your information security</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@ -512,11 +520,10 @@
|
||||
<small id="WebhookURL_help" class="form-text text-muted">
|
||||
<a
|
||||
target="blank"
|
||||
href="https://github.com/jeessy2/ddns-go#webhook"
|
||||
>点击参考官方 Webhook 说明</a
|
||||
href="https://github.com/jeessy2/ddns-go/blob/master/README_EN.md#webhook"
|
||||
>Click to get more info</a
|
||||
><br />
|
||||
支持的变量 #{ipv4Addr}, #{ipv4Result}, #{ipv4Domains},
|
||||
#{ipv6Addr}, #{ipv6Result}, #{ipv6Domains}
|
||||
Support variables #{ipv4Addr}, #{ipv4Result}, #{ipv4Domains}, #{ipv6Addr}, #{ipv6Result}, #{ipv6Domains}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -539,8 +546,7 @@
|
||||
id="WebhookRequestBody_help"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
如 RequestBody 为空则为 GET 请求,否则为 POST
|
||||
请求。支持的变量同上
|
||||
If RequestBody is empty, it is a GET request, otherwise it is a POST request. Supported variables are the same as above
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -561,7 +567,7 @@
|
||||
id="WebhookHeaders_help"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
一行一个Header, 如:Authorization: Bearer API_KEY
|
||||
One header per line, such as: Authorization: Bearer API_KEY
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@ -574,7 +580,7 @@
|
||||
id="webhookTestBtn"
|
||||
aria-describedby="webhookTestBtn_help"
|
||||
>
|
||||
模拟测试Webhook
|
||||
Try it
|
||||
</button>
|
||||
<small
|
||||
id="webhookTestBtn_help"
|
||||
@ -596,7 +602,7 @@
|
||||
<div class="logs-panel col-md-6 offset-md-3" style="visibility: hidden">
|
||||
<textarea class="logs form-control" id="logs" readonly></textarea>
|
||||
<button type="button" class="btn btn-danger btn-sm" id="clearLogBtn">
|
||||
清空
|
||||
Clear
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -604,28 +610,36 @@
|
||||
onclick="showHideLogs()"
|
||||
style="float: right"
|
||||
>
|
||||
确认
|
||||
OK
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
// 是否为中文
|
||||
const isZH = navigator.language?.toLowerCase().startsWith("zh")
|
||||
</script>
|
||||
<script>
|
||||
const dnsProviders = [
|
||||
{
|
||||
name: "Alidns(阿里云)",
|
||||
name: isZH ? "阿里云": "Aliyun",
|
||||
id: "alidns",
|
||||
idLabel: "AccessKey ID",
|
||||
secretLabel: "AccessKey Secret",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://ram.console.aliyun.com/manage/ak?spm=5176.12818093.nav-right.dak.488716d0mHaMgg'>创建 AccessKey</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://ram.console.aliyun.com/manage/ak?spm=5176.12818093.nav-right.dak.488716d0mHaMgg'>创建 AccessKey</a>"
|
||||
: "<a target='_blank' href='https://ram.console.aliyun.com/manage/ak?spm=5176.12818093.nav-right.dak.488716d0mHaMgg'>Create AccessKey</a>"
|
||||
},
|
||||
{
|
||||
name: "腾讯云",
|
||||
name: isZH ? "腾讯云": "Tencent",
|
||||
id: "tencentcloud",
|
||||
idLabel: "SecretId",
|
||||
secretLabel: "SecretKey",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://console.dnspod.cn/account/token/apikey'>创建腾讯云 API 密钥</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://console.dnspod.cn/account/token/apikey'>创建腾讯云 API 密钥</a>"
|
||||
: "<a target='_blank' href='https://console.dnspod.cn/account/token/apikey'>Create AccessKey</a>"
|
||||
},
|
||||
{
|
||||
name: "DnsPod",
|
||||
@ -641,15 +655,19 @@
|
||||
idLabel: "",
|
||||
secretLabel: "Token",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://dash.cloudflare.com/profile/api-tokens'>创建令牌->编辑区域 DNS (使用模板)</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://dash.cloudflare.com/profile/api-tokens'>创建令牌 -> 编辑区域 DNS (使用模板)</a>"
|
||||
: "<a target='_blank' href='https://dash.cloudflare.com/profile/api-tokens'>Create Token -> Edit Zone DNS (Use template)</a>"
|
||||
},
|
||||
{
|
||||
name: "华为云",
|
||||
name: isZH ? "华为云": "Huawei",
|
||||
id: "huaweicloud",
|
||||
idLabel: "Access Key Id",
|
||||
secretLabel: "Secret Access Key",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://console.huaweicloud.com/iam/?locale=zh-cn#/mine/accessKey'>新增访问密钥</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://console.huaweicloud.com/iam/?locale=zh-cn#/mine/accessKey'>新增访问密钥</a>"
|
||||
: "<a target='_blank' href='https://console.huaweicloud.com/iam/?locale=zh-cn#/mine/accessKey'>Create</a>"
|
||||
},
|
||||
{
|
||||
name: "Callback",
|
||||
@ -657,10 +675,12 @@
|
||||
idLabel: "URL",
|
||||
secretLabel: "RequestBody",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://github.com/jeessy2/ddns-go#callback'>自定义回调</a> 支持的变量 #{ip}, #{domain}, #{recordType}, #{ttl}",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://github.com/jeessy2/ddns-go#callback'>自定义回调</a> 支持的变量 #{ip}, #{domain}, #{recordType}, #{ttl}"
|
||||
: "<a target='_blank' href='https://github.com/jeessy2/ddns-go/blob/master/README_EN.md#callback'>Callback</a> Support variables #{ip}, #{domain}, #{recordType}, #{ttl}"
|
||||
},
|
||||
{
|
||||
name: "百度云",
|
||||
name: isZH ? "百度云": "Baidu",
|
||||
id: "baiducloud",
|
||||
idLabel: "AccessKey ID",
|
||||
secretLabel: "AccessKey Secret",
|
||||
@ -673,7 +693,9 @@
|
||||
idLabel: "API Key",
|
||||
secretLabel: "Secret Key",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://porkbun.com/account/api'>创建 Access</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://porkbun.com/account/api'>创建 Access</a>"
|
||||
: "<a target='_blank' href='https://porkbun.com/account/api'>Create Access</a>"
|
||||
},
|
||||
{
|
||||
name: "GoDaddy",
|
||||
@ -681,7 +703,9 @@
|
||||
idLabel: "Key",
|
||||
secretLabel: "Secret",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://developer.godaddy.com/keys'>创建 API KEY</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://developer.godaddy.com/keys'>创建 API KEY</a>"
|
||||
: "<a target='_blank' href='https://porkbun.com/account/api'>Create API KEY</a>"
|
||||
},
|
||||
{
|
||||
name: "Google Domain",
|
||||
@ -689,7 +713,9 @@
|
||||
idLabel: "Username",
|
||||
secretLabel: "Password",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://support.google.com/domains/answer/6147083?hl=zh-Hans'>新建动态域名解析记录</a>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://support.google.com/domains/answer/6147083?hl=zh-Hans'>新建动态域名解析记录</a>"
|
||||
: "<a target='_blank' href='https://support.google.com/domains/answer/6147083?hl=en'>How to get started</a>"
|
||||
},
|
||||
{
|
||||
name: "Namecheap",
|
||||
@ -697,7 +723,9 @@
|
||||
idLabel: "",
|
||||
secretLabel: "Password",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://www.namecheap.com/support/knowledgebase/article.aspx/36/11/how-do-i-start-using-dynamic-dns/'>开启namecheap动态域名解析</a> <span style='color: red'>Namecheap DDNS 不支持更新 IPv6</span>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://www.namecheap.com/support/knowledgebase/article.aspx/36/11/how-do-i-start-using-dynamic-dns/'>开启namecheap动态域名解析</a> <span style='color: red'>Namecheap DDNS 不支持更新 IPv6</span>"
|
||||
: "<a target='_blank' href='https://www.namecheap.com/support/knowledgebase/article.aspx/36/11/how-do-i-start-using-dynamic-dns/'>How to get started</a> <span style='color: red'>Namecheap DDNS does not support updating IPv6</span>"
|
||||
},
|
||||
{
|
||||
name: "NameSilo",
|
||||
@ -705,7 +733,9 @@
|
||||
idLabel: "",
|
||||
secretLabel: "Password",
|
||||
helpHtml:
|
||||
"<a target='_blank' href='https://www.namesilo.com/account/api-manager'>开启namesilo动态域名解析</a> <b>请注意namesilo的TTL最低1小时</b>",
|
||||
isZH
|
||||
? "<a target='_blank' href='https://www.namesilo.com/account/api-manager'>开启namesilo动态域名解析</a> <b>请注意namesilo的TTL最低1小时</b>"
|
||||
: "<a target='_blank' href='https://www.namesilo.com/account/api-manager'>How to get started</a> <b>Please note that the TTL of namesilo is at least 1 hour</b>"
|
||||
},
|
||||
];
|
||||
let DnsSelectorInnerHTML = "";
|
||||
@ -736,13 +766,17 @@
|
||||
Ipv4Enable: "on",
|
||||
Ipv4GetType: "url",
|
||||
Ipv4Url:
|
||||
"https://myip4.ipip.net,https://ddns.oray.com/checkip,https://ip.3322.net,https://4.ipw.cn",
|
||||
isZH
|
||||
? "https://myip4.ipip.net, https://ddns.oray.com/checkip, https://ip.3322.net, https://4.ipw.cn"
|
||||
: "https://api.ipify.org, https://ddns.oray.com/checkip, https://ip.3322.net, https://4.ipw.cn",
|
||||
Ipv4Cmd: "",
|
||||
Ipv4Domains: "",
|
||||
Ipv6Enable: "on",
|
||||
Ipv6GetType: "netInterface",
|
||||
Ipv6Url:
|
||||
"https://speed.neu6.edu.cn/getIP.php,https://v6.ident.me,https://6.ipw.cn",
|
||||
isZH
|
||||
? "https://speed.neu6.edu.cn/getIP.php, https://v6.ident.me, https://6.ipw.cn"
|
||||
: "https://api64.ipify.org, https://speed.neu6.edu.cn/getIP.php, https://v6.ident.me, https://6.ipw.cn",
|
||||
Ipv6Cmd: "",
|
||||
IPv6Reg: "",
|
||||
Ipv6Domains: "",
|
||||
@ -829,7 +863,7 @@
|
||||
e.preventDefault();
|
||||
document.getElementById("index_" + index).disabled = true;
|
||||
document.getElementById("index_" + index).text =
|
||||
index + 1 + " - 已删除";
|
||||
index + 1 + " - Deleted";
|
||||
dnsConf[index] = null;
|
||||
index = dnsConf.length - 1;
|
||||
for (; dnsConf[index] == null && index >= 0; index--) {}
|
||||
@ -895,7 +929,7 @@
|
||||
try {
|
||||
dnsConf = JSON.parse(jsonConf);
|
||||
} catch (e) {
|
||||
alert("解析配置失败: " + e.toString());
|
||||
alert("error: " + e.toString());
|
||||
return;
|
||||
}
|
||||
const selectOld = document.getElementById("index");
|
||||
@ -953,7 +987,7 @@
|
||||
});
|
||||
} else {
|
||||
showMessage({
|
||||
content: "保存成功",
|
||||
content: isZH ? "保存成功" : "Successfully saved",
|
||||
type: "success",
|
||||
duration: 1500,
|
||||
});
|
||||
@ -961,7 +995,7 @@
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
alert(`保存失败: ${err.toString()}`);
|
||||
alert(`${err.toString()}`);
|
||||
});
|
||||
})
|
||||
);
|
||||
@ -976,9 +1010,7 @@
|
||||
const logsList = JSON.parse(result);
|
||||
const logsDom = document.getElementById("logs");
|
||||
// 判断滚动条是否在底部
|
||||
const isBottom =
|
||||
logsDom.scrollHeight - logsDom.scrollTop - logsDom.clientHeight <
|
||||
10;
|
||||
const isBottom = logsDom.scrollHeight - logsDom.scrollTop - logsDom.clientHeight < 10;
|
||||
logsDom.value = logsList.join("");
|
||||
// 如果滚动条原先在底部,滚动到底部
|
||||
if (isBottom) {
|
||||
@ -996,8 +1028,7 @@
|
||||
// 如果日志有更新且当前未读到,增加未读标记
|
||||
if (
|
||||
newLogsList.length &&
|
||||
document.querySelector(".logs-panel").style.visibility ===
|
||||
"hidden"
|
||||
document.querySelector(".logs-panel").style.visibility === "hidden"
|
||||
) {
|
||||
document.getElementById("logsBtn").classList.add("unread"); // 没有分号会导致和下面合并为同一个语句
|
||||
// 如果新增日志行数小于等于3,则message显示新增日志,否则显示前2行并提示剩余行数
|
||||
@ -1020,7 +1051,7 @@
|
||||
}
|
||||
showMessage({
|
||||
type: "info",
|
||||
content: `剩余${newLogsList.length - 2}条日志请自行查看`,
|
||||
content: isZH ? `剩余${newLogsList.length - 2}条日志请自行查看` : `There are ${newLogsList.length - 2} logs left, please check by yourself`,
|
||||
});
|
||||
}
|
||||
})();
|
||||
@ -1065,10 +1096,10 @@
|
||||
|
||||
if (label === "ipv4") {
|
||||
document.getElementById("ipv4_url_help").innerText =
|
||||
"支持多个接口,使用半角逗号分隔。如:https://myip4.ipip.net, https://ddns.oray.com/checkip, https://ip.3322.net";
|
||||
"https://myip4.ipip.net, https://ddns.oray.com/checkip, https://ip.3322.net";
|
||||
} else {
|
||||
document.getElementById("ipv6_url_help").innerText =
|
||||
"支持多个接口,使用半角逗号分隔。如:https://speed.neu6.edu.cn/getIP.php, https://v6.ident.me, https://6.ipw.cn";
|
||||
"https://speed.neu6.edu.cn/getIP.php, https://v6.ident.me, https://6.ipw.cn";
|
||||
document.getElementById("IPv6RegDiv").style.display = "none";
|
||||
}
|
||||
}
|
||||
@ -1078,10 +1109,14 @@
|
||||
displayElement(label, "netInterface_select");
|
||||
if (label === "ipv4") {
|
||||
document.getElementById("ipv4_url_help").innerText =
|
||||
"通过网卡获取 IP,建议在多宽带的路由器中使用";
|
||||
isZH
|
||||
? "通过网卡获取IPv4"
|
||||
: "Get IPv4 address through network card";
|
||||
} else {
|
||||
document.getElementById("ipv6_url_help").innerText =
|
||||
"通过网卡获取 IP,如不指定匹配正则表达式,将默认使用第一个 IPv6 地址";
|
||||
isZH
|
||||
? "如不指定匹配正则表达式,将默认使用第一个 IPv6 地址"
|
||||
: "If you do not specify a matching regular expression, the first IPv6 address will be used by default";
|
||||
document.getElementById("IPv6RegDiv").removeAttribute("style");
|
||||
}
|
||||
|
||||
@ -1125,27 +1160,30 @@
|
||||
}
|
||||
} else {
|
||||
document.getElementById(`${label}_url_help`).innerHTML =
|
||||
'<span style="color: red">没有找到可用的网卡</span>';
|
||||
isZH ? '<span style="color: red">没有找到可用的网卡</span>': '<span style="color: red">No available network card found</span>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 通过命令获取
|
||||
function cmdClick(label) {
|
||||
const warning = "警告:执行的命令拥有本服务所具有的权限,请谨慎使用!";
|
||||
displayElement(label, "cmd");
|
||||
if (label === "ipv4") {
|
||||
document.getElementById("ipv4_url_help").innerHTML = `<p>
|
||||
通过命令获取 IP,仅使用标准输出(stdout)的第一个匹配的 IPv4 地址。如:ip -4 addr show eth1
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考">点击参考更多</a>
|
||||
<br /><strong>${warning}</strong>
|
||||
</p>`;
|
||||
document.getElementById("ipv4_url_help").innerHTML =
|
||||
isZH
|
||||
? `<p>
|
||||
通过命令获取IPv4, 仅使用标准输出(stdout)的第一个匹配的 IPv4 地址。如: ip -4 addr show eth1
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考">点击参考更多</a>
|
||||
</p>`
|
||||
: `Get IPv4 through command, only use the first matching IPv4 address of standard output(stdout). Such as: ip -4 addr show eth1`;
|
||||
} else {
|
||||
document.getElementById("ipv6_url_help").innerHTML = `<p>
|
||||
通过命令获取 IP,仅使用标准输出(stdout)的第一个匹配的 IPv6 地址。如:ip -6 addr show eth1
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考">点击参考更多</a>
|
||||
<br /><strong>${warning}</strong>
|
||||
</p>`;
|
||||
document.getElementById("ipv6_url_help").innerHTML =
|
||||
isZH
|
||||
? `<p>
|
||||
通过命令获取IPv6, 仅使用标准输出(stdout)的第一个匹配的 IPv6 地址。如: ip -6 addr show eth1
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考">点击参考更多</a>
|
||||
</p>`
|
||||
: `Get IPv6 through command, only use the first matching IPv6 address of standard output(stdout). Such as: ip -6 addr show eth1`;
|
||||
document.getElementById("IPv6RegDiv").style.display = "none";
|
||||
}
|
||||
}
|
||||
@ -1185,7 +1223,9 @@
|
||||
"webhookTestBtn_help"
|
||||
);
|
||||
webhookTestBtnHelp.innerText =
|
||||
"提交模拟测试成功! 数据为假数据, 只是为了测试Webhook正常与否";
|
||||
isZH
|
||||
? "提交模拟测试成功! 数据为假数据, 只是为了测试Webhook正常与否"
|
||||
: "Submit simulation test successfully! The data is fake data, just to test whether the Webhook is normal or not";
|
||||
setTimeout(() => {
|
||||
webhookTestBtnHelp.innerText = "";
|
||||
}, 5000);
|
||||
@ -1223,5 +1263,44 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
if (isZH) {
|
||||
// 改写标签为中文
|
||||
document.getElementById("dnsProvider").innerHTML = "DNS 服务商"
|
||||
document.getElementById("ttl_help").innerHTML = "如账号支持更小的 TTL, 可修改。IP 有变化时才会更新TTL"
|
||||
|
||||
document.querySelectorAll("#enabled_label").forEach(item => item.innerHTML = "是否启用")
|
||||
document.querySelectorAll("#getIPMethod_label").forEach(item => item.innerHTML = "获取 IP 方式")
|
||||
document.querySelectorAll("#urlRadio_label").forEach(item => item.innerHTML = "通过接口获取")
|
||||
document.querySelectorAll("#netInterfaceRadio_label").forEach(item => item.innerHTML = "通过网卡获取")
|
||||
document.querySelectorAll("#cmdRadio_label").forEach(item => item.innerHTML = "通过命令获取")
|
||||
document.getElementById("ipv4_domains_help").innerHTML = `
|
||||
<p>
|
||||
一行一个域名, 可使用冒号分隔根域名(example.cn.eu.org)与子域名(www), 填写为:<b>www:example.cn.eu.org</b>
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go/wiki/传递自定义参数">支持传递自定义参数</a>
|
||||
</p>
|
||||
`;
|
||||
document.getElementById("ipv6_domains_help").innerHTML = document.getElementById("ipv4_domains_help").innerHTML;
|
||||
|
||||
document.getElementById("IPv6RegDivLabel").innerText = "匹配正则表达式";
|
||||
document.getElementById("IPv6Reg_label").innerText = "可使用 @1 指定第一个IPv6地址, @2 指定第二个IPv6地址... 也可使用正则表达式匹配指定的IPv6地址, 留空不启用";
|
||||
document.getElementById("NotAllowWanAccess_label").innerText = "禁止公网访问";
|
||||
document.getElementById("NotAllowWanAccess_help").innerText = "默认启用,可禁止从公网访问本页面";
|
||||
document.getElementById("UsernameLabel").innerText = "用户名";
|
||||
document.getElementById("PasswordLabel").innerText = "密码";
|
||||
document.getElementById("Username_help").innerText = "为保护你的信息安全,建议输入";
|
||||
document.getElementById("password_help").innerText = "为保护你的信息安全,建议输入";
|
||||
|
||||
document.getElementById("WebhookURL_help").innerHTML = `
|
||||
<a target="blank" href="https://github.com/jeessy2/ddns-go#webhook">点击参考官方 Webhook 说明</a>
|
||||
<br />
|
||||
支持的变量 #{ipv4Addr}, #{ipv4Result}, #{ipv4Domains}, #{ipv6Addr}, #{ipv6Result}, #{ipv6Domains}
|
||||
`
|
||||
document.getElementById("WebhookRequestBody_help").innerText = "如 RequestBody 为空则为 GET 请求,否则为 POST 请求。支持的变量同上"
|
||||
document.getElementById("WebhookHeaders_help").innerText = "一行一个Header, 如: Authorization: Bearer API_KEY"
|
||||
document.getElementById("webhookTestBtn").innerText = "模拟测试Webhook"
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user