diff --git a/.build/ddns.spec b/.build/ddns.spec
index 5a58016..dd997d6 100644
--- a/.build/ddns.spec
+++ b/.build/ddns.spec
@@ -21,7 +21,8 @@ a = Analysis(['../run.py'],
'dns.dnspod_com',
'dns.dnscom',
'dns.cloudflare',
- 'dns.huaweidns'
+ 'dns.huaweidns',
+ 'dns.callback'
],
hookspath=[],
runtime_hooks=[],
diff --git a/README.md b/README.md
index c1e2204..487c52e 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@
- [x] 可设置定时任务
- [x] TTL 配置支持
- [x] 本地文件缓存(减少 API 请求)
+ - [x] 地址变更时触发自定义回调API(与 DDNS 功能互斥)
## 使用
@@ -83,6 +84,7 @@
- [CloudFlare API Key](https://support.cloudflare.com/hc/en-us/articles/200167836-Where-do-I-find-my-Cloudflare-API-key-) (除了`email + API KEY`,也可使用`Token`需要列出 Zone 权限)
- [HE.net DDNS 文档](https://dns.he.net/docs.html)(仅需将设置的密码填入`token`字段,`id`字段可留空)
- [华为 APIKEY 申请](https://console.huaweicloud.com/iam/)(点左边访问密钥,然后点新增访问密钥)
+ - 自定义回调的参数填写方式请查看下方的自定义回调配置说明
2. 修改配置文件,`ipv4`和`ipv6`字段,为待更新的域名,详细参照配置说明
@@ -109,7 +111,7 @@ python run.py -c /path/to/config.json
| :----: | :---------: | :------: | :---------: | :---------------: | ----------------------------------------------------------------------------------------------------------- |
| id | string | √ | 无 | api 访问 ID | Cloudflare 为邮箱(使用 Token 时留空)
HE.net 可留空 |
| token | string | √ | 无 | api 授权 token | 部分平台叫 secret key , **反馈粘贴时删除** |
-| dns | string | No | `"dnspod"` | dns 服务商 | 阿里`alidns`,
dns.com 为`dnscom`,
DNSPOD 国际版`dnspod_com`,
HE.net 为`he`,华为 DNS 为`huaweidns` |
+| dns | string | No | `"dnspod"` | dns 服务商 | 阿里`alidns`,
dns.com 为`dnscom`,
DNSPOD 国际版`dnspod_com`,
HE.net 为`he`,华为 DNS 为`huaweidns`,
自定义回调为`callback` |
| ipv4 | array | No | `[]` | ipv4 域名列表 | 为`[]`时,不会获取和更新 IPv4 地址 |
| ipv6 | array | No | `[]` | ipv6 域名列表 | 为`[]`时,不会获取和更新 IPv6 地址 |
| index4 | string\|int | No | `"default"` | ipv4 获取方式 | 可设置`网卡`,`内网`,`公网`,`正则`等方式 |
@@ -133,6 +135,19 @@ python run.py -c /path/to/config.json
- 字符串`"shell:xxx"`: 使用系统 shell 运行`xxx`,并把结果 stdout 作为目标 IP
- `false`: 强制禁止更新 ipv4 或 ipv6 的 DNS 解析
+#### 自定义回调配置说明
+
+- `id` 字段填写回调地址,以 HTTP 或 HTTPS 开头,推荐采用 HTTPS 方式的回调 API ,当 `token` 字段非空且 URL 参数包含下表所示的常量字符串时,常量会被程序替换为实际值
+- `token` 字段为 POST 参数,本字段为空或不存在则使用 GET 方式发起回调,回调参数采用 JSON 格式编码,当 JSON 的首层参数值包含下表所示的常量字符串时,常量会被程序替换为实际值
+
+| 常量名称 | 常量内容 | 说明 |
+| ---------------- | ---------------------- | -------- |
+| `__DOMAIN__` | DDNS 域名 | |
+| `__RECORDTYPE__` | DDNS 记录类型 | |
+| `__TTL__` | DDNS TTL | |
+| `__TIMESTAMP__` | 请求发起时间戳 | 包含小数 |
+| `__IP__` | 获取的对应类型的IP地址 | |
+
#### 配置示例
```json
@@ -140,7 +155,7 @@ python run.py -c /path/to/config.json
"$schema": "https://ddns.newfuture.cc/schema/v2.8.json",
"id": "12345",
"token": "mytokenkey",
- "dns": "dnspod 或 dnspod_com 或 alidns 或 dnscom 或 cloudflare 或 he 或 huaweidns",
+ "dns": "dnspod 或 dnspod_com 或 alidns 或 dnscom 或 cloudflare 或 he 或 huaweidns 或 callback",
"ipv4": ["ddns.newfuture.cc", "ipv4.ddns.newfuture.cc"],
"ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"],
"index4": 0,
diff --git a/dns/callback.py b/dns/callback.py
new file mode 100644
index 0000000..57f55f6
--- /dev/null
+++ b/dns/callback.py
@@ -0,0 +1,113 @@
+# coding=utf-8
+"""
+Custom Callback API
+自定义回调接口解析操作库
+
+@author: 老周部落
+"""
+
+from json import loads as jsondecode, dumps as jsonencode
+from logging import debug, info, warning
+from time import time
+
+try:
+ # python 2
+ from httplib import HTTPSConnection, HTTPConnection
+ from urlparse import urlparse, parse_qsl
+ from urllib import urlencode
+except ImportError:
+ # python 3
+ from http.client import HTTPSConnection, HTTPConnection
+ from urllib.parse import urlencode, urlparse, parse_qsl
+
+__author__ = '老周部落'
+
+class Config:
+ ID = None # 自定义回调 URL
+ TOKEN = None # 使用 JSON 编码的 POST 参数
+ PROXY = None # 代理设置
+ TTL = None
+
+def request(method, action, param=None, **params):
+ """
+ 发送请求数据
+ """
+ if param:
+ params.update(param)
+
+ URLObj = urlparse(Config.ID)
+ params = dict((k, params[k]) for k in params if params[k] is not None)
+ info("%s/%s : %s", URLObj.netloc, action, params)
+
+ if Config.PROXY:
+ if URLObj.netloc == "http":
+ conn = HTTPConnection(Config.PROXY)
+ else:
+ conn = HTTPSConnection(Config.PROXY)
+ conn.set_tunnel(URLObj.netloc, URLObj.port)
+ else:
+ if URLObj.netloc == "http":
+ conn = HTTPConnection(URLObj.netloc, URLObj.port)
+ else:
+ conn = HTTPSConnection(URLObj.netloc, URLObj.port)
+
+ headers = {}
+
+ if method == "GET":
+ if params:
+ action += '?' + urlencode(params)
+ params = ""
+ else:
+ headers["Content-Type"] = "application/x-www-form-urlencoded"
+
+ params = urlencode(params)
+
+ conn.request(method, action, params, headers)
+ response = conn.getresponse()
+ res = response.read().decode('utf8')
+ conn.close()
+ if response.status < 200 or response.status >= 300:
+ warning('%s : error[%d]:%s', action, response.status, res)
+ raise Exception(res)
+ else:
+ debug('%s : result:%s', action, res)
+ return data
+
+def replace_params(domain, record_type, ip, params):
+ """
+ 替换定义常量为实际值
+ """
+ dict = {"__DOMAIN__": domain, "__RECORDTYPE__": record_type, "__TTL__": Config.TTL, "__TIMESTAMP__": time(), "__IP__": ip}
+ for key, value in params.items():
+ if dict.get(value):
+ params[key] = dict.get(value)
+ return params
+
+def update_record(domain, value, record_type="A"):
+ """
+ 更新记录
+ """
+ info(">>>>>%s(%s)", domain, record_type)
+
+ result = {}
+
+ if not Config.TOKEN: # 此处使用 TOKEN 参数透传 POST 参数所用的 JSON
+ method = "GET"
+ URLObj = urlparse(Config.ID)
+ path = URLObj.path
+ query = dict(parse_qsl(URLObj.query))
+ params = replace_params(domain, record_type, value, query)
+ else:
+ method = "POST"
+ URLObj = urlparse(Config.ID)
+ path = URLObj.path
+ params = replace_params(domain, record_type, value, jsondecode(Config.TOKEN))
+
+ res = request(method, path, params)
+
+ if res:
+ result = "Callback Request Success!\n" + res
+ else:
+ result = "Callback Request Fail!\n"
+
+ return result
diff --git a/schema/v2.8.json b/schema/v2.8.json
index c2cdf8a..aad3a2c 100644
--- a/schema/v2.8.json
+++ b/schema/v2.8.json
@@ -34,7 +34,7 @@
"$id": "/properties/dns",
"type": "string",
"title": "DNS Provider",
- "description": "dns服务商:阿里为alidns,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,HE.net为he",
+ "description": "dns服务商:阿里为alidns,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,HE.net为he,华为DNS为huaweidns,自定义回调为callback",
"default": "dnspod",
"examples": [
"dnspod",
@@ -48,7 +48,8 @@
"dnspod_com",
"dnscom",
"he",
- "huaweidns"
+ "huaweidns",
+ "callback"
]
},
"ipv4": {