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

添加CloudFlare支持+一个小feature #20

Merged
merged 2 commits into from
Jul 21, 2018
Merged
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ python run.py -c /path/to/config.json
* `default` 系统访问外网默认IP
* `public`使用公网ip(使用公网API查询)
* `nku` NKU网关ip(只支持ipv4)
* `none` 不更新ipv4/ipv6的DNS解析

### 配置示例
```json
Expand Down
145 changes: 145 additions & 0 deletions dns/cloudflare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# coding=utf-8
"""
CloudFlare API
CloudFlare 接口解析操作库
https://api.cloudflare.com/#dns-records-for-a-zone-properties
@author: TongYifan
"""

import json
import logging as log

try:
# python 2
from httplib import HTTPSConnection
import urllib
except ImportError:
# python 3
from http.client import HTTPSConnection
import urllib.parse as urllib

__author__ = 'TongYifan'

ID = "AUTH EMAIL" # CloudFlare 验证的是用户Email,等同于其他平台的userID
TOKEN = "API KEY"
PROXY = None # 代理设置
API_SITE = "api.cloudflare.com"


def request(method, action, param=None, **params):
"""
发送请求数据
"""
if param:
params.update(param)

log.debug("$s %s : params:%s", action, params)
if PROXY:
conn = HTTPSConnection(PROXY)
conn.set_tunnel(API_SITE, 443)
else:
conn = HTTPSConnection(API_SITE)

if method in ['PUT', 'POST']:
# 从public_v(4,6)获取的IP是bytes类型,在json.dumps时会报TypeError
params['content'] = str(params.get('content'))
params = json.dumps(params)
else:
params = urllib.urlencode(params)
conn.request(method, '/client/v4/zones' + action, params,
{"Content-type": "application/json",
"X-Auth-Email": ID,
"X-Auth-Key": TOKEN})
response = conn.getresponse()
res = response.read()
conn.close()
if response.status < 200 or response.status >= 300:
raise Exception(res)
else:
data = json.loads(res.decode('utf8'))
if not data:
raise Exception("Empty Response")
elif data.get('success'):
return data.get('result', [{}])
else:
raise Exception(data.get('errors', [{}]))


def get_zone_id(domain):
"""
切割域名获取主域名ID(Zone_ID)
https://api.cloudflare.com/#zone-list-zones
"""
if len(domain.split('.')) > 2:
main = domain.split('.', 1)[1]
else:
main = domain
res = request('GET', '', name=main)
zoneid = res[0].get('id')
return zoneid


def get_records(zoneid, **conditions):
"""
获取记录ID
返回满足条件的所有记录[]
TODO 大于100翻页
"""
if not hasattr(get_records, 'records'):
get_records.records = {} # "静态变量"存储已查询过的id
get_records.keys = ('id', 'type', 'name', 'content', 'proxied', 'ttl')

if not zoneid in get_records.records:
get_records.records[zoneid] = {}
data = request('GET', '/' + zoneid + '/dns_records', per_page=100)
if data:
for record in data:
get_records.records[zoneid][record['id']] = {
k: v for (k, v) in record.items() if k in get_records.keys}

records = {}
for (zid, record) in get_records.records[zoneid].items():
for (k, value) in conditions.items():
if record.get(k) != value:
break
else: # for else push
records[zid] = record
return records


def update_record(domain, value, record_type="A"):
"""
更新记录
"""
log.debug(">>>>>%s(%s)", domain, record_type)
zoneid = get_zone_id(domain)
if not zoneid:
raise Exception("invalid domain: [ %s ] " % domain)

records = get_records(zoneid, name=domain, type=record_type)
result = {}
if records: # update
# https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
for (rid, record) in records.items():
if record['content'] != value:
res = request('PUT', '/' + zoneid + '/dns_records/' + record['id'],
type=record_type, content=value, name=domain)
if res:
get_records.records[zoneid][rid]['content'] = value
result[rid] = res.get("record")
else:
result[rid] = "Update fail!\n" + str(res)
else:
result[rid] = domain
else: # create
# https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
res = request('POST', '/' + zoneid + '/dns_records',
type=record_type, name=domain, content=value, proxied=False, ttl=600)
if res:
get_records.records[zoneid][res['id']] = res
get_records.records[zoneid][res['id']].update(
value=value, type=record_type)
result = res
else:
result = domain + " created fail!"
return result
4 changes: 3 additions & 1 deletion run.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def get_ip(ip_type):
get IP address
"""
index = get_config('index' + ip_type) or "default"
if str(index).isdigit(): # local eth
if index == 'none':
return None
elif str(index).isdigit(): # local eth
value = getattr(ip, "local_v" + ip_type)(index)
elif any((c in index) for c in '*.:'): # regex
value = getattr(ip, "regex_v" + ip_type)(index)
Expand Down