Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/email #172

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
config.*.json

.idea
.vscode
*.temp

Expand Down
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,24 @@ python run.py -c /path/to/config.json

#### 配置参数表

| key | type | required | default | description | tips |
| :----: | :---------: | :------: | :---------: | :---------------: | ----------------------------------------------------------------------------------------------------------- |
| id | string | √ | 无 | api 访问 ID | Cloudflare 为邮箱(使用 Token 时留空)<br>HE.net 可留空 |
| token | string | √ | 无 | api 授权 token | 部分平台叫 secret key , **反馈粘贴时删除** |
| dns | string | No | `"dnspod"` | dns 服务商 | 阿里`alidns`,<br>dns.com 为`dnscom`,<br>DNSPOD 国际版`dnspod_com`,<br>HE.net 为`he`,华为 DNS 为`huaweidns` |
| ipv4 | array | No | `[]` | ipv4 域名列表 | 为`[]`时,不会获取和更新 IPv4 地址 |
| ipv6 | array | No | `[]` | ipv6 域名列表 | 为`[]`时,不会获取和更新 IPv6 地址 |
| index4 | string\|int | No | `"default"` | ipv4 获取方式 | 可设置`网卡`,`内网`,`公网`,`正则`等方式 |
| index6 | string\|int | No | `"default"` | ipv6 获取方式 | 可设置`网卡`,`内网`,`公网`,`正则`等方式 |
| ttl | number | No | `null` | DNS 解析 TTL 时间 | 不设置采用 DNS 默认策略 |
| proxy | string | No | 无 | http 代理`;`分割 | 多代理逐个尝试直到成功,`DIRECT`为直连 |
| debug | bool | No | `false` | 是否开启调试 | 运行异常时,打开调试输出,方便诊断错误 |
| cache | bool | No | `true` | 是否缓存记录 | 正常情况打开避免频繁更新 |
| key | type | required | default | description | tips |
| :----------: | :---------: | :------: | :---------: | :---------------: | ----------------------------------------------------------------------------------------------------------- |
| id | string | √ | 无 | api 访问 ID | Cloudflare 为邮箱(使用 Token 时留空)<br>HE.net 可留空 |
| token | string | √ | 无 | api 授权 token | 部分平台叫 secret key , **反馈粘贴时删除** |
| dns | string | No | `"dnspod"` | dns 服务商 | 阿里`alidns`,<br>dns.com 为`dnscom`,<br>DNSPOD 国际版`dnspod_com`,<br>HE.net 为`he`,华为 DNS 为`huaweidns` |
| ipv4 | array | No | `[]` | ipv4 域名列表 | 为`[]`时,不会获取和更新 IPv4 地址 |
| ipv6 | array | No | `[]` | ipv6 域名列表 | 为`[]`时,不会获取和更新 IPv6 地址 |
| index4 | string\|int | No | `"default"` | ipv4 获取方式 | 可设置`网卡`,`内网`,`公网`,`正则`等方式 |
| index6 | string\|int | No | `"default"` | ipv6 获取方式 | 可设置`网卡`,`内网`,`公网`,`正则`等方式 |
| ttl | number | No | `null` | DNS 解析 TTL 时间 | 不设置采用 DNS 默认策略 |
| proxy | string | No | 无 | http 代理`;`分割 | 多代理逐个尝试直到成功,`DIRECT`为直连 |
| debug | bool | No | `false` | 是否开启调试 | 运行异常时,打开调试输出,方便诊断错误 |
| cache | bool | No | `true` | 是否缓存记录 | 正常情况打开避免频繁更新 |
| smtpHost | string | No | 无 | SMTP 服务器 | 如 163.smtp.com |
| smtpPort | int | No | 25 | SMTP 端口 | 正常情况打开避免频繁更新 |
| smtpUser | string | No | 无 | 邮箱 用户 | xxx@163.com |
| smtpPassword | string | No | 无 | 密码 | 邮箱密码或授权码 |
| smtpAddrs | array | No | 无 | 收件人 | 为`[]`时,不发送邮件 |

#### index4 和 index6 参数说明

Expand Down
55 changes: 47 additions & 8 deletions run.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
# -*- coding:utf-8 -*-
"""
DDNS
Expand All @@ -13,10 +13,11 @@
from tempfile import gettempdir
from logging import DEBUG, basicConfig, info, warning, error
from subprocess import check_output
import time

import sys

from util import ip
from util import ip, mail
from util.cache import Cache

__version__ = "${BUILD_SOURCEBRANCHNAME}@${BUILD_DATE}" # CI 时会被Tag替换
Expand All @@ -36,6 +37,11 @@
getattr(sys, '_MEIPASS'), 'lib', 'cert.pem')

CACHE_FILE = path.join(gettempdir(), 'ddns.cache')
log_rows = []


def time_str():
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))


def get_config(key=None, default=None, path="config.json"):
Expand Down Expand Up @@ -68,6 +74,11 @@ def get_config(key=None, default=None, path="config.json"):
"ttl": None,
"proxy": None,
"debug": False,
"smtpHost": None,
"smtpPort": None,
"smtpUser": None,
"smtpPassword": None,
"smtpAddrs": None
}
dumpjson(configure, configfile, indent=2, sort_keys=True)
sys.exit("New template configure file `%s` is generated." % path)
Expand Down Expand Up @@ -112,8 +123,8 @@ def change_dns_record(dns, proxy_list, **kw):
else:
dns.PROXY = proxy
record_type, domain = kw['record_type'], kw['domain']
print('\n%s(%s) ==> %s [via %s]' %
(domain, record_type, kw['ip'], proxy))
log = '%s - %s(%s) ==> %s [via %s]' % (time_str(), domain, record_type, kw['ip'], proxy)
print(log, end='\n')
try:
return dns.update_record(domain, kw['ip'], record_type=record_type)
except Exception as e:
Expand All @@ -131,21 +142,48 @@ def update_ip(ip_type, cache, dns, proxy_list):
return None
address = get_ip(ip_type)
if not address:
error('Fail to get %s address!' ,ipname)
error('Fail to get %s address!', ipname)
return False
elif cache and (address == cache[ipname]):
print('.', end=" ") # 缓存命中
print('%s - %s cached' % (time_str(), address), end='\n') # 缓存命中
return True
record_type = (ip_type == '4') and 'A' or 'AAAA'
update_fail = False # https://github.com/NewFuture/DDNS/issues/16
for domain in domains:
if change_dns_record(dns, proxy_list, domain=domain, ip=address, record_type=record_type):
result = change_dns_record(dns, proxy_list, domain=domain, ip=address, record_type=record_type)
if result:
update_fail = True
log_rows.append(
'<span>%s </span><span>- <span style="color: green">SET </span> %s(%s) -> %s [via %s]</span>' % (
time_str(), domain, record_type, address, get_config('proxy')))

if cache is not False:
# 如果更新失败删除缓存
cache[ipname] = update_fail and address


def send_email():
smtp_host = get_config('smtpHost')
if not smtp_host or not log_rows:
return
body = ''
for row in log_rows:
body += '<span>%s</span><br>' % row
html = '''
<html>
<body>
<div>%s</div>
</body>
</html>
''' % body
smtp_port = get_config('smtpPort', 25)
smtp_user = get_config('smtpUser')
smtp_password = get_config('smtpPassword')
smtp_address = get_config('smtpAddrs')
mail.send_email(host=smtp_host, port=smtp_port, user=smtp_user, password=smtp_password, to_addrs=smtp_address,
html=html)


def main():
"""
更新
Expand Down Expand Up @@ -174,7 +212,7 @@ def main():
print("=" * 25, ctime(), "=" * 25, sep=' ')

proxy = get_config('proxy') or 'DIRECT'
proxy_list = proxy.strip('; ') .split(';')
proxy_list = proxy.strip('; ').split(';')

cache = get_config('cache', True) and Cache(CACHE_FILE)
if cache is False:
Expand All @@ -184,6 +222,7 @@ def main():
cache.clear()
update_ip('4', cache, dns, proxy_list)
update_ip('6', cache, dns, proxy_list)
send_email()


if __name__ == '__main__':
Expand Down
16 changes: 16 additions & 0 deletions util/mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText


def send_email(host, port=25, to_addrs=None, user=None, password=None, html=None):
msg = MIMEText(html, 'html', 'utf-8')
msg['Subject'] = 'DDNS'
msg['From'] = user
# 收件人为多个收件人,通过join将列表转换为以;为间隔的字符串
msg['To'] = ";".join(to_addrs)
smtp = smtplib.SMTP()
smtp.set_debuglevel(1)
smtp.connect(host=host, port=port)
smtp.login(user, password)
smtp.sendmail(user, to_addrs, msg.as_string())