init
This commit is contained in:
parent
340da83789
commit
635647c0fa
163
.gitignore
vendored
163
.gitignore
vendored
|
@ -1,162 +1,11 @@
|
|||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
# vue
|
||||
./nsi-collection-platform/node_modules/
|
||||
./nsi-collection-platform/dist/
|
||||
./nsi-collection-platform/.idea
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
NSICollectionPlatformServer/.idea
|
||||
|
||||
NSICollectionPlatformServer/venv
|
||||
|
|
53
NSICollectionPlatformServer/README.md
Normal file
53
NSICollectionPlatformServer/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# 网络安全信息搜集平台
|
||||
> 网络安全信息搜集平台服务端。为前端页面展示提供全套后台服务功能。
|
||||
|
||||
## 项目说明
|
||||
* app.py
|
||||
> 项目启动文件,包含全部的request请求接口和拦截器设置
|
||||
|
||||
* userManager.py
|
||||
> 用户信息管理模块。提供对用户增、删、改、查、登录、注册等功能。
|
||||
|
||||
* dnsResolve.py.py
|
||||
> DNS解析模块。提供对dns进行解析的功能。
|
||||
|
||||
* subdomainLookup.py
|
||||
> 子域名解析模块。
|
||||
|
||||
* emailGrabbing.py
|
||||
> 邮箱内容解析模块。目前只对指定邮箱账号中的内容进行扒取和解析。
|
||||
|
||||
* portDetection.py
|
||||
> 端口检测模块。用于检测指定地址上指定端口的状态(开启/关闭)。
|
||||
|
||||
* requirements.txt
|
||||
> 包管理文件。包含所有需要依赖的三方包。需要在项目启动前执行安装。
|
||||
|
||||
## To Start
|
||||
1. 使用以下命令安装需要的Python依赖包。
|
||||
```shell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
2. 切换目录到当前路径下
|
||||
|
||||
3. 运行app.py
|
||||
```shell
|
||||
#前台执行
|
||||
python3 app.py
|
||||
#后台守护进程执行
|
||||
nohup python3 app.py >> app.log 2>&1 &
|
||||
```
|
||||
|
||||
## 备注
|
||||
1. 更新依赖包文件可以使用以下命令
|
||||
```shell
|
||||
pip freeze > requirements.txt
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
349
NSICollectionPlatformServer/app.py
Normal file
349
NSICollectionPlatformServer/app.py
Normal file
|
@ -0,0 +1,349 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
|
||||
from flask import Flask
|
||||
from flask import request, make_response
|
||||
|
||||
import userManager as User
|
||||
import dnsResolve
|
||||
import subdomainLookup
|
||||
import emailGrabbing
|
||||
import portDetection
|
||||
import logOperation as Operation
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
data_source = {
|
||||
"host": "118.24.151.27",
|
||||
"username": "admin",
|
||||
"password": "Liu947752894!",
|
||||
"database": "NSI"
|
||||
}
|
||||
logOperation = Operation.OperationLog(**data_source)
|
||||
user_manager = User.UserManager(**data_source)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host="127.0.0.1", port=8080)
|
||||
|
||||
|
||||
def result(code="000000", desc="SUCCESS", data=None):
|
||||
res = {
|
||||
"code": code,
|
||||
"desc": desc,
|
||||
"data": data
|
||||
}
|
||||
return res
|
||||
|
||||
|
||||
@app.before_request
|
||||
def request_handle():
|
||||
"""
|
||||
请求拦截器,根据token统一判断是否可用
|
||||
:return: 拦截结果
|
||||
"""
|
||||
print(request.url)
|
||||
print(request.headers)
|
||||
url = request.url.split("/admin")[1]
|
||||
print(url)
|
||||
url = url.split("?")[0]
|
||||
print(url)
|
||||
if url not in ["/login", "/register"]:
|
||||
flag = False
|
||||
if "token" in request.headers:
|
||||
token = request.headers['token']
|
||||
flag = user_manager.valid_token(token)
|
||||
if not flag:
|
||||
response = make_response(result(code="100000", desc="valid token error"))
|
||||
response.status = 401
|
||||
return response
|
||||
|
||||
|
||||
def log_operation(request_info, desc="", data=None):
|
||||
"""
|
||||
记录操作日志记录并保存在数据库中
|
||||
:param request_info: 请求命令
|
||||
:param desc: 用户执行的操作
|
||||
:param data: 操作执行数据内容
|
||||
"""
|
||||
token = ""
|
||||
username = ""
|
||||
if "token" in request_info.headers \
|
||||
and request_info.headers["token"] is not None \
|
||||
and 'null' != request_info.headers["token"]:
|
||||
token = request_info.headers["token"]
|
||||
else:
|
||||
username = request_info.json["username"]
|
||||
logOperation.log(token=token, desc=desc, data=data, username=username)
|
||||
|
||||
|
||||
@app.route('/admin/login', methods=['POST'])
|
||||
def login():
|
||||
"""
|
||||
用户登录
|
||||
:return: 登录结果
|
||||
"""
|
||||
username = request.json['username']
|
||||
password = request.json['password']
|
||||
__res = user_manager.valid_login(username, password)
|
||||
if __res is None or len(__res) == 0:
|
||||
res = result(code="10000", desc="用户不存在")
|
||||
else:
|
||||
data = {
|
||||
"token": User.create_token(username + password),
|
||||
"role": __res['role']
|
||||
}
|
||||
res = result(data=data)
|
||||
log_operation(request_info=request, desc="用户登录", data={
|
||||
"用户名": username,
|
||||
"操作执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/register', methods=['POST'])
|
||||
def register():
|
||||
"""
|
||||
用户注册,此时无法设置权限,只能管理员对用户设置权限
|
||||
:return:
|
||||
"""
|
||||
username = request.json['username']
|
||||
password = request.json['password']
|
||||
role = request.json['role']
|
||||
__res = user_manager.user_register(username, password, role)
|
||||
if __res:
|
||||
res = result(data="用户注册成功")
|
||||
else:
|
||||
res = result(code="10000", desc="用户已经存在")
|
||||
log_operation(request_info=request, desc="用户注册", data={
|
||||
"用户名": username,
|
||||
"操作执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/user/add', methods=['POST'])
|
||||
def user_add():
|
||||
"""
|
||||
新增用户
|
||||
:return:
|
||||
"""
|
||||
__res = user_manager.user_add(
|
||||
request.json['username'],
|
||||
request.json['password'],
|
||||
request.json['role'],
|
||||
)
|
||||
if __res:
|
||||
res = result(data="新增用户成功")
|
||||
else:
|
||||
res = result(code="10000", desc="新增用户失败")
|
||||
log_operation(request_info=request, desc="管理员新增用户", data={
|
||||
"用户名": request.json['username'],
|
||||
"角色": request.json['role'],
|
||||
"操作执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/user/delete', methods=['POST'])
|
||||
def user_delete():
|
||||
"""
|
||||
根据id删除用户
|
||||
:return:
|
||||
"""
|
||||
__id = request.json['id']
|
||||
__res = user_manager.user_delete(__id)
|
||||
if __res:
|
||||
res = result(data="删除用户成功")
|
||||
else:
|
||||
res = result(code="10000", desc="删除用户失败")
|
||||
log_operation(request_info=request, desc="删除用户", data={
|
||||
"ID": __id,
|
||||
"操作结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/user/edit', methods=['POST'])
|
||||
def user_edit():
|
||||
"""
|
||||
编辑用户
|
||||
:return:
|
||||
"""
|
||||
__res = user_manager.user_edit(
|
||||
request.json['id'],
|
||||
request.json['username'],
|
||||
request.json['password'],
|
||||
request.json['role'],
|
||||
)
|
||||
if __res:
|
||||
res = result(data="编辑用户成功")
|
||||
else:
|
||||
res = result(code="10000", desc="编辑用户失败")
|
||||
log_operation(request_info=request, desc="编辑用户", data={
|
||||
"ID": request.json['id'],
|
||||
"用户名": request.json['username'],
|
||||
"角色": request.json['role'],
|
||||
"操作执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/user/list', methods=['GET'])
|
||||
def user_list():
|
||||
"""
|
||||
获取用户列表
|
||||
:return:
|
||||
"""
|
||||
__res = user_manager.user_list()
|
||||
if __res:
|
||||
return result(data=__res)
|
||||
else:
|
||||
return result(code="10000", desc="获取用户列表失败")
|
||||
|
||||
|
||||
@app.route('/admin/user/get', methods=['GET'])
|
||||
def user_get():
|
||||
"""
|
||||
根据id获取用户信息
|
||||
:return:
|
||||
"""
|
||||
__res = user_manager.user_get(request.values['id'])
|
||||
if __res:
|
||||
return result(data=__res)
|
||||
else:
|
||||
return result(code="10000", desc="获取用户信息失败")
|
||||
|
||||
|
||||
@app.route('/admin/user/authority/change', methods=['POST'])
|
||||
def user_authority_change():
|
||||
"""
|
||||
根据id修改用户权限
|
||||
:return:
|
||||
"""
|
||||
__id = request.json['id']
|
||||
__role = request.json['role']
|
||||
__res = user_manager.user_authority_change(__id, __role)
|
||||
if __res:
|
||||
res = result(data=__res)
|
||||
else:
|
||||
res = result(code="10000", desc="获取用户信息失败")
|
||||
log_operation(request_info=request, desc="修改用户权限", data={
|
||||
"ID": __id,
|
||||
"角色": __role,
|
||||
"操作执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/dns/resolution', methods=['GET'])
|
||||
def dns_resolution():
|
||||
"""
|
||||
DNS解析
|
||||
:return:
|
||||
"""
|
||||
__domainType = request.values["domainType"]
|
||||
__domain = request.values["domain"]
|
||||
if __domainType is None or __domainType not in ["A", "MX", "NS", "CNAME"]:
|
||||
res = result(code="100000", desc="无效类型")
|
||||
else:
|
||||
if "A" == __domainType:
|
||||
__data = dnsResolve.resolution_a(__domain)
|
||||
elif "MX" == __domainType:
|
||||
__data = dnsResolve.resolution_mx(__domain)
|
||||
elif "NS" == __domainType:
|
||||
__data = dnsResolve.resolution_ns(__domain)
|
||||
elif "CNAME" == __domainType:
|
||||
__data = dnsResolve.resolution_cname(__domain)
|
||||
else:
|
||||
__data = []
|
||||
res = result(data=__data)
|
||||
log_operation(request_info=request, desc="DNS解析", data={
|
||||
"解析类型": __domainType,
|
||||
"解析域名": __domain,
|
||||
"解析结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/subdomain/lookup', methods=['GET'])
|
||||
def subdomain_lookup():
|
||||
"""
|
||||
子域名查询
|
||||
:return:
|
||||
"""
|
||||
domain = request.values["domain"]
|
||||
if domain is None or domain == "":
|
||||
res = result(code="100000", desc="域名为空")
|
||||
else:
|
||||
sub_domain_list = subdomainLookup.sub_domain_lookup(domain=domain)
|
||||
__data = []
|
||||
for key in sub_domain_list:
|
||||
__data.append({
|
||||
"href": key,
|
||||
"title": sub_domain_list[key]
|
||||
})
|
||||
res = result(data=__data)
|
||||
log_operation(request_info=request, desc="子域名查询", data={
|
||||
"解析域名": domain,
|
||||
"解析结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/email/grabbing', methods=['GET'])
|
||||
def email_grabbing():
|
||||
"""
|
||||
邮箱账号抓取
|
||||
:return:
|
||||
"""
|
||||
keyword = request.values["keyword"]
|
||||
email_suffix = request.values["email_suffix"]
|
||||
email_count = int(request.values["email_count"])
|
||||
if keyword is None or keyword == "":
|
||||
res = result(code="100000", desc="搜索关键值不能为空")
|
||||
elif email_suffix is None or email_suffix == "":
|
||||
res = result(code="100000", desc="搜索邮箱后缀不能为空")
|
||||
else:
|
||||
email_grabbing_result = emailGrabbing.EmailAccountGrabbing(keyword=keyword, email_suffix=email_suffix,
|
||||
email_count=email_count).grabbing()
|
||||
res = result(data=email_grabbing_result)
|
||||
log_operation(request_info=request, desc="邮箱账号抓取", data={
|
||||
"查询关键字": keyword,
|
||||
"指定邮箱后缀": email_suffix,
|
||||
"邮箱账号抓取结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/port/detection', methods=['GET'])
|
||||
def port_detection():
|
||||
"""
|
||||
端口检测
|
||||
:return:
|
||||
"""
|
||||
domain = request.values["domain"]
|
||||
port = request.values["port"]
|
||||
if domain is None or domain == "":
|
||||
res = result(code="100000", desc="域名/IP不能为空")
|
||||
else:
|
||||
port_detection_result = portDetection.detection(domain=domain, port=port)
|
||||
res = result(data=port_detection_result)
|
||||
log_operation(request_info=request, desc="端口检测", data={
|
||||
"域名或IP": domain,
|
||||
"端口号": port,
|
||||
"执行结果": res
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
@app.route('/admin/operation/log/get', methods=['GET'])
|
||||
def operation_log():
|
||||
"""
|
||||
操作记录
|
||||
:return:
|
||||
"""
|
||||
username = request.values["username"]
|
||||
__operation_log_list = logOperation.list_log(username=username)
|
||||
res = result(data=__operation_log_list)
|
||||
return res
|
60
NSICollectionPlatformServer/dataSource.py
Normal file
60
NSICollectionPlatformServer/dataSource.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
@Time : 2021/05/12
|
||||
@Author :
|
||||
@Site :
|
||||
@File : dataSource.py
|
||||
@Software: PyCharm
|
||||
@Description:
|
||||
"""
|
||||
import pymysql
|
||||
import traceback
|
||||
|
||||
|
||||
class DataSource:
|
||||
def __init__(self, host='localhost', port=3306, username=None, password=None, database=None):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.database = database
|
||||
# 打开数据库连接
|
||||
self.db = pymysql.connect(host=self.host, port=self.port, user=self.username, password=self.password, database=self.database)
|
||||
# 使用 cursor() 方法创建一个游标对象 cursor
|
||||
self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor)
|
||||
|
||||
def __is_connected(self):
|
||||
try:
|
||||
self.db.ping(reconnect=True)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.db = pymysql.connections.Connection(host=self.host, port=self.port, user=self.username, password=self.password, database=self.database)
|
||||
|
||||
def fetchall(self, sql):
|
||||
self.__is_connected()
|
||||
self.cursor.execute(sql)
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def fetchmany(self, sql):
|
||||
self.__is_connected()
|
||||
self.cursor.execute(sql)
|
||||
return self.cursor.fetchmany()
|
||||
|
||||
def fetchone(self, sql):
|
||||
self.__is_connected()
|
||||
self.cursor.execute(sql)
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def execute(self, sql):
|
||||
self.__is_connected()
|
||||
try:
|
||||
self.cursor.execute(sql)
|
||||
self.db.commit()
|
||||
except:
|
||||
self.db.rollback()
|
||||
|
||||
def close(self):
|
||||
self.__is_connected()
|
||||
# 关闭数据库连接
|
||||
self.db.close()
|
55
NSICollectionPlatformServer/dnsResolve.py
Normal file
55
NSICollectionPlatformServer/dnsResolve.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
|
||||
import dns
|
||||
import requests
|
||||
|
||||
|
||||
def resolution_a(domain):
|
||||
query_list = []
|
||||
a = dns.resolver.resolve(domain, 'A')
|
||||
for i in a.response.answer:
|
||||
for j in i.items:
|
||||
if j.rdtype == 1:
|
||||
ip = j.address
|
||||
__ip_query = get_ip_info(ip)
|
||||
__ip_query["ip"] = ip
|
||||
__ip_query["domain"] = domain
|
||||
query_list.append(__ip_query)
|
||||
return query_list
|
||||
|
||||
|
||||
def resolution_mx(domain):
|
||||
mx = dns.resolver.resolve(domain, 'MX') # 指定查看类型为MX
|
||||
for i in mx:
|
||||
print('MX preference=', i.preference, 'mail exchanger=', i.exchange)
|
||||
|
||||
|
||||
def resolution_ns(domain):
|
||||
ns = dns.resolver.resolve(domain, 'NS') # 指定查询类型为NS记录
|
||||
for i in ns.response.answer:
|
||||
for j in i.items:
|
||||
print(j.to_text())
|
||||
|
||||
|
||||
def resolution_cname(domain):
|
||||
cname = dns.resolver.resolve(domain, 'CNAME') # 指定查询类型为CNAME记录
|
||||
for i in cname.response.answer: # 结果将回应cname后的目标域名
|
||||
for j in i.items:
|
||||
print(j.to_text())
|
||||
|
||||
|
||||
def get_ip_info(ip):
|
||||
# IP地址库接口
|
||||
r = requests.get('https://ip.taobao.com/getIpInfo.php?ip=%s' % ip)
|
||||
content = json.loads(r.content.decode("utf8"))
|
||||
ip_query = {}
|
||||
if "code" in content and content["code"] == '0':
|
||||
i = content['data']
|
||||
ip_query["country"] = i['COUNTRY_CN']
|
||||
ip_query["area"] = i['AREA_CN']
|
||||
ip_query["province"] = i['PROVINCE_CN']
|
||||
ip_query["city"] = i['CITY_CN']
|
||||
ip_query["isp"] = i['ISP_CN']
|
||||
return ip_query
|
58
NSICollectionPlatformServer/emailGrabbing.py
Normal file
58
NSICollectionPlatformServer/emailGrabbing.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from fake_useragent import UserAgent
|
||||
|
||||
|
||||
def get_http_headers():
|
||||
try:
|
||||
ua = UserAgent()
|
||||
header = {
|
||||
"User-Agent": ua.random,
|
||||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7,zh-TW;q=0.6"
|
||||
}
|
||||
except Exception as e:
|
||||
header = {
|
||||
u'User-Agent': u'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36'}
|
||||
return header
|
||||
|
||||
|
||||
class EmailAccountGrabbing:
|
||||
def __init__(self, keyword="test", email_count=2, grabbing_engine="https://www.bing.com/search", email_suffix="hotmail.com"):
|
||||
self.keyword = keyword
|
||||
self.email_count = email_count
|
||||
self.grabbing_engine = grabbing_engine
|
||||
self.email_suffix = email_suffix
|
||||
|
||||
def grabbing(self):
|
||||
email_grabbing_result = []
|
||||
for i in range(1, self.email_count):
|
||||
j = 1
|
||||
if i != 1:
|
||||
j = i*10+1
|
||||
params = {
|
||||
"q": "%s @%s" % (self.keyword, self.email_suffix),
|
||||
"go": "搜索",
|
||||
"qs": "bs",
|
||||
"form": "QBRE",
|
||||
"first": j
|
||||
}
|
||||
cookies = {
|
||||
"SRCHHPGUSR": "NRSLT=50"
|
||||
}
|
||||
ret = requests.get(self.grabbing_engine, headers=get_http_headers(), params=params, cookies=cookies)
|
||||
soup = BeautifulSoup(ret.text, "html.parser")
|
||||
nodes = soup.find_all(class_="b_caption")
|
||||
re_email = re.compile('\w+[a-zA-Z0-9_.\-]*@%s' % self.email_suffix)
|
||||
for node in nodes:
|
||||
emails = re_email.findall(node.text)
|
||||
for email in emails:
|
||||
email_grabbing_result.append({
|
||||
"grabbingEngine": ret.url,
|
||||
"emailAddress": email,
|
||||
"keyword": self.keyword
|
||||
})
|
||||
return email_grabbing_result
|
46
NSICollectionPlatformServer/logOperation.py
Normal file
46
NSICollectionPlatformServer/logOperation.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import traceback
|
||||
|
||||
from dataSource import DataSource
|
||||
|
||||
|
||||
class OperationLog:
|
||||
def __init__(self, host='localhost', port=3306, username=None, password=None, database=None):
|
||||
self.db = DataSource(host, port, username, password, database)
|
||||
|
||||
def log(self, token, desc="", data=None, username=""):
|
||||
"""
|
||||
记录用户操作
|
||||
:param token: 令牌(用户名和令牌不可同时有值)
|
||||
:param desc: 操作描述
|
||||
:param data: 操作数据
|
||||
:param username: 用户名(用户名和令牌不可同时有值)
|
||||
"""
|
||||
try:
|
||||
if data is None:
|
||||
data = {}
|
||||
if "" == token:
|
||||
sql_insert = 'INSERT INTO LOG_OPERATION (username, operationContent, operationData) VALUES ("' + username + '", "' + desc + '", ' + json.dumps(
|
||||
json.dumps(data)) + ')'
|
||||
else:
|
||||
sql = 'SELECT * FROM USER WHERE `password`="' + token + '"'
|
||||
user_info = self.db.fetchone(sql)
|
||||
sql_insert = 'INSERT INTO LOG_OPERATION (username, operationContent, operationData) VALUES ("' + \
|
||||
user_info["username"] + '", "' + desc + '", ' + json.dumps(json.dumps(data)) + ')'
|
||||
self.db.execute(sql=sql_insert)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
def list_log(self, username=""):
|
||||
"""
|
||||
获取用户操作列表集合
|
||||
:param username: 根据用户名查看对应操作记录
|
||||
:return:
|
||||
"""
|
||||
if username is None or username == "":
|
||||
sql = 'SELECT * FROM LOG_OPERATION'
|
||||
else:
|
||||
sql = 'SELECT * FROM LOG_OPERATION WHERE username="' + username + '"'
|
||||
return self.db.fetchall(sql)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar.gz
Normal file
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar.gz
Normal file
Binary file not shown.
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1.tar
vendored
Normal file
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1.tar
vendored
Normal file
Binary file not shown.
21
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/PKG-INFO
vendored
Normal file
21
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/PKG-INFO
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: bs4
|
||||
Version: 0.0.1
|
||||
Summary: Screen-scraping library
|
||||
Home-page: https://pypi.python.org/pypi/beautifulsoup4
|
||||
Author: Leonard Richardson
|
||||
Author-email: leonardr@segfault.org
|
||||
License: MIT
|
||||
Download-URL: http://www.crummy.com/software/BeautifulSoup/bs4/download/
|
||||
Description: Use `beautifulsoup4 <https://pypi.python.org/pypi/beautifulsoup4>`_ instead.
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
||||
Classifier: Topic :: Text Processing :: Markup :: XML
|
||||
Classifier: Topic :: Text Processing :: Markup :: SGML
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
21
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/PKG-INFO
vendored
Normal file
21
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/PKG-INFO
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: bs4
|
||||
Version: 0.0.1
|
||||
Summary: Screen-scraping library
|
||||
Home-page: https://pypi.python.org/pypi/beautifulsoup4
|
||||
Author: Leonard Richardson
|
||||
Author-email: leonardr@segfault.org
|
||||
License: MIT
|
||||
Download-URL: http://www.crummy.com/software/BeautifulSoup/bs4/download/
|
||||
Description: Use `beautifulsoup4 <https://pypi.python.org/pypi/beautifulsoup4>`_ instead.
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
||||
Classifier: Topic :: Text Processing :: Markup :: XML
|
||||
Classifier: Topic :: Text Processing :: Markup :: SGML
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
7
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/SOURCES.txt
vendored
Normal file
7
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/SOURCES.txt
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
setup.cfg
|
||||
setup.py
|
||||
bs4.egg-info/PKG-INFO
|
||||
bs4.egg-info/SOURCES.txt
|
||||
bs4.egg-info/dependency_links.txt
|
||||
bs4.egg-info/requires.txt
|
||||
bs4.egg-info/top_level.txt
|
|
@ -0,0 +1 @@
|
|||
|
1
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/requires.txt
vendored
Normal file
1
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/requires.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
beautifulsoup4
|
1
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/top_level.txt
vendored
Normal file
1
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/bs4.egg-info/top_level.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
|
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/dist/bs4-0.0.1-py3.9.egg
vendored
Normal file
BIN
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/dist/bs4-0.0.1-py3.9.egg
vendored
Normal file
Binary file not shown.
5
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/setup.cfg
vendored
Normal file
5
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/setup.cfg
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
27
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/setup.py
vendored
Normal file
27
NSICollectionPlatformServer/packages/bs4-0.0.1.tar/dist/bs4-0.0.1/setup.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="bs4",
|
||||
version="0.0.1",
|
||||
author="Leonard Richardson",
|
||||
author_email='leonardr@segfault.org',
|
||||
url="https://pypi.python.org/pypi/beautifulsoup4",
|
||||
download_url="http://www.crummy.com/software/BeautifulSoup/bs4/download/",
|
||||
description="Screen-scraping library",
|
||||
long_description="""Use `beautifulsoup4 <https://pypi.python.org/pypi/beautifulsoup4>`_ instead.""", # noqa
|
||||
license="MIT",
|
||||
install_requires=['beautifulsoup4'],
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2",
|
||||
'Programming Language :: Python :: 3',
|
||||
"Topic :: Text Processing :: Markup :: HTML",
|
||||
"Topic :: Text Processing :: Markup :: XML",
|
||||
"Topic :: Text Processing :: Markup :: SGML",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
NSICollectionPlatformServer/packages/dnspython-2.1.0.zip
Normal file
BIN
NSICollectionPlatformServer/packages/dnspython-2.1.0.zip
Normal file
Binary file not shown.
35
NSICollectionPlatformServer/packages/dnspython-2.1.0/LICENSE
vendored
Normal file
35
NSICollectionPlatformServer/packages/dnspython-2.1.0/LICENSE
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
ISC License
|
||||
|
||||
Copyright (C) Dnspython Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted, provided that the
|
||||
above copyright notice and this permission notice appear in all
|
||||
copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 2001-2017 Nominum, Inc.
|
||||
Copyright (C) Google Inc.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose with or without fee is hereby granted,
|
||||
provided that the above copyright notice and this permission notice
|
||||
appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
3
NSICollectionPlatformServer/packages/dnspython-2.1.0/MANIFEST.in
vendored
Normal file
3
NSICollectionPlatformServer/packages/dnspython-2.1.0/MANIFEST.in
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
include LICENSE ChangeLog README.md
|
||||
recursive-include examples *.txt *.py
|
||||
recursive-include tests *.txt *.py Makefile *.good example query
|
38
NSICollectionPlatformServer/packages/dnspython-2.1.0/PKG-INFO
vendored
Normal file
38
NSICollectionPlatformServer/packages/dnspython-2.1.0/PKG-INFO
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: dnspython
|
||||
Version: 2.1.0
|
||||
Summary: DNS toolkit
|
||||
Home-page: http://www.dnspython.org
|
||||
Author: Bob Halley
|
||||
Author-email: halley@dnspython.org
|
||||
License: ISC
|
||||
Description: dnspython is a DNS toolkit for Python. It supports almost all
|
||||
record types. It can be used for queries, zone transfers, and dynamic
|
||||
updates. It supports TSIG authenticated messages and EDNS0.
|
||||
|
||||
dnspython provides both high and low level access to DNS. The high
|
||||
level classes perform queries for data of a given name, type, and
|
||||
class, and return an answer set. The low level classes allow
|
||||
direct manipulation of DNS zones, messages, names, and records.
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: ISC License (ISCL)
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Internet :: Name Service (DNS)
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Provides: dns
|
||||
Requires-Python: >=3.6
|
||||
Provides-Extra: DOH
|
||||
Provides-Extra: IDNA
|
||||
Provides-Extra: DNSSEC
|
||||
Provides-Extra: trio
|
||||
Provides-Extra: curio
|
74
NSICollectionPlatformServer/packages/dnspython-2.1.0/README.md
vendored
Normal file
74
NSICollectionPlatformServer/packages/dnspython-2.1.0/README.md
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
# dnspython
|
||||
|
||||
[![Build Status](https://travis-ci.org/rthalley/dnspython.svg?branch=master)](https://travis-ci.org/rthalley/dnspython)
|
||||
[![Documentation Status](https://readthedocs.org/projects/dnspython/badge/?version=latest)](https://dnspython.readthedocs.io/en/latest/?badge=latest)
|
||||
[![PyPI version](https://badge.fury.io/py/dnspython.svg)](https://badge.fury.io/py/dnspython)
|
||||
[![Coverage](https://codecov.io/github/rthalley/dnspython/coverage.svg?branch=master)](https://codecov.io/gh/rthalley/dnspython)
|
||||
[![License: ISC](https://img.shields.io/badge/License-ISC-brightgreen.svg)](https://opensource.org/licenses/ISC)
|
||||
|
||||
## INTRODUCTION
|
||||
|
||||
dnspython is a DNS toolkit for Python. It supports almost all record types. It
|
||||
can be used for queries, zone transfers, and dynamic updates. It supports TSIG
|
||||
authenticated messages and EDNS0.
|
||||
|
||||
dnspython provides both high and low level access to DNS. The high level classes
|
||||
perform queries for data of a given name, type, and class, and return an answer
|
||||
set. The low level classes allow direct manipulation of DNS zones, messages,
|
||||
names, and records.
|
||||
|
||||
To see a few of the ways dnspython can be used, look in the `examples/`
|
||||
directory.
|
||||
|
||||
dnspython is a utility to work with DNS, `/etc/hosts` is thus not used. For
|
||||
simple forward DNS lookups, it's better to use `socket.getaddrinfo()` or
|
||||
`socket.gethostbyname()`.
|
||||
|
||||
dnspython originated at Nominum where it was developed
|
||||
to facilitate the testing of DNS software.
|
||||
|
||||
## ABOUT THIS RELEASE
|
||||
|
||||
This is dnspython 2.1.0.
|
||||
Please read
|
||||
[What's New](https://dnspython.readthedocs.io/en/stable/whatsnew.html) for
|
||||
information about the changes in this release.
|
||||
|
||||
## INSTALLATION
|
||||
|
||||
* Many distributions have dnspython packaged for you, so you should
|
||||
check there first.
|
||||
* If you have pip installed, you can do `pip install dnspython`
|
||||
* If not just download the source file and unzip it, then run
|
||||
`sudo python setup.py install`
|
||||
* To install the latest from the master branch, run `pip install git+https://github.com/rthalley/dnspython.git`
|
||||
|
||||
If you want to use DNS-over-HTTPS, you must run
|
||||
`pip install dnspython[doh]`.
|
||||
|
||||
If you want to use DNSSEC functionality, you must run
|
||||
`pip install dnspython[dnssec]`.
|
||||
|
||||
If you want to use internationalized domain names (IDNA)
|
||||
functionality, you must run
|
||||
`pip install dnspython[idna]`
|
||||
|
||||
If you want to use the Trio asynchronous I/O package, you must run
|
||||
`pip install dnspython[trio]`.
|
||||
|
||||
If you want to use the Curio asynchronous I/O package, you must run
|
||||
`pip install dnspython[curio]`.
|
||||
|
||||
Note that you can install any combination of the above, e.g.:
|
||||
`pip install dnspython[doh,dnssec,idna]`
|
||||
|
||||
### Notices
|
||||
|
||||
Python 2.x support ended with the release of 1.16.0. dnspython 2.0.0 and
|
||||
later only support Python 3.6 and later.
|
||||
|
||||
Documentation has moved to
|
||||
[dnspython.readthedocs.io](https://dnspython.readthedocs.io).
|
||||
|
||||
The ChangeLog has been discontinued. Please see the git history for detailed
|
||||
change information.
|
66
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/__init__.py
vendored
Normal file
66
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/__init__.py
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""dnspython DNS toolkit"""
|
||||
|
||||
__all__ = [
|
||||
'asyncbackend',
|
||||
'asyncquery',
|
||||
'asyncresolver',
|
||||
'dnssec',
|
||||
'e164',
|
||||
'edns',
|
||||
'entropy',
|
||||
'exception',
|
||||
'flags',
|
||||
'immutable',
|
||||
'inet',
|
||||
'ipv4',
|
||||
'ipv6',
|
||||
'message',
|
||||
'name',
|
||||
'namedict',
|
||||
'node',
|
||||
'opcode',
|
||||
'query',
|
||||
'rcode',
|
||||
'rdata',
|
||||
'rdataclass',
|
||||
'rdataset',
|
||||
'rdatatype',
|
||||
'renderer',
|
||||
'resolver',
|
||||
'reversename',
|
||||
'rrset',
|
||||
'serial',
|
||||
'set',
|
||||
'tokenizer',
|
||||
'transaction',
|
||||
'tsig',
|
||||
'tsigkeyring',
|
||||
'ttl',
|
||||
'rdtypes',
|
||||
'update',
|
||||
'version',
|
||||
'versioned',
|
||||
'wire',
|
||||
'xfr',
|
||||
'zone',
|
||||
'zonefile',
|
||||
]
|
||||
|
||||
from dns.version import version as __version__ # noqa
|
60
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_asyncbackend.py
vendored
Normal file
60
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_asyncbackend.py
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# This is a nullcontext for both sync and async. 3.7 has a nullcontext,
|
||||
# but it is only for sync use.
|
||||
|
||||
class NullContext:
|
||||
def __init__(self, enter_result=None):
|
||||
self.enter_result = enter_result
|
||||
|
||||
def __enter__(self):
|
||||
return self.enter_result
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
async def __aenter__(self):
|
||||
return self.enter_result
|
||||
|
||||
async def __aexit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
|
||||
# These are declared here so backends can import them without creating
|
||||
# circular dependencies with dns.asyncbackend.
|
||||
|
||||
class Socket: # pragma: no cover
|
||||
async def close(self):
|
||||
pass
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_value, traceback):
|
||||
await self.close()
|
||||
|
||||
|
||||
class DatagramSocket(Socket): # pragma: no cover
|
||||
async def sendto(self, what, destination, timeout):
|
||||
pass
|
||||
|
||||
async def recvfrom(self, size, timeout):
|
||||
pass
|
||||
|
||||
|
||||
class StreamSocket(Socket): # pragma: no cover
|
||||
async def sendall(self, what, destination, timeout):
|
||||
pass
|
||||
|
||||
async def recv(self, size, timeout):
|
||||
pass
|
||||
|
||||
|
||||
class Backend: # pragma: no cover
|
||||
def name(self):
|
||||
return 'unknown'
|
||||
|
||||
async def make_socket(self, af, socktype, proto=0,
|
||||
source=None, destination=None, timeout=None,
|
||||
ssl_context=None, server_hostname=None):
|
||||
raise NotImplementedError
|
138
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_asyncio_backend.py
vendored
Normal file
138
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_asyncio_backend.py
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
"""asyncio library query support"""
|
||||
|
||||
import socket
|
||||
import asyncio
|
||||
|
||||
import dns._asyncbackend
|
||||
import dns.exception
|
||||
|
||||
|
||||
def _get_running_loop():
|
||||
try:
|
||||
return asyncio.get_running_loop()
|
||||
except AttributeError: # pragma: no cover
|
||||
return asyncio.get_event_loop()
|
||||
|
||||
|
||||
class _DatagramProtocol:
|
||||
def __init__(self):
|
||||
self.transport = None
|
||||
self.recvfrom = None
|
||||
|
||||
def connection_made(self, transport):
|
||||
self.transport = transport
|
||||
|
||||
def datagram_received(self, data, addr):
|
||||
if self.recvfrom:
|
||||
self.recvfrom.set_result((data, addr))
|
||||
self.recvfrom = None
|
||||
|
||||
def error_received(self, exc): # pragma: no cover
|
||||
if self.recvfrom and not self.recvfrom.done():
|
||||
self.recvfrom.set_exception(exc)
|
||||
|
||||
def connection_lost(self, exc):
|
||||
if self.recvfrom and not self.recvfrom.done():
|
||||
self.recvfrom.set_exception(exc)
|
||||
|
||||
def close(self):
|
||||
self.transport.close()
|
||||
|
||||
|
||||
async def _maybe_wait_for(awaitable, timeout):
|
||||
if timeout:
|
||||
try:
|
||||
return await asyncio.wait_for(awaitable, timeout)
|
||||
except asyncio.TimeoutError:
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
else:
|
||||
return await awaitable
|
||||
|
||||
|
||||
class DatagramSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, family, transport, protocol):
|
||||
self.family = family
|
||||
self.transport = transport
|
||||
self.protocol = protocol
|
||||
|
||||
async def sendto(self, what, destination, timeout): # pragma: no cover
|
||||
# no timeout for asyncio sendto
|
||||
self.transport.sendto(what, destination)
|
||||
|
||||
async def recvfrom(self, size, timeout):
|
||||
# ignore size as there's no way I know to tell protocol about it
|
||||
done = _get_running_loop().create_future()
|
||||
assert self.protocol.recvfrom is None
|
||||
self.protocol.recvfrom = done
|
||||
await _maybe_wait_for(done, timeout)
|
||||
return done.result()
|
||||
|
||||
async def close(self):
|
||||
self.protocol.close()
|
||||
|
||||
async def getpeername(self):
|
||||
return self.transport.get_extra_info('peername')
|
||||
|
||||
async def getsockname(self):
|
||||
return self.transport.get_extra_info('sockname')
|
||||
|
||||
|
||||
class StreamSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, af, reader, writer):
|
||||
self.family = af
|
||||
self.reader = reader
|
||||
self.writer = writer
|
||||
|
||||
async def sendall(self, what, timeout):
|
||||
self.writer.write(what)
|
||||
return await _maybe_wait_for(self.writer.drain(), timeout)
|
||||
|
||||
async def recv(self, count, timeout):
|
||||
return await _maybe_wait_for(self.reader.read(count),
|
||||
timeout)
|
||||
|
||||
async def close(self):
|
||||
self.writer.close()
|
||||
try:
|
||||
await self.writer.wait_closed()
|
||||
except AttributeError: # pragma: no cover
|
||||
pass
|
||||
|
||||
async def getpeername(self):
|
||||
return self.writer.get_extra_info('peername')
|
||||
|
||||
async def getsockname(self):
|
||||
return self.writer.get_extra_info('sockname')
|
||||
|
||||
|
||||
class Backend(dns._asyncbackend.Backend):
|
||||
def name(self):
|
||||
return 'asyncio'
|
||||
|
||||
async def make_socket(self, af, socktype, proto=0,
|
||||
source=None, destination=None, timeout=None,
|
||||
ssl_context=None, server_hostname=None):
|
||||
loop = _get_running_loop()
|
||||
if socktype == socket.SOCK_DGRAM:
|
||||
transport, protocol = await loop.create_datagram_endpoint(
|
||||
_DatagramProtocol, source, family=af,
|
||||
proto=proto)
|
||||
return DatagramSocket(af, transport, protocol)
|
||||
elif socktype == socket.SOCK_STREAM:
|
||||
(r, w) = await _maybe_wait_for(
|
||||
asyncio.open_connection(destination[0],
|
||||
destination[1],
|
||||
ssl=ssl_context,
|
||||
family=af,
|
||||
proto=proto,
|
||||
local_addr=source,
|
||||
server_hostname=server_hostname),
|
||||
timeout)
|
||||
return StreamSocket(af, r, w)
|
||||
raise NotImplementedError('unsupported socket ' +
|
||||
f'type {socktype}') # pragma: no cover
|
||||
|
||||
async def sleep(self, interval):
|
||||
await asyncio.sleep(interval)
|
108
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_curio_backend.py
vendored
Normal file
108
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_curio_backend.py
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
"""curio async I/O library query support"""
|
||||
|
||||
import socket
|
||||
import curio
|
||||
import curio.socket # type: ignore
|
||||
|
||||
import dns._asyncbackend
|
||||
import dns.exception
|
||||
import dns.inet
|
||||
|
||||
|
||||
def _maybe_timeout(timeout):
|
||||
if timeout:
|
||||
return curio.ignore_after(timeout)
|
||||
else:
|
||||
return dns._asyncbackend.NullContext()
|
||||
|
||||
|
||||
# for brevity
|
||||
_lltuple = dns.inet.low_level_address_tuple
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
class DatagramSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, socket):
|
||||
self.socket = socket
|
||||
self.family = socket.family
|
||||
|
||||
async def sendto(self, what, destination, timeout):
|
||||
async with _maybe_timeout(timeout):
|
||||
return await self.socket.sendto(what, destination)
|
||||
raise dns.exception.Timeout(timeout=timeout) # pragma: no cover
|
||||
|
||||
async def recvfrom(self, size, timeout):
|
||||
async with _maybe_timeout(timeout):
|
||||
return await self.socket.recvfrom(size)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def close(self):
|
||||
await self.socket.close()
|
||||
|
||||
async def getpeername(self):
|
||||
return self.socket.getpeername()
|
||||
|
||||
async def getsockname(self):
|
||||
return self.socket.getsockname()
|
||||
|
||||
|
||||
class StreamSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, socket):
|
||||
self.socket = socket
|
||||
self.family = socket.family
|
||||
|
||||
async def sendall(self, what, timeout):
|
||||
async with _maybe_timeout(timeout):
|
||||
return await self.socket.sendall(what)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def recv(self, size, timeout):
|
||||
async with _maybe_timeout(timeout):
|
||||
return await self.socket.recv(size)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def close(self):
|
||||
await self.socket.close()
|
||||
|
||||
async def getpeername(self):
|
||||
return self.socket.getpeername()
|
||||
|
||||
async def getsockname(self):
|
||||
return self.socket.getsockname()
|
||||
|
||||
|
||||
class Backend(dns._asyncbackend.Backend):
|
||||
def name(self):
|
||||
return 'curio'
|
||||
|
||||
async def make_socket(self, af, socktype, proto=0,
|
||||
source=None, destination=None, timeout=None,
|
||||
ssl_context=None, server_hostname=None):
|
||||
if socktype == socket.SOCK_DGRAM:
|
||||
s = curio.socket.socket(af, socktype, proto)
|
||||
try:
|
||||
if source:
|
||||
s.bind(_lltuple(source, af))
|
||||
except Exception: # pragma: no cover
|
||||
await s.close()
|
||||
raise
|
||||
return DatagramSocket(s)
|
||||
elif socktype == socket.SOCK_STREAM:
|
||||
if source:
|
||||
source_addr = _lltuple(source, af)
|
||||
else:
|
||||
source_addr = None
|
||||
async with _maybe_timeout(timeout):
|
||||
s = await curio.open_connection(destination[0], destination[1],
|
||||
ssl=ssl_context,
|
||||
source_addr=source_addr,
|
||||
server_hostname=server_hostname)
|
||||
return StreamSocket(s)
|
||||
raise NotImplementedError('unsupported socket ' +
|
||||
f'type {socktype}') # pragma: no cover
|
||||
|
||||
async def sleep(self, interval):
|
||||
await curio.sleep(interval)
|
84
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_immutable_attr.py
vendored
Normal file
84
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_immutable_attr.py
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# This implementation of the immutable decorator is for python 3.6,
|
||||
# which doesn't have Context Variables. This implementation is somewhat
|
||||
# costly for classes with slots, as it adds a __dict__ to them.
|
||||
|
||||
|
||||
import inspect
|
||||
|
||||
|
||||
class _Immutable:
|
||||
"""Immutable mixin class"""
|
||||
|
||||
# Note we MUST NOT have __slots__ as that causes
|
||||
#
|
||||
# TypeError: multiple bases have instance lay-out conflict
|
||||
#
|
||||
# when we get mixed in with another class with slots. When we
|
||||
# get mixed into something with slots, it effectively adds __dict__ to
|
||||
# the slots of the other class, which allows attribute setting to work,
|
||||
# albeit at the cost of the dictionary.
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if not hasattr(self, '_immutable_init') or \
|
||||
self._immutable_init is not self:
|
||||
raise TypeError("object doesn't support attribute assignment")
|
||||
else:
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if not hasattr(self, '_immutable_init') or \
|
||||
self._immutable_init is not self:
|
||||
raise TypeError("object doesn't support attribute assignment")
|
||||
else:
|
||||
super().__delattr__(name)
|
||||
|
||||
|
||||
def _immutable_init(f):
|
||||
def nf(*args, **kwargs):
|
||||
try:
|
||||
# Are we already initializing an immutable class?
|
||||
previous = args[0]._immutable_init
|
||||
except AttributeError:
|
||||
# We are the first!
|
||||
previous = None
|
||||
object.__setattr__(args[0], '_immutable_init', args[0])
|
||||
try:
|
||||
# call the actual __init__
|
||||
f(*args, **kwargs)
|
||||
finally:
|
||||
if not previous:
|
||||
# If we started the initialzation, establish immutability
|
||||
# by removing the attribute that allows mutation
|
||||
object.__delattr__(args[0], '_immutable_init')
|
||||
nf.__signature__ = inspect.signature(f)
|
||||
return nf
|
||||
|
||||
|
||||
def immutable(cls):
|
||||
if _Immutable in cls.__mro__:
|
||||
# Some ancestor already has the mixin, so just make sure we keep
|
||||
# following the __init__ protocol.
|
||||
cls.__init__ = _immutable_init(cls.__init__)
|
||||
if hasattr(cls, '__setstate__'):
|
||||
cls.__setstate__ = _immutable_init(cls.__setstate__)
|
||||
ncls = cls
|
||||
else:
|
||||
# Mixin the Immutable class and follow the __init__ protocol.
|
||||
class ncls(_Immutable, cls):
|
||||
|
||||
@_immutable_init
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if hasattr(cls, '__setstate__'):
|
||||
@_immutable_init
|
||||
def __setstate__(self, *args, **kwargs):
|
||||
super().__setstate__(*args, **kwargs)
|
||||
|
||||
# make ncls have the same name and module as cls
|
||||
ncls.__name__ = cls.__name__
|
||||
ncls.__qualname__ = cls.__qualname__
|
||||
ncls.__module__ = cls.__module__
|
||||
return ncls
|
75
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_immutable_ctx.py
vendored
Normal file
75
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_immutable_ctx.py
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# This implementation of the immutable decorator requires python >=
|
||||
# 3.7, and is significantly more storage efficient when making classes
|
||||
# with slots immutable. It's also faster.
|
||||
|
||||
import contextvars
|
||||
import inspect
|
||||
|
||||
|
||||
_in__init__ = contextvars.ContextVar('_immutable_in__init__', default=False)
|
||||
|
||||
|
||||
class _Immutable:
|
||||
"""Immutable mixin class"""
|
||||
|
||||
# We set slots to the empty list to say "we don't have any attributes".
|
||||
# We do this so that if we're mixed in with a class with __slots__, we
|
||||
# don't cause a __dict__ to be added which would waste space.
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if _in__init__.get() is not self:
|
||||
raise TypeError("object doesn't support attribute assignment")
|
||||
else:
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if _in__init__.get() is not self:
|
||||
raise TypeError("object doesn't support attribute assignment")
|
||||
else:
|
||||
super().__delattr__(name)
|
||||
|
||||
|
||||
def _immutable_init(f):
|
||||
def nf(*args, **kwargs):
|
||||
previous = _in__init__.set(args[0])
|
||||
try:
|
||||
# call the actual __init__
|
||||
f(*args, **kwargs)
|
||||
finally:
|
||||
_in__init__.reset(previous)
|
||||
nf.__signature__ = inspect.signature(f)
|
||||
return nf
|
||||
|
||||
|
||||
def immutable(cls):
|
||||
if _Immutable in cls.__mro__:
|
||||
# Some ancestor already has the mixin, so just make sure we keep
|
||||
# following the __init__ protocol.
|
||||
cls.__init__ = _immutable_init(cls.__init__)
|
||||
if hasattr(cls, '__setstate__'):
|
||||
cls.__setstate__ = _immutable_init(cls.__setstate__)
|
||||
ncls = cls
|
||||
else:
|
||||
# Mixin the Immutable class and follow the __init__ protocol.
|
||||
class ncls(_Immutable, cls):
|
||||
# We have to do the __slots__ declaration here too!
|
||||
__slots__ = ()
|
||||
|
||||
@_immutable_init
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if hasattr(cls, '__setstate__'):
|
||||
@_immutable_init
|
||||
def __setstate__(self, *args, **kwargs):
|
||||
super().__setstate__(*args, **kwargs)
|
||||
|
||||
# make ncls have the same name and module as cls
|
||||
ncls.__name__ = cls.__name__
|
||||
ncls.__qualname__ = cls.__qualname__
|
||||
ncls.__module__ = cls.__module__
|
||||
return ncls
|
121
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_trio_backend.py
vendored
Normal file
121
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/_trio_backend.py
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
"""trio async I/O library query support"""
|
||||
|
||||
import socket
|
||||
import trio
|
||||
import trio.socket # type: ignore
|
||||
|
||||
import dns._asyncbackend
|
||||
import dns.exception
|
||||
import dns.inet
|
||||
|
||||
|
||||
def _maybe_timeout(timeout):
|
||||
if timeout:
|
||||
return trio.move_on_after(timeout)
|
||||
else:
|
||||
return dns._asyncbackend.NullContext()
|
||||
|
||||
|
||||
# for brevity
|
||||
_lltuple = dns.inet.low_level_address_tuple
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
class DatagramSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, socket):
|
||||
self.socket = socket
|
||||
self.family = socket.family
|
||||
|
||||
async def sendto(self, what, destination, timeout):
|
||||
with _maybe_timeout(timeout):
|
||||
return await self.socket.sendto(what, destination)
|
||||
raise dns.exception.Timeout(timeout=timeout) # pragma: no cover
|
||||
|
||||
async def recvfrom(self, size, timeout):
|
||||
with _maybe_timeout(timeout):
|
||||
return await self.socket.recvfrom(size)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def close(self):
|
||||
self.socket.close()
|
||||
|
||||
async def getpeername(self):
|
||||
return self.socket.getpeername()
|
||||
|
||||
async def getsockname(self):
|
||||
return self.socket.getsockname()
|
||||
|
||||
|
||||
class StreamSocket(dns._asyncbackend.DatagramSocket):
|
||||
def __init__(self, family, stream, tls=False):
|
||||
self.family = family
|
||||
self.stream = stream
|
||||
self.tls = tls
|
||||
|
||||
async def sendall(self, what, timeout):
|
||||
with _maybe_timeout(timeout):
|
||||
return await self.stream.send_all(what)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def recv(self, size, timeout):
|
||||
with _maybe_timeout(timeout):
|
||||
return await self.stream.receive_some(size)
|
||||
raise dns.exception.Timeout(timeout=timeout)
|
||||
|
||||
async def close(self):
|
||||
await self.stream.aclose()
|
||||
|
||||
async def getpeername(self):
|
||||
if self.tls:
|
||||
return self.stream.transport_stream.socket.getpeername()
|
||||
else:
|
||||
return self.stream.socket.getpeername()
|
||||
|
||||
async def getsockname(self):
|
||||
if self.tls:
|
||||
return self.stream.transport_stream.socket.getsockname()
|
||||
else:
|
||||
return self.stream.socket.getsockname()
|
||||
|
||||
|
||||
class Backend(dns._asyncbackend.Backend):
|
||||
def name(self):
|
||||
return 'trio'
|
||||
|
||||
async def make_socket(self, af, socktype, proto=0, source=None,
|
||||
destination=None, timeout=None,
|
||||
ssl_context=None, server_hostname=None):
|
||||
s = trio.socket.socket(af, socktype, proto)
|
||||
stream = None
|
||||
try:
|
||||
if source:
|
||||
await s.bind(_lltuple(source, af))
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
with _maybe_timeout(timeout):
|
||||
await s.connect(_lltuple(destination, af))
|
||||
except Exception: # pragma: no cover
|
||||
s.close()
|
||||
raise
|
||||
if socktype == socket.SOCK_DGRAM:
|
||||
return DatagramSocket(s)
|
||||
elif socktype == socket.SOCK_STREAM:
|
||||
stream = trio.SocketStream(s)
|
||||
s = None
|
||||
tls = False
|
||||
if ssl_context:
|
||||
tls = True
|
||||
try:
|
||||
stream = trio.SSLStream(stream, ssl_context,
|
||||
server_hostname=server_hostname)
|
||||
except Exception: # pragma: no cover
|
||||
await stream.aclose()
|
||||
raise
|
||||
return StreamSocket(af, stream, tls)
|
||||
raise NotImplementedError('unsupported socket ' +
|
||||
f'type {socktype}') # pragma: no cover
|
||||
|
||||
async def sleep(self, interval):
|
||||
await trio.sleep(interval)
|
101
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncbackend.py
vendored
Normal file
101
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncbackend.py
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
import dns.exception
|
||||
|
||||
# pylint: disable=unused-import
|
||||
|
||||
from dns._asyncbackend import Socket, DatagramSocket, \
|
||||
StreamSocket, Backend # noqa:
|
||||
|
||||
# pylint: enable=unused-import
|
||||
|
||||
_default_backend = None
|
||||
|
||||
_backends = {}
|
||||
|
||||
# Allow sniffio import to be disabled for testing purposes
|
||||
_no_sniffio = False
|
||||
|
||||
class AsyncLibraryNotFoundError(dns.exception.DNSException):
|
||||
pass
|
||||
|
||||
|
||||
def get_backend(name):
|
||||
"""Get the specified asychronous backend.
|
||||
|
||||
*name*, a ``str``, the name of the backend. Currently the "trio",
|
||||
"curio", and "asyncio" backends are available.
|
||||
|
||||
Raises NotImplementError if an unknown backend name is specified.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel,redefined-outer-name
|
||||
backend = _backends.get(name)
|
||||
if backend:
|
||||
return backend
|
||||
if name == 'trio':
|
||||
import dns._trio_backend
|
||||
backend = dns._trio_backend.Backend()
|
||||
elif name == 'curio':
|
||||
import dns._curio_backend
|
||||
backend = dns._curio_backend.Backend()
|
||||
elif name == 'asyncio':
|
||||
import dns._asyncio_backend
|
||||
backend = dns._asyncio_backend.Backend()
|
||||
else:
|
||||
raise NotImplementedError(f'unimplemented async backend {name}')
|
||||
_backends[name] = backend
|
||||
return backend
|
||||
|
||||
|
||||
def sniff():
|
||||
"""Attempt to determine the in-use asynchronous I/O library by using
|
||||
the ``sniffio`` module if it is available.
|
||||
|
||||
Returns the name of the library, or raises AsyncLibraryNotFoundError
|
||||
if the library cannot be determined.
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
try:
|
||||
if _no_sniffio:
|
||||
raise ImportError
|
||||
import sniffio
|
||||
try:
|
||||
return sniffio.current_async_library()
|
||||
except sniffio.AsyncLibraryNotFoundError:
|
||||
raise AsyncLibraryNotFoundError('sniffio cannot determine ' +
|
||||
'async library')
|
||||
except ImportError:
|
||||
import asyncio
|
||||
try:
|
||||
asyncio.get_running_loop()
|
||||
return 'asyncio'
|
||||
except RuntimeError:
|
||||
raise AsyncLibraryNotFoundError('no async library detected')
|
||||
except AttributeError: # pragma: no cover
|
||||
# we have to check current_task on 3.6
|
||||
if not asyncio.Task.current_task():
|
||||
raise AsyncLibraryNotFoundError('no async library detected')
|
||||
return 'asyncio'
|
||||
|
||||
|
||||
def get_default_backend():
|
||||
"""Get the default backend, initializing it if necessary.
|
||||
"""
|
||||
if _default_backend:
|
||||
return _default_backend
|
||||
|
||||
return set_default_backend(sniff())
|
||||
|
||||
|
||||
def set_default_backend(name):
|
||||
"""Set the default backend.
|
||||
|
||||
It's not normally necessary to call this method, as
|
||||
``get_default_backend()`` will initialize the backend
|
||||
appropriately in many cases. If ``sniffio`` is not installed, or
|
||||
in testing situations, this function allows the backend to be set
|
||||
explicitly.
|
||||
"""
|
||||
global _default_backend
|
||||
_default_backend = get_backend(name)
|
||||
return _default_backend
|
434
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncquery.py
vendored
Normal file
434
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncquery.py
vendored
Normal file
|
@ -0,0 +1,434 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Talk to a DNS server."""
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
|
||||
import dns.asyncbackend
|
||||
import dns.exception
|
||||
import dns.inet
|
||||
import dns.name
|
||||
import dns.message
|
||||
import dns.rcode
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
|
||||
from dns.query import _compute_times, _matches_destination, BadResponse, ssl, \
|
||||
UDPMode
|
||||
|
||||
|
||||
# for brevity
|
||||
_lltuple = dns.inet.low_level_address_tuple
|
||||
|
||||
|
||||
def _source_tuple(af, address, port):
|
||||
# Make a high level source tuple, or return None if address and port
|
||||
# are both None
|
||||
if address or port:
|
||||
if address is None:
|
||||
if af == socket.AF_INET:
|
||||
address = '0.0.0.0'
|
||||
elif af == socket.AF_INET6:
|
||||
address = '::'
|
||||
else:
|
||||
raise NotImplementedError(f'unknown address family {af}')
|
||||
return (address, port)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _timeout(expiration, now=None):
|
||||
if expiration:
|
||||
if not now:
|
||||
now = time.time()
|
||||
return max(expiration - now, 0)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
async def send_udp(sock, what, destination, expiration=None):
|
||||
"""Send a DNS message to the specified UDP socket.
|
||||
|
||||
*sock*, a ``dns.asyncbackend.DatagramSocket``.
|
||||
|
||||
*what*, a ``bytes`` or ``dns.message.Message``, the message to send.
|
||||
|
||||
*destination*, a destination tuple appropriate for the address family
|
||||
of the socket, specifying where to send the query.
|
||||
|
||||
*expiration*, a ``float`` or ``None``, the absolute time at which
|
||||
a timeout exception should be raised. If ``None``, no timeout will
|
||||
occur.
|
||||
|
||||
Returns an ``(int, float)`` tuple of bytes sent and the sent time.
|
||||
"""
|
||||
|
||||
if isinstance(what, dns.message.Message):
|
||||
what = what.to_wire()
|
||||
sent_time = time.time()
|
||||
n = await sock.sendto(what, destination, _timeout(expiration, sent_time))
|
||||
return (n, sent_time)
|
||||
|
||||
|
||||
async def receive_udp(sock, destination=None, expiration=None,
|
||||
ignore_unexpected=False, one_rr_per_rrset=False,
|
||||
keyring=None, request_mac=b'', ignore_trailing=False,
|
||||
raise_on_truncation=False):
|
||||
"""Read a DNS message from a UDP socket.
|
||||
|
||||
*sock*, a ``dns.asyncbackend.DatagramSocket``.
|
||||
|
||||
See :py:func:`dns.query.receive_udp()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
|
||||
wire = b''
|
||||
while 1:
|
||||
(wire, from_address) = await sock.recvfrom(65535, _timeout(expiration))
|
||||
if _matches_destination(sock.family, from_address, destination,
|
||||
ignore_unexpected):
|
||||
break
|
||||
received_time = time.time()
|
||||
r = dns.message.from_wire(wire, keyring=keyring, request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing,
|
||||
raise_on_truncation=raise_on_truncation)
|
||||
return (r, received_time, from_address)
|
||||
|
||||
async def udp(q, where, timeout=None, port=53, source=None, source_port=0,
|
||||
ignore_unexpected=False, one_rr_per_rrset=False,
|
||||
ignore_trailing=False, raise_on_truncation=False, sock=None,
|
||||
backend=None):
|
||||
"""Return the response obtained after sending a query via UDP.
|
||||
|
||||
*sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``,
|
||||
the socket to use for the query. If ``None``, the default, a
|
||||
socket is created. Note that if a socket is provided, the
|
||||
*source*, *source_port*, and *backend* are ignored.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.query.udp()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
wire = q.to_wire()
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
s = None
|
||||
# After 3.6 is no longer supported, this can use an AsyncExitStack.
|
||||
try:
|
||||
af = dns.inet.af_for_address(where)
|
||||
destination = _lltuple((where, port), af)
|
||||
if sock:
|
||||
s = sock
|
||||
else:
|
||||
if not backend:
|
||||
backend = dns.asyncbackend.get_default_backend()
|
||||
stuple = _source_tuple(af, source, source_port)
|
||||
s = await backend.make_socket(af, socket.SOCK_DGRAM, 0, stuple)
|
||||
await send_udp(s, wire, destination, expiration)
|
||||
(r, received_time, _) = await receive_udp(s, destination, expiration,
|
||||
ignore_unexpected,
|
||||
one_rr_per_rrset,
|
||||
q.keyring, q.mac,
|
||||
ignore_trailing,
|
||||
raise_on_truncation)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
finally:
|
||||
if not sock and s:
|
||||
await s.close()
|
||||
|
||||
async def udp_with_fallback(q, where, timeout=None, port=53, source=None,
|
||||
source_port=0, ignore_unexpected=False,
|
||||
one_rr_per_rrset=False, ignore_trailing=False,
|
||||
udp_sock=None, tcp_sock=None, backend=None):
|
||||
"""Return the response to the query, trying UDP first and falling back
|
||||
to TCP if UDP results in a truncated response.
|
||||
|
||||
*udp_sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``,
|
||||
the socket to use for the UDP query. If ``None``, the default, a
|
||||
socket is created. Note that if a socket is provided the *source*,
|
||||
*source_port*, and *backend* are ignored for the UDP query.
|
||||
|
||||
*tcp_sock*, a ``dns.asyncbackend.StreamSocket``, or ``None``, the
|
||||
socket to use for the TCP query. If ``None``, the default, a
|
||||
socket is created. Note that if a socket is provided *where*,
|
||||
*source*, *source_port*, and *backend* are ignored for the TCP query.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.query.udp_with_fallback()` for the documentation
|
||||
of the other parameters, exceptions, and return type of this
|
||||
method.
|
||||
"""
|
||||
try:
|
||||
response = await udp(q, where, timeout, port, source, source_port,
|
||||
ignore_unexpected, one_rr_per_rrset,
|
||||
ignore_trailing, True, udp_sock, backend)
|
||||
return (response, False)
|
||||
except dns.message.Truncated:
|
||||
response = await tcp(q, where, timeout, port, source, source_port,
|
||||
one_rr_per_rrset, ignore_trailing, tcp_sock,
|
||||
backend)
|
||||
return (response, True)
|
||||
|
||||
|
||||
async def send_tcp(sock, what, expiration=None):
|
||||
"""Send a DNS message to the specified TCP socket.
|
||||
|
||||
*sock*, a ``dns.asyncbackend.StreamSocket``.
|
||||
|
||||
See :py:func:`dns.query.send_tcp()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
|
||||
if isinstance(what, dns.message.Message):
|
||||
what = what.to_wire()
|
||||
l = len(what)
|
||||
# copying the wire into tcpmsg is inefficient, but lets us
|
||||
# avoid writev() or doing a short write that would get pushed
|
||||
# onto the net
|
||||
tcpmsg = struct.pack("!H", l) + what
|
||||
sent_time = time.time()
|
||||
await sock.sendall(tcpmsg, _timeout(expiration, sent_time))
|
||||
return (len(tcpmsg), sent_time)
|
||||
|
||||
|
||||
async def _read_exactly(sock, count, expiration):
|
||||
"""Read the specified number of bytes from stream. Keep trying until we
|
||||
either get the desired amount, or we hit EOF.
|
||||
"""
|
||||
s = b''
|
||||
while count > 0:
|
||||
n = await sock.recv(count, _timeout(expiration))
|
||||
if n == b'':
|
||||
raise EOFError
|
||||
count = count - len(n)
|
||||
s = s + n
|
||||
return s
|
||||
|
||||
|
||||
async def receive_tcp(sock, expiration=None, one_rr_per_rrset=False,
|
||||
keyring=None, request_mac=b'', ignore_trailing=False):
|
||||
"""Read a DNS message from a TCP socket.
|
||||
|
||||
*sock*, a ``dns.asyncbackend.StreamSocket``.
|
||||
|
||||
See :py:func:`dns.query.receive_tcp()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
|
||||
ldata = await _read_exactly(sock, 2, expiration)
|
||||
(l,) = struct.unpack("!H", ldata)
|
||||
wire = await _read_exactly(sock, l, expiration)
|
||||
received_time = time.time()
|
||||
r = dns.message.from_wire(wire, keyring=keyring, request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing)
|
||||
return (r, received_time)
|
||||
|
||||
|
||||
async def tcp(q, where, timeout=None, port=53, source=None, source_port=0,
|
||||
one_rr_per_rrset=False, ignore_trailing=False, sock=None,
|
||||
backend=None):
|
||||
"""Return the response obtained after sending a query via TCP.
|
||||
|
||||
*sock*, a ``dns.asyncbacket.StreamSocket``, or ``None``, the
|
||||
socket to use for the query. If ``None``, the default, a socket
|
||||
is created. Note that if a socket is provided
|
||||
*where*, *port*, *source*, *source_port*, and *backend* are ignored.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.query.tcp()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
|
||||
wire = q.to_wire()
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
s = None
|
||||
# After 3.6 is no longer supported, this can use an AsyncExitStack.
|
||||
try:
|
||||
if sock:
|
||||
# Verify that the socket is connected, as if it's not connected,
|
||||
# it's not writable, and the polling in send_tcp() will time out or
|
||||
# hang forever.
|
||||
await sock.getpeername()
|
||||
s = sock
|
||||
else:
|
||||
# These are simple (address, port) pairs, not
|
||||
# family-dependent tuples you pass to lowlevel socket
|
||||
# code.
|
||||
af = dns.inet.af_for_address(where)
|
||||
stuple = _source_tuple(af, source, source_port)
|
||||
dtuple = (where, port)
|
||||
if not backend:
|
||||
backend = dns.asyncbackend.get_default_backend()
|
||||
s = await backend.make_socket(af, socket.SOCK_STREAM, 0, stuple,
|
||||
dtuple, timeout)
|
||||
await send_tcp(s, wire, expiration)
|
||||
(r, received_time) = await receive_tcp(s, expiration, one_rr_per_rrset,
|
||||
q.keyring, q.mac,
|
||||
ignore_trailing)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
finally:
|
||||
if not sock and s:
|
||||
await s.close()
|
||||
|
||||
async def tls(q, where, timeout=None, port=853, source=None, source_port=0,
|
||||
one_rr_per_rrset=False, ignore_trailing=False, sock=None,
|
||||
backend=None, ssl_context=None, server_hostname=None):
|
||||
"""Return the response obtained after sending a query via TLS.
|
||||
|
||||
*sock*, an ``asyncbackend.StreamSocket``, or ``None``, the socket
|
||||
to use for the query. If ``None``, the default, a socket is
|
||||
created. Note that if a socket is provided, it must be a
|
||||
connected SSL stream socket, and *where*, *port*,
|
||||
*source*, *source_port*, *backend*, *ssl_context*, and *server_hostname*
|
||||
are ignored.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.query.tls()` for the documentation of the other
|
||||
parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
# After 3.6 is no longer supported, this can use an AsyncExitStack.
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
if not sock:
|
||||
if ssl_context is None:
|
||||
ssl_context = ssl.create_default_context()
|
||||
if server_hostname is None:
|
||||
ssl_context.check_hostname = False
|
||||
else:
|
||||
ssl_context = None
|
||||
server_hostname = None
|
||||
af = dns.inet.af_for_address(where)
|
||||
stuple = _source_tuple(af, source, source_port)
|
||||
dtuple = (where, port)
|
||||
if not backend:
|
||||
backend = dns.asyncbackend.get_default_backend()
|
||||
s = await backend.make_socket(af, socket.SOCK_STREAM, 0, stuple,
|
||||
dtuple, timeout, ssl_context,
|
||||
server_hostname)
|
||||
else:
|
||||
s = sock
|
||||
try:
|
||||
timeout = _timeout(expiration)
|
||||
response = await tcp(q, where, timeout, port, source, source_port,
|
||||
one_rr_per_rrset, ignore_trailing, s, backend)
|
||||
end_time = time.time()
|
||||
response.time = end_time - begin_time
|
||||
return response
|
||||
finally:
|
||||
if not sock and s:
|
||||
await s.close()
|
||||
|
||||
async def inbound_xfr(where, txn_manager, query=None,
|
||||
port=53, timeout=None, lifetime=None, source=None,
|
||||
source_port=0, udp_mode=UDPMode.NEVER,
|
||||
backend=None):
|
||||
"""Conduct an inbound transfer and apply it via a transaction from the
|
||||
txn_manager.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.query.inbound_xfr()` for the documentation of
|
||||
the other parameters, exceptions, and return type of this method.
|
||||
"""
|
||||
if query is None:
|
||||
(query, serial) = dns.xfr.make_query(txn_manager)
|
||||
rdtype = query.question[0].rdtype
|
||||
is_ixfr = rdtype == dns.rdatatype.IXFR
|
||||
origin = txn_manager.from_wire_origin()
|
||||
wire = query.to_wire()
|
||||
af = dns.inet.af_for_address(where)
|
||||
stuple = _source_tuple(af, source, source_port)
|
||||
dtuple = (where, port)
|
||||
(_, expiration) = _compute_times(lifetime)
|
||||
retry = True
|
||||
while retry:
|
||||
retry = False
|
||||
if is_ixfr and udp_mode != UDPMode.NEVER:
|
||||
sock_type = socket.SOCK_DGRAM
|
||||
is_udp = True
|
||||
else:
|
||||
sock_type = socket.SOCK_STREAM
|
||||
is_udp = False
|
||||
if not backend:
|
||||
backend = dns.asyncbackend.get_default_backend()
|
||||
s = await backend.make_socket(af, sock_type, 0, stuple, dtuple,
|
||||
_timeout(expiration))
|
||||
async with s:
|
||||
if is_udp:
|
||||
await s.sendto(wire, dtuple, _timeout(expiration))
|
||||
else:
|
||||
tcpmsg = struct.pack("!H", len(wire)) + wire
|
||||
await s.sendall(tcpmsg, expiration)
|
||||
with dns.xfr.Inbound(txn_manager, rdtype, serial,
|
||||
is_udp) as inbound:
|
||||
done = False
|
||||
tsig_ctx = None
|
||||
while not done:
|
||||
(_, mexpiration) = _compute_times(timeout)
|
||||
if mexpiration is None or \
|
||||
(expiration is not None and mexpiration > expiration):
|
||||
mexpiration = expiration
|
||||
if is_udp:
|
||||
destination = _lltuple((where, port), af)
|
||||
while True:
|
||||
timeout = _timeout(mexpiration)
|
||||
(rwire, from_address) = await s.recvfrom(65535,
|
||||
timeout)
|
||||
if _matches_destination(af, from_address,
|
||||
destination, True):
|
||||
break
|
||||
else:
|
||||
ldata = await _read_exactly(s, 2, mexpiration)
|
||||
(l,) = struct.unpack("!H", ldata)
|
||||
rwire = await _read_exactly(s, l, mexpiration)
|
||||
is_ixfr = (rdtype == dns.rdatatype.IXFR)
|
||||
r = dns.message.from_wire(rwire, keyring=query.keyring,
|
||||
request_mac=query.mac, xfr=True,
|
||||
origin=origin, tsig_ctx=tsig_ctx,
|
||||
multi=(not is_udp),
|
||||
one_rr_per_rrset=is_ixfr)
|
||||
try:
|
||||
done = inbound.process_message(r)
|
||||
except dns.xfr.UseTCP:
|
||||
assert is_udp # should not happen if we used TCP!
|
||||
if udp_mode == UDPMode.ONLY:
|
||||
raise
|
||||
done = True
|
||||
retry = True
|
||||
udp_mode = UDPMode.NEVER
|
||||
continue
|
||||
tsig_ctx = r.tsig_ctx
|
||||
if not retry and query.keyring and not r.had_tsig:
|
||||
raise dns.exception.FormError("missing TSIG")
|
230
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncresolver.py
vendored
Normal file
230
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/asyncresolver.py
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Asynchronous DNS stub resolver."""
|
||||
|
||||
import time
|
||||
|
||||
import dns.asyncbackend
|
||||
import dns.asyncquery
|
||||
import dns.exception
|
||||
import dns.query
|
||||
import dns.resolver
|
||||
|
||||
# import some resolver symbols for brevity
|
||||
from dns.resolver import NXDOMAIN, NoAnswer, NotAbsolute, NoRootSOA
|
||||
|
||||
|
||||
# for indentation purposes below
|
||||
_udp = dns.asyncquery.udp
|
||||
_tcp = dns.asyncquery.tcp
|
||||
|
||||
|
||||
class Resolver(dns.resolver.BaseResolver):
|
||||
"""Asynchronous DNS stub resolver."""
|
||||
|
||||
async def resolve(self, qname, rdtype=dns.rdatatype.A,
|
||||
rdclass=dns.rdataclass.IN,
|
||||
tcp=False, source=None, raise_on_no_answer=True,
|
||||
source_port=0, lifetime=None, search=None,
|
||||
backend=None):
|
||||
"""Query nameservers asynchronously to find the answer to the question.
|
||||
|
||||
*backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
|
||||
the default, then dnspython will use the default backend.
|
||||
|
||||
See :py:func:`dns.resolver.Resolver.resolve()` for the
|
||||
documentation of the other parameters, exceptions, and return
|
||||
type of this method.
|
||||
"""
|
||||
|
||||
resolution = dns.resolver._Resolution(self, qname, rdtype, rdclass, tcp,
|
||||
raise_on_no_answer, search)
|
||||
if not backend:
|
||||
backend = dns.asyncbackend.get_default_backend()
|
||||
start = time.time()
|
||||
while True:
|
||||
(request, answer) = resolution.next_request()
|
||||
# Note we need to say "if answer is not None" and not just
|
||||
# "if answer" because answer implements __len__, and python
|
||||
# will call that. We want to return if we have an answer
|
||||
# object, including in cases where its length is 0.
|
||||
if answer is not None:
|
||||
# cache hit!
|
||||
return answer
|
||||
done = False
|
||||
while not done:
|
||||
(nameserver, port, tcp, backoff) = resolution.next_nameserver()
|
||||
if backoff:
|
||||
await backend.sleep(backoff)
|
||||
timeout = self._compute_timeout(start, lifetime)
|
||||
try:
|
||||
if dns.inet.is_address(nameserver):
|
||||
if tcp:
|
||||
response = await _tcp(request, nameserver,
|
||||
timeout, port,
|
||||
source, source_port,
|
||||
backend=backend)
|
||||
else:
|
||||
response = await _udp(request, nameserver,
|
||||
timeout, port,
|
||||
source, source_port,
|
||||
raise_on_truncation=True,
|
||||
backend=backend)
|
||||
else:
|
||||
# We don't do DoH yet.
|
||||
raise NotImplementedError
|
||||
except Exception as ex:
|
||||
(_, done) = resolution.query_result(None, ex)
|
||||
continue
|
||||
(answer, done) = resolution.query_result(response, None)
|
||||
# Note we need to say "if answer is not None" and not just
|
||||
# "if answer" because answer implements __len__, and python
|
||||
# will call that. We want to return if we have an answer
|
||||
# object, including in cases where its length is 0.
|
||||
if answer is not None:
|
||||
return answer
|
||||
|
||||
async def resolve_address(self, ipaddr, *args, **kwargs):
|
||||
"""Use an asynchronous resolver to run a reverse query for PTR
|
||||
records.
|
||||
|
||||
This utilizes the resolve() method to perform a PTR lookup on the
|
||||
specified IP address.
|
||||
|
||||
*ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get
|
||||
the PTR record for.
|
||||
|
||||
All other arguments that can be passed to the resolve() function
|
||||
except for rdtype and rdclass are also supported by this
|
||||
function.
|
||||
|
||||
"""
|
||||
|
||||
return await self.resolve(dns.reversename.from_address(ipaddr),
|
||||
rdtype=dns.rdatatype.PTR,
|
||||
rdclass=dns.rdataclass.IN,
|
||||
*args, **kwargs)
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
async def canonical_name(self, name):
|
||||
"""Determine the canonical name of *name*.
|
||||
|
||||
The canonical name is the name the resolver uses for queries
|
||||
after all CNAME and DNAME renamings have been applied.
|
||||
|
||||
*name*, a ``dns.name.Name`` or ``str``, the query name.
|
||||
|
||||
This method can raise any exception that ``resolve()`` can
|
||||
raise, other than ``dns.resolver.NoAnswer`` and
|
||||
``dns.resolver.NXDOMAIN``.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
try:
|
||||
answer = await self.resolve(name, raise_on_no_answer=False)
|
||||
canonical_name = answer.canonical_name
|
||||
except dns.resolver.NXDOMAIN as e:
|
||||
canonical_name = e.canonical_name
|
||||
return canonical_name
|
||||
|
||||
|
||||
default_resolver = None
|
||||
|
||||
|
||||
def get_default_resolver():
|
||||
"""Get the default asynchronous resolver, initializing it if necessary."""
|
||||
if default_resolver is None:
|
||||
reset_default_resolver()
|
||||
return default_resolver
|
||||
|
||||
|
||||
def reset_default_resolver():
|
||||
"""Re-initialize default asynchronous resolver.
|
||||
|
||||
Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX
|
||||
systems) will be re-read immediately.
|
||||
"""
|
||||
|
||||
global default_resolver
|
||||
default_resolver = Resolver()
|
||||
|
||||
|
||||
async def resolve(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
|
||||
tcp=False, source=None, raise_on_no_answer=True,
|
||||
source_port=0, lifetime=None, search=None, backend=None):
|
||||
"""Query nameservers asynchronously to find the answer to the question.
|
||||
|
||||
This is a convenience function that uses the default resolver
|
||||
object to make the query.
|
||||
|
||||
See :py:func:`dns.asyncresolver.Resolver.resolve` for more
|
||||
information on the parameters.
|
||||
"""
|
||||
|
||||
return await get_default_resolver().resolve(qname, rdtype, rdclass, tcp,
|
||||
source, raise_on_no_answer,
|
||||
source_port, lifetime, search,
|
||||
backend)
|
||||
|
||||
|
||||
async def resolve_address(ipaddr, *args, **kwargs):
|
||||
"""Use a resolver to run a reverse query for PTR records.
|
||||
|
||||
See :py:func:`dns.asyncresolver.Resolver.resolve_address` for more
|
||||
information on the parameters.
|
||||
"""
|
||||
|
||||
return await get_default_resolver().resolve_address(ipaddr, *args, **kwargs)
|
||||
|
||||
async def canonical_name(name):
|
||||
"""Determine the canonical name of *name*.
|
||||
|
||||
See :py:func:`dns.resolver.Resolver.canonical_name` for more
|
||||
information on the parameters and possible exceptions.
|
||||
"""
|
||||
|
||||
return await get_default_resolver().canonical_name(name)
|
||||
|
||||
async def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False,
|
||||
resolver=None, backend=None):
|
||||
"""Find the name of the zone which contains the specified name.
|
||||
|
||||
See :py:func:`dns.resolver.Resolver.zone_for_name` for more
|
||||
information on the parameters and possible exceptions.
|
||||
"""
|
||||
|
||||
if isinstance(name, str):
|
||||
name = dns.name.from_text(name, dns.name.root)
|
||||
if resolver is None:
|
||||
resolver = get_default_resolver()
|
||||
if not name.is_absolute():
|
||||
raise NotAbsolute(name)
|
||||
while True:
|
||||
try:
|
||||
answer = await resolver.resolve(name, dns.rdatatype.SOA, rdclass,
|
||||
tcp, backend=backend)
|
||||
if answer.rrset.name == name:
|
||||
return name
|
||||
# otherwise we were CNAMEd or DNAMEd and need to look higher
|
||||
except (NXDOMAIN, NoAnswer):
|
||||
pass
|
||||
try:
|
||||
name = name.parent()
|
||||
except dns.name.NoParent: # pragma: no cover
|
||||
raise NoRootSOA
|
605
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/dnssec.py
vendored
Normal file
605
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/dnssec.py
vendored
Normal file
|
@ -0,0 +1,605 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Common DNSSEC-related functions and constants."""
|
||||
|
||||
import hashlib
|
||||
import struct
|
||||
import time
|
||||
import base64
|
||||
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
import dns.name
|
||||
import dns.node
|
||||
import dns.rdataset
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
import dns.rdataclass
|
||||
|
||||
|
||||
class UnsupportedAlgorithm(dns.exception.DNSException):
|
||||
"""The DNSSEC algorithm is not supported."""
|
||||
|
||||
|
||||
class ValidationFailure(dns.exception.DNSException):
|
||||
"""The DNSSEC signature is invalid."""
|
||||
|
||||
|
||||
class Algorithm(dns.enum.IntEnum):
|
||||
RSAMD5 = 1
|
||||
DH = 2
|
||||
DSA = 3
|
||||
ECC = 4
|
||||
RSASHA1 = 5
|
||||
DSANSEC3SHA1 = 6
|
||||
RSASHA1NSEC3SHA1 = 7
|
||||
RSASHA256 = 8
|
||||
RSASHA512 = 10
|
||||
ECCGOST = 12
|
||||
ECDSAP256SHA256 = 13
|
||||
ECDSAP384SHA384 = 14
|
||||
ED25519 = 15
|
||||
ED448 = 16
|
||||
INDIRECT = 252
|
||||
PRIVATEDNS = 253
|
||||
PRIVATEOID = 254
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 255
|
||||
|
||||
|
||||
def algorithm_from_text(text):
|
||||
"""Convert text into a DNSSEC algorithm value.
|
||||
|
||||
*text*, a ``str``, the text to convert to into an algorithm value.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return Algorithm.from_text(text)
|
||||
|
||||
|
||||
def algorithm_to_text(value):
|
||||
"""Convert a DNSSEC algorithm value to text
|
||||
|
||||
*value*, an ``int`` a DNSSEC algorithm.
|
||||
|
||||
Returns a ``str``, the name of a DNSSEC algorithm.
|
||||
"""
|
||||
|
||||
return Algorithm.to_text(value)
|
||||
|
||||
|
||||
def key_id(key):
|
||||
"""Return the key id (a 16-bit number) for the specified key.
|
||||
|
||||
*key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY``
|
||||
|
||||
Returns an ``int`` between 0 and 65535
|
||||
"""
|
||||
|
||||
rdata = key.to_wire()
|
||||
if key.algorithm == Algorithm.RSAMD5:
|
||||
return (rdata[-3] << 8) + rdata[-2]
|
||||
else:
|
||||
total = 0
|
||||
for i in range(len(rdata) // 2):
|
||||
total += (rdata[2 * i] << 8) + \
|
||||
rdata[2 * i + 1]
|
||||
if len(rdata) % 2 != 0:
|
||||
total += rdata[len(rdata) - 1] << 8
|
||||
total += ((total >> 16) & 0xffff)
|
||||
return total & 0xffff
|
||||
|
||||
class DSDigest(dns.enum.IntEnum):
|
||||
"""DNSSEC Delgation Signer Digest Algorithm"""
|
||||
|
||||
SHA1 = 1
|
||||
SHA256 = 2
|
||||
SHA384 = 4
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 255
|
||||
|
||||
|
||||
def make_ds(name, key, algorithm, origin=None):
|
||||
"""Create a DS record for a DNSSEC key.
|
||||
|
||||
*name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record.
|
||||
|
||||
*key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY``, the key the DS is about.
|
||||
|
||||
*algorithm*, a ``str`` or ``int`` specifying the hash algorithm.
|
||||
The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case
|
||||
does not matter for these strings.
|
||||
|
||||
*origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name,
|
||||
then it will be made absolute using the specified origin.
|
||||
|
||||
Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
|
||||
|
||||
Returns a ``dns.rdtypes.ANY.DS.DS``
|
||||
"""
|
||||
|
||||
try:
|
||||
if isinstance(algorithm, str):
|
||||
algorithm = DSDigest[algorithm.upper()]
|
||||
except Exception:
|
||||
raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm)
|
||||
|
||||
if algorithm == DSDigest.SHA1:
|
||||
dshash = hashlib.sha1()
|
||||
elif algorithm == DSDigest.SHA256:
|
||||
dshash = hashlib.sha256()
|
||||
elif algorithm == DSDigest.SHA384:
|
||||
dshash = hashlib.sha384()
|
||||
else:
|
||||
raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm)
|
||||
|
||||
if isinstance(name, str):
|
||||
name = dns.name.from_text(name, origin)
|
||||
dshash.update(name.canonicalize().to_wire())
|
||||
dshash.update(key.to_wire(origin=origin))
|
||||
digest = dshash.digest()
|
||||
|
||||
dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, algorithm) + \
|
||||
digest
|
||||
return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0,
|
||||
len(dsrdata))
|
||||
|
||||
|
||||
def _find_candidate_keys(keys, rrsig):
|
||||
candidate_keys = []
|
||||
value = keys.get(rrsig.signer)
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, dns.node.Node):
|
||||
try:
|
||||
rdataset = value.find_rdataset(dns.rdataclass.IN,
|
||||
dns.rdatatype.DNSKEY)
|
||||
except KeyError:
|
||||
return None
|
||||
else:
|
||||
rdataset = value
|
||||
for rdata in rdataset:
|
||||
if rdata.algorithm == rrsig.algorithm and \
|
||||
key_id(rdata) == rrsig.key_tag:
|
||||
candidate_keys.append(rdata)
|
||||
return candidate_keys
|
||||
|
||||
|
||||
def _is_rsa(algorithm):
|
||||
return algorithm in (Algorithm.RSAMD5, Algorithm.RSASHA1,
|
||||
Algorithm.RSASHA1NSEC3SHA1, Algorithm.RSASHA256,
|
||||
Algorithm.RSASHA512)
|
||||
|
||||
|
||||
def _is_dsa(algorithm):
|
||||
return algorithm in (Algorithm.DSA, Algorithm.DSANSEC3SHA1)
|
||||
|
||||
|
||||
def _is_ecdsa(algorithm):
|
||||
return algorithm in (Algorithm.ECDSAP256SHA256, Algorithm.ECDSAP384SHA384)
|
||||
|
||||
|
||||
def _is_eddsa(algorithm):
|
||||
return algorithm in (Algorithm.ED25519, Algorithm.ED448)
|
||||
|
||||
|
||||
def _is_gost(algorithm):
|
||||
return algorithm == Algorithm.ECCGOST
|
||||
|
||||
|
||||
def _is_md5(algorithm):
|
||||
return algorithm == Algorithm.RSAMD5
|
||||
|
||||
|
||||
def _is_sha1(algorithm):
|
||||
return algorithm in (Algorithm.DSA, Algorithm.RSASHA1,
|
||||
Algorithm.DSANSEC3SHA1, Algorithm.RSASHA1NSEC3SHA1)
|
||||
|
||||
|
||||
def _is_sha256(algorithm):
|
||||
return algorithm in (Algorithm.RSASHA256, Algorithm.ECDSAP256SHA256)
|
||||
|
||||
|
||||
def _is_sha384(algorithm):
|
||||
return algorithm == Algorithm.ECDSAP384SHA384
|
||||
|
||||
|
||||
def _is_sha512(algorithm):
|
||||
return algorithm == Algorithm.RSASHA512
|
||||
|
||||
|
||||
def _make_hash(algorithm):
|
||||
if _is_md5(algorithm):
|
||||
return hashes.MD5()
|
||||
if _is_sha1(algorithm):
|
||||
return hashes.SHA1()
|
||||
if _is_sha256(algorithm):
|
||||
return hashes.SHA256()
|
||||
if _is_sha384(algorithm):
|
||||
return hashes.SHA384()
|
||||
if _is_sha512(algorithm):
|
||||
return hashes.SHA512()
|
||||
if algorithm == Algorithm.ED25519:
|
||||
return hashes.SHA512()
|
||||
if algorithm == Algorithm.ED448:
|
||||
return hashes.SHAKE256(114)
|
||||
|
||||
raise ValidationFailure('unknown hash for algorithm %u' % algorithm)
|
||||
|
||||
|
||||
def _bytes_to_long(b):
|
||||
return int.from_bytes(b, 'big')
|
||||
|
||||
|
||||
def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):
|
||||
"""Validate an RRset against a single signature rdata, throwing an
|
||||
exception if validation is not successful.
|
||||
|
||||
*rrset*, the RRset to validate. This can be a
|
||||
``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
|
||||
tuple.
|
||||
|
||||
*rrsig*, a ``dns.rdata.Rdata``, the signature to validate.
|
||||
|
||||
*keys*, the key dictionary, used to find the DNSKEY associated
|
||||
with a given name. The dictionary is keyed by a
|
||||
``dns.name.Name``, and has ``dns.node.Node`` or
|
||||
``dns.rdataset.Rdataset`` values.
|
||||
|
||||
*origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative
|
||||
names.
|
||||
|
||||
*now*, an ``int`` or ``None``, the time, in seconds since the epoch, to
|
||||
use as the current time when validating. If ``None``, the actual current
|
||||
time is used.
|
||||
|
||||
Raises ``ValidationFailure`` if the signature is expired, not yet valid,
|
||||
the public key is invalid, the algorithm is unknown, the verification
|
||||
fails, etc.
|
||||
|
||||
Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by
|
||||
dnspython but not implemented.
|
||||
"""
|
||||
|
||||
if isinstance(origin, str):
|
||||
origin = dns.name.from_text(origin, dns.name.root)
|
||||
|
||||
candidate_keys = _find_candidate_keys(keys, rrsig)
|
||||
if candidate_keys is None:
|
||||
raise ValidationFailure('unknown key')
|
||||
|
||||
for candidate_key in candidate_keys:
|
||||
# For convenience, allow the rrset to be specified as a (name,
|
||||
# rdataset) tuple as well as a proper rrset
|
||||
if isinstance(rrset, tuple):
|
||||
rrname = rrset[0]
|
||||
rdataset = rrset[1]
|
||||
else:
|
||||
rrname = rrset.name
|
||||
rdataset = rrset
|
||||
|
||||
if now is None:
|
||||
now = time.time()
|
||||
if rrsig.expiration < now:
|
||||
raise ValidationFailure('expired')
|
||||
if rrsig.inception > now:
|
||||
raise ValidationFailure('not yet valid')
|
||||
|
||||
if _is_rsa(rrsig.algorithm):
|
||||
keyptr = candidate_key.key
|
||||
(bytes_,) = struct.unpack('!B', keyptr[0:1])
|
||||
keyptr = keyptr[1:]
|
||||
if bytes_ == 0:
|
||||
(bytes_,) = struct.unpack('!H', keyptr[0:2])
|
||||
keyptr = keyptr[2:]
|
||||
rsa_e = keyptr[0:bytes_]
|
||||
rsa_n = keyptr[bytes_:]
|
||||
try:
|
||||
public_key = rsa.RSAPublicNumbers(
|
||||
_bytes_to_long(rsa_e),
|
||||
_bytes_to_long(rsa_n)).public_key(default_backend())
|
||||
except ValueError:
|
||||
raise ValidationFailure('invalid public key')
|
||||
sig = rrsig.signature
|
||||
elif _is_dsa(rrsig.algorithm):
|
||||
keyptr = candidate_key.key
|
||||
(t,) = struct.unpack('!B', keyptr[0:1])
|
||||
keyptr = keyptr[1:]
|
||||
octets = 64 + t * 8
|
||||
dsa_q = keyptr[0:20]
|
||||
keyptr = keyptr[20:]
|
||||
dsa_p = keyptr[0:octets]
|
||||
keyptr = keyptr[octets:]
|
||||
dsa_g = keyptr[0:octets]
|
||||
keyptr = keyptr[octets:]
|
||||
dsa_y = keyptr[0:octets]
|
||||
try:
|
||||
public_key = dsa.DSAPublicNumbers(
|
||||
_bytes_to_long(dsa_y),
|
||||
dsa.DSAParameterNumbers(
|
||||
_bytes_to_long(dsa_p),
|
||||
_bytes_to_long(dsa_q),
|
||||
_bytes_to_long(dsa_g))).public_key(default_backend())
|
||||
except ValueError:
|
||||
raise ValidationFailure('invalid public key')
|
||||
sig_r = rrsig.signature[1:21]
|
||||
sig_s = rrsig.signature[21:]
|
||||
sig = utils.encode_dss_signature(_bytes_to_long(sig_r),
|
||||
_bytes_to_long(sig_s))
|
||||
elif _is_ecdsa(rrsig.algorithm):
|
||||
keyptr = candidate_key.key
|
||||
if rrsig.algorithm == Algorithm.ECDSAP256SHA256:
|
||||
curve = ec.SECP256R1()
|
||||
octets = 32
|
||||
else:
|
||||
curve = ec.SECP384R1()
|
||||
octets = 48
|
||||
ecdsa_x = keyptr[0:octets]
|
||||
ecdsa_y = keyptr[octets:octets * 2]
|
||||
try:
|
||||
public_key = ec.EllipticCurvePublicNumbers(
|
||||
curve=curve,
|
||||
x=_bytes_to_long(ecdsa_x),
|
||||
y=_bytes_to_long(ecdsa_y)).public_key(default_backend())
|
||||
except ValueError:
|
||||
raise ValidationFailure('invalid public key')
|
||||
sig_r = rrsig.signature[0:octets]
|
||||
sig_s = rrsig.signature[octets:]
|
||||
sig = utils.encode_dss_signature(_bytes_to_long(sig_r),
|
||||
_bytes_to_long(sig_s))
|
||||
|
||||
elif _is_eddsa(rrsig.algorithm):
|
||||
keyptr = candidate_key.key
|
||||
if rrsig.algorithm == Algorithm.ED25519:
|
||||
loader = ed25519.Ed25519PublicKey
|
||||
else:
|
||||
loader = ed448.Ed448PublicKey
|
||||
try:
|
||||
public_key = loader.from_public_bytes(keyptr)
|
||||
except ValueError:
|
||||
raise ValidationFailure('invalid public key')
|
||||
sig = rrsig.signature
|
||||
elif _is_gost(rrsig.algorithm):
|
||||
raise UnsupportedAlgorithm(
|
||||
'algorithm "%s" not supported by dnspython' %
|
||||
algorithm_to_text(rrsig.algorithm))
|
||||
else:
|
||||
raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm)
|
||||
|
||||
data = b''
|
||||
data += rrsig.to_wire(origin=origin)[:18]
|
||||
data += rrsig.signer.to_digestable(origin)
|
||||
|
||||
# Derelativize the name before considering labels.
|
||||
rrname = rrname.derelativize(origin)
|
||||
|
||||
if len(rrname) - 1 < rrsig.labels:
|
||||
raise ValidationFailure('owner name longer than RRSIG labels')
|
||||
elif rrsig.labels < len(rrname) - 1:
|
||||
suffix = rrname.split(rrsig.labels + 1)[1]
|
||||
rrname = dns.name.from_text('*', suffix)
|
||||
rrnamebuf = rrname.to_digestable()
|
||||
rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass,
|
||||
rrsig.original_ttl)
|
||||
rrlist = sorted(rdataset)
|
||||
for rr in rrlist:
|
||||
data += rrnamebuf
|
||||
data += rrfixed
|
||||
rrdata = rr.to_digestable(origin)
|
||||
rrlen = struct.pack('!H', len(rrdata))
|
||||
data += rrlen
|
||||
data += rrdata
|
||||
|
||||
chosen_hash = _make_hash(rrsig.algorithm)
|
||||
try:
|
||||
if _is_rsa(rrsig.algorithm):
|
||||
public_key.verify(sig, data, padding.PKCS1v15(), chosen_hash)
|
||||
elif _is_dsa(rrsig.algorithm):
|
||||
public_key.verify(sig, data, chosen_hash)
|
||||
elif _is_ecdsa(rrsig.algorithm):
|
||||
public_key.verify(sig, data, ec.ECDSA(chosen_hash))
|
||||
elif _is_eddsa(rrsig.algorithm):
|
||||
public_key.verify(sig, data)
|
||||
else:
|
||||
# Raise here for code clarity; this won't actually ever happen
|
||||
# since if the algorithm is really unknown we'd already have
|
||||
# raised an exception above
|
||||
raise ValidationFailure('unknown algorithm %u' %
|
||||
rrsig.algorithm) # pragma: no cover
|
||||
# If we got here, we successfully verified so we can return
|
||||
# without error
|
||||
return
|
||||
except InvalidSignature:
|
||||
# this happens on an individual validation failure
|
||||
continue
|
||||
# nothing verified -- raise failure:
|
||||
raise ValidationFailure('verify failure')
|
||||
|
||||
|
||||
def _validate(rrset, rrsigset, keys, origin=None, now=None):
|
||||
"""Validate an RRset against a signature RRset, throwing an exception
|
||||
if none of the signatures validate.
|
||||
|
||||
*rrset*, the RRset to validate. This can be a
|
||||
``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
|
||||
tuple.
|
||||
|
||||
*rrsigset*, the signature RRset. This can be a
|
||||
``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
|
||||
tuple.
|
||||
|
||||
*keys*, the key dictionary, used to find the DNSKEY associated
|
||||
with a given name. The dictionary is keyed by a
|
||||
``dns.name.Name``, and has ``dns.node.Node`` or
|
||||
``dns.rdataset.Rdataset`` values.
|
||||
|
||||
*origin*, a ``dns.name.Name``, the origin to use for relative names;
|
||||
defaults to None.
|
||||
|
||||
*now*, an ``int`` or ``None``, the time, in seconds since the epoch, to
|
||||
use as the current time when validating. If ``None``, the actual current
|
||||
time is used.
|
||||
|
||||
Raises ``ValidationFailure`` if the signature is expired, not yet valid,
|
||||
the public key is invalid, the algorithm is unknown, the verification
|
||||
fails, etc.
|
||||
"""
|
||||
|
||||
if isinstance(origin, str):
|
||||
origin = dns.name.from_text(origin, dns.name.root)
|
||||
|
||||
if isinstance(rrset, tuple):
|
||||
rrname = rrset[0]
|
||||
else:
|
||||
rrname = rrset.name
|
||||
|
||||
if isinstance(rrsigset, tuple):
|
||||
rrsigname = rrsigset[0]
|
||||
rrsigrdataset = rrsigset[1]
|
||||
else:
|
||||
rrsigname = rrsigset.name
|
||||
rrsigrdataset = rrsigset
|
||||
|
||||
rrname = rrname.choose_relativity(origin)
|
||||
rrsigname = rrsigname.choose_relativity(origin)
|
||||
if rrname != rrsigname:
|
||||
raise ValidationFailure("owner names do not match")
|
||||
|
||||
for rrsig in rrsigrdataset:
|
||||
try:
|
||||
_validate_rrsig(rrset, rrsig, keys, origin, now)
|
||||
return
|
||||
except (ValidationFailure, UnsupportedAlgorithm):
|
||||
pass
|
||||
raise ValidationFailure("no RRSIGs validated")
|
||||
|
||||
|
||||
class NSEC3Hash(dns.enum.IntEnum):
|
||||
"""NSEC3 hash algorithm"""
|
||||
|
||||
SHA1 = 1
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 255
|
||||
|
||||
def nsec3_hash(domain, salt, iterations, algorithm):
|
||||
"""
|
||||
Calculate the NSEC3 hash, according to
|
||||
https://tools.ietf.org/html/rfc5155#section-5
|
||||
|
||||
*domain*, a ``dns.name.Name`` or ``str``, the name to hash.
|
||||
|
||||
*salt*, a ``str``, ``bytes``, or ``None``, the hash salt. If a
|
||||
string, it is decoded as a hex string.
|
||||
|
||||
*iterations*, an ``int``, the number of iterations.
|
||||
|
||||
*algorithm*, a ``str`` or ``int``, the hash algorithm.
|
||||
The only defined algorithm is SHA1.
|
||||
|
||||
Returns a ``str``, the encoded NSEC3 hash.
|
||||
"""
|
||||
|
||||
b32_conversion = str.maketrans(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "0123456789ABCDEFGHIJKLMNOPQRSTUV"
|
||||
)
|
||||
|
||||
try:
|
||||
if isinstance(algorithm, str):
|
||||
algorithm = NSEC3Hash[algorithm.upper()]
|
||||
except Exception:
|
||||
raise ValueError("Wrong hash algorithm (only SHA1 is supported)")
|
||||
|
||||
if algorithm != NSEC3Hash.SHA1:
|
||||
raise ValueError("Wrong hash algorithm (only SHA1 is supported)")
|
||||
|
||||
salt_encoded = salt
|
||||
if salt is None:
|
||||
salt_encoded = b''
|
||||
elif isinstance(salt, str):
|
||||
if len(salt) % 2 == 0:
|
||||
salt_encoded = bytes.fromhex(salt)
|
||||
else:
|
||||
raise ValueError("Invalid salt length")
|
||||
|
||||
if not isinstance(domain, dns.name.Name):
|
||||
domain = dns.name.from_text(domain)
|
||||
domain_encoded = domain.canonicalize().to_wire()
|
||||
|
||||
digest = hashlib.sha1(domain_encoded + salt_encoded).digest()
|
||||
for _ in range(iterations):
|
||||
digest = hashlib.sha1(digest + salt_encoded).digest()
|
||||
|
||||
output = base64.b32encode(digest).decode("utf-8")
|
||||
output = output.translate(b32_conversion)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def _need_pyca(*args, **kwargs):
|
||||
raise ImportError("DNSSEC validation requires " +
|
||||
"python cryptography") # pragma: no cover
|
||||
|
||||
|
||||
try:
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.primitives.asymmetric import utils
|
||||
from cryptography.hazmat.primitives.asymmetric import dsa
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
from cryptography.hazmat.primitives.asymmetric import ed448
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
except ImportError: # pragma: no cover
|
||||
validate = _need_pyca
|
||||
validate_rrsig = _need_pyca
|
||||
_have_pyca = False
|
||||
else:
|
||||
validate = _validate # type: ignore
|
||||
validate_rrsig = _validate_rrsig # type: ignore
|
||||
_have_pyca = True
|
||||
|
||||
### BEGIN generated Algorithm constants
|
||||
|
||||
RSAMD5 = Algorithm.RSAMD5
|
||||
DH = Algorithm.DH
|
||||
DSA = Algorithm.DSA
|
||||
ECC = Algorithm.ECC
|
||||
RSASHA1 = Algorithm.RSASHA1
|
||||
DSANSEC3SHA1 = Algorithm.DSANSEC3SHA1
|
||||
RSASHA1NSEC3SHA1 = Algorithm.RSASHA1NSEC3SHA1
|
||||
RSASHA256 = Algorithm.RSASHA256
|
||||
RSASHA512 = Algorithm.RSASHA512
|
||||
ECCGOST = Algorithm.ECCGOST
|
||||
ECDSAP256SHA256 = Algorithm.ECDSAP256SHA256
|
||||
ECDSAP384SHA384 = Algorithm.ECDSAP384SHA384
|
||||
ED25519 = Algorithm.ED25519
|
||||
ED448 = Algorithm.ED448
|
||||
INDIRECT = Algorithm.INDIRECT
|
||||
PRIVATEDNS = Algorithm.PRIVATEDNS
|
||||
PRIVATEOID = Algorithm.PRIVATEOID
|
||||
|
||||
### END generated Algorithm constants
|
104
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/e164.py
vendored
Normal file
104
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/e164.py
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2006-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS E.164 helpers."""
|
||||
|
||||
import dns.exception
|
||||
import dns.name
|
||||
import dns.resolver
|
||||
|
||||
#: The public E.164 domain.
|
||||
public_enum_domain = dns.name.from_text('e164.arpa.')
|
||||
|
||||
|
||||
def from_e164(text, origin=public_enum_domain):
|
||||
"""Convert an E.164 number in textual form into a Name object whose
|
||||
value is the ENUM domain name for that number.
|
||||
|
||||
Non-digits in the text are ignored, i.e. "16505551212",
|
||||
"+1.650.555.1212" and "1 (650) 555-1212" are all the same.
|
||||
|
||||
*text*, a ``str``, is an E.164 number in textual form.
|
||||
|
||||
*origin*, a ``dns.name.Name``, the domain in which the number
|
||||
should be constructed. The default is ``e164.arpa.``.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
parts = [d for d in text if d.isdigit()]
|
||||
parts.reverse()
|
||||
return dns.name.from_text('.'.join(parts), origin=origin)
|
||||
|
||||
|
||||
def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
|
||||
"""Convert an ENUM domain name into an E.164 number.
|
||||
|
||||
Note that dnspython does not have any information about preferred
|
||||
number formats within national numbering plans, so all numbers are
|
||||
emitted as a simple string of digits, prefixed by a '+' (unless
|
||||
*want_plus_prefix* is ``False``).
|
||||
|
||||
*name* is a ``dns.name.Name``, the ENUM domain name.
|
||||
|
||||
*origin* is a ``dns.name.Name``, a domain containing the ENUM
|
||||
domain name. The name is relativized to this domain before being
|
||||
converted to text. If ``None``, no relativization is done.
|
||||
|
||||
*want_plus_prefix* is a ``bool``. If True, add a '+' to the beginning of
|
||||
the returned number.
|
||||
|
||||
Returns a ``str``.
|
||||
|
||||
"""
|
||||
if origin is not None:
|
||||
name = name.relativize(origin)
|
||||
dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1]
|
||||
if len(dlabels) != len(name.labels):
|
||||
raise dns.exception.SyntaxError('non-digit labels in ENUM domain name')
|
||||
dlabels.reverse()
|
||||
text = b''.join(dlabels)
|
||||
if want_plus_prefix:
|
||||
text = b'+' + text
|
||||
return text.decode()
|
||||
|
||||
|
||||
def query(number, domains, resolver=None):
|
||||
"""Look for NAPTR RRs for the specified number in the specified domains.
|
||||
|
||||
e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.'])
|
||||
|
||||
*number*, a ``str`` is the number to look for.
|
||||
|
||||
*domains* is an iterable containing ``dns.name.Name`` values.
|
||||
|
||||
*resolver*, a ``dns.resolver.Resolver``, is the resolver to use. If
|
||||
``None``, the default resolver is used.
|
||||
"""
|
||||
|
||||
if resolver is None:
|
||||
resolver = dns.resolver.get_default_resolver()
|
||||
e_nx = dns.resolver.NXDOMAIN()
|
||||
for domain in domains:
|
||||
if isinstance(domain, str):
|
||||
domain = dns.name.from_text(domain)
|
||||
qname = dns.e164.from_e164(number, domain)
|
||||
try:
|
||||
return resolver.resolve(qname, 'NAPTR')
|
||||
except dns.resolver.NXDOMAIN as e:
|
||||
e_nx += e
|
||||
raise e_nx
|
376
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/edns.py
vendored
Normal file
376
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/edns.py
vendored
Normal file
|
@ -0,0 +1,376 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2009-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""EDNS Options"""
|
||||
|
||||
import math
|
||||
import socket
|
||||
import struct
|
||||
|
||||
import dns.enum
|
||||
import dns.inet
|
||||
import dns.rdata
|
||||
|
||||
|
||||
class OptionType(dns.enum.IntEnum):
|
||||
#: NSID
|
||||
NSID = 3
|
||||
#: DAU
|
||||
DAU = 5
|
||||
#: DHU
|
||||
DHU = 6
|
||||
#: N3U
|
||||
N3U = 7
|
||||
#: ECS (client-subnet)
|
||||
ECS = 8
|
||||
#: EXPIRE
|
||||
EXPIRE = 9
|
||||
#: COOKIE
|
||||
COOKIE = 10
|
||||
#: KEEPALIVE
|
||||
KEEPALIVE = 11
|
||||
#: PADDING
|
||||
PADDING = 12
|
||||
#: CHAIN
|
||||
CHAIN = 13
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 65535
|
||||
|
||||
|
||||
class Option:
|
||||
|
||||
"""Base class for all EDNS option types."""
|
||||
|
||||
def __init__(self, otype):
|
||||
"""Initialize an option.
|
||||
|
||||
*otype*, an ``int``, is the option type.
|
||||
"""
|
||||
self.otype = OptionType.make(otype)
|
||||
|
||||
def to_wire(self, file=None):
|
||||
"""Convert an option to wire format.
|
||||
|
||||
Returns a ``bytes`` or ``None``.
|
||||
|
||||
"""
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, otype, parser):
|
||||
"""Build an EDNS option object from wire format.
|
||||
|
||||
*otype*, an ``int``, is the option type.
|
||||
|
||||
*parser*, a ``dns.wire.Parser``, the parser, which should be
|
||||
restructed to the option length.
|
||||
|
||||
Returns a ``dns.edns.Option``.
|
||||
"""
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
def _cmp(self, other):
|
||||
"""Compare an EDNS option with another option of the same type.
|
||||
|
||||
Returns < 0 if < *other*, 0 if == *other*, and > 0 if > *other*.
|
||||
"""
|
||||
wire = self.to_wire()
|
||||
owire = other.to_wire()
|
||||
if wire == owire:
|
||||
return 0
|
||||
if wire > owire:
|
||||
return 1
|
||||
return -1
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Option):
|
||||
return False
|
||||
if self.otype != other.otype:
|
||||
return False
|
||||
return self._cmp(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
if not isinstance(other, Option):
|
||||
return True
|
||||
if self.otype != other.otype:
|
||||
return True
|
||||
return self._cmp(other) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Option) or \
|
||||
self.otype != other.otype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
if not isinstance(other, Option) or \
|
||||
self.otype != other.otype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) <= 0
|
||||
|
||||
def __ge__(self, other):
|
||||
if not isinstance(other, Option) or \
|
||||
self.otype != other.otype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) >= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
if not isinstance(other, Option) or \
|
||||
self.otype != other.otype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) > 0
|
||||
|
||||
def __str__(self):
|
||||
return self.to_text()
|
||||
|
||||
|
||||
class GenericOption(Option):
|
||||
|
||||
"""Generic Option Class
|
||||
|
||||
This class is used for EDNS option types for which we have no better
|
||||
implementation.
|
||||
"""
|
||||
|
||||
def __init__(self, otype, data):
|
||||
super().__init__(otype)
|
||||
self.data = dns.rdata.Rdata._as_bytes(data, True)
|
||||
|
||||
def to_wire(self, file=None):
|
||||
if file:
|
||||
file.write(self.data)
|
||||
else:
|
||||
return self.data
|
||||
|
||||
def to_text(self):
|
||||
return "Generic %d" % self.otype
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, otype, parser):
|
||||
return cls(otype, parser.get_remaining())
|
||||
|
||||
|
||||
class ECSOption(Option):
|
||||
"""EDNS Client Subnet (ECS, RFC7871)"""
|
||||
|
||||
def __init__(self, address, srclen=None, scopelen=0):
|
||||
"""*address*, a ``str``, is the client address information.
|
||||
|
||||
*srclen*, an ``int``, the source prefix length, which is the
|
||||
leftmost number of bits of the address to be used for the
|
||||
lookup. The default is 24 for IPv4 and 56 for IPv6.
|
||||
|
||||
*scopelen*, an ``int``, the scope prefix length. This value
|
||||
must be 0 in queries, and should be set in responses.
|
||||
"""
|
||||
|
||||
super().__init__(OptionType.ECS)
|
||||
af = dns.inet.af_for_address(address)
|
||||
|
||||
if af == socket.AF_INET6:
|
||||
self.family = 2
|
||||
if srclen is None:
|
||||
srclen = 56
|
||||
address = dns.rdata.Rdata._as_ipv6_address(address)
|
||||
srclen = dns.rdata.Rdata._as_int(srclen, 0, 128)
|
||||
scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 128)
|
||||
elif af == socket.AF_INET:
|
||||
self.family = 1
|
||||
if srclen is None:
|
||||
srclen = 24
|
||||
address = dns.rdata.Rdata._as_ipv4_address(address)
|
||||
srclen = dns.rdata.Rdata._as_int(srclen, 0, 32)
|
||||
scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 32)
|
||||
else: # pragma: no cover (this will never happen)
|
||||
raise ValueError('Bad address family')
|
||||
|
||||
self.address = address
|
||||
self.srclen = srclen
|
||||
self.scopelen = scopelen
|
||||
|
||||
addrdata = dns.inet.inet_pton(af, address)
|
||||
nbytes = int(math.ceil(srclen / 8.0))
|
||||
|
||||
# Truncate to srclen and pad to the end of the last octet needed
|
||||
# See RFC section 6
|
||||
self.addrdata = addrdata[:nbytes]
|
||||
nbits = srclen % 8
|
||||
if nbits != 0:
|
||||
last = struct.pack('B',
|
||||
ord(self.addrdata[-1:]) & (0xff << (8 - nbits)))
|
||||
self.addrdata = self.addrdata[:-1] + last
|
||||
|
||||
def to_text(self):
|
||||
return "ECS {}/{} scope/{}".format(self.address, self.srclen,
|
||||
self.scopelen)
|
||||
|
||||
@staticmethod
|
||||
def from_text(text):
|
||||
"""Convert a string into a `dns.edns.ECSOption`
|
||||
|
||||
*text*, a `str`, the text form of the option.
|
||||
|
||||
Returns a `dns.edns.ECSOption`.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> import dns.edns
|
||||
>>>
|
||||
>>> # basic example
|
||||
>>> dns.edns.ECSOption.from_text('1.2.3.4/24')
|
||||
>>>
|
||||
>>> # also understands scope
|
||||
>>> dns.edns.ECSOption.from_text('1.2.3.4/24/32')
|
||||
>>>
|
||||
>>> # IPv6
|
||||
>>> dns.edns.ECSOption.from_text('2001:4b98::1/64/64')
|
||||
>>>
|
||||
>>> # it understands results from `dns.edns.ECSOption.to_text()`
|
||||
>>> dns.edns.ECSOption.from_text('ECS 1.2.3.4/24/32')
|
||||
"""
|
||||
optional_prefix = 'ECS'
|
||||
tokens = text.split()
|
||||
ecs_text = None
|
||||
if len(tokens) == 1:
|
||||
ecs_text = tokens[0]
|
||||
elif len(tokens) == 2:
|
||||
if tokens[0] != optional_prefix:
|
||||
raise ValueError('could not parse ECS from "{}"'.format(text))
|
||||
ecs_text = tokens[1]
|
||||
else:
|
||||
raise ValueError('could not parse ECS from "{}"'.format(text))
|
||||
n_slashes = ecs_text.count('/')
|
||||
if n_slashes == 1:
|
||||
address, srclen = ecs_text.split('/')
|
||||
scope = 0
|
||||
elif n_slashes == 2:
|
||||
address, srclen, scope = ecs_text.split('/')
|
||||
else:
|
||||
raise ValueError('could not parse ECS from "{}"'.format(text))
|
||||
try:
|
||||
scope = int(scope)
|
||||
except ValueError:
|
||||
raise ValueError('invalid scope ' +
|
||||
'"{}": scope must be an integer'.format(scope))
|
||||
try:
|
||||
srclen = int(srclen)
|
||||
except ValueError:
|
||||
raise ValueError('invalid srclen ' +
|
||||
'"{}": srclen must be an integer'.format(srclen))
|
||||
return ECSOption(address, srclen, scope)
|
||||
|
||||
def to_wire(self, file=None):
|
||||
value = (struct.pack('!HBB', self.family, self.srclen, self.scopelen) +
|
||||
self.addrdata)
|
||||
if file:
|
||||
file.write(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, otype, parser):
|
||||
family, src, scope = parser.get_struct('!HBB')
|
||||
addrlen = int(math.ceil(src / 8.0))
|
||||
prefix = parser.get_bytes(addrlen)
|
||||
if family == 1:
|
||||
pad = 4 - addrlen
|
||||
addr = dns.ipv4.inet_ntoa(prefix + b'\x00' * pad)
|
||||
elif family == 2:
|
||||
pad = 16 - addrlen
|
||||
addr = dns.ipv6.inet_ntoa(prefix + b'\x00' * pad)
|
||||
else:
|
||||
raise ValueError('unsupported family')
|
||||
|
||||
return cls(addr, src, scope)
|
||||
|
||||
|
||||
_type_to_class = {
|
||||
OptionType.ECS: ECSOption
|
||||
}
|
||||
|
||||
def get_option_class(otype):
|
||||
"""Return the class for the specified option type.
|
||||
|
||||
The GenericOption class is used if a more specific class is not
|
||||
known.
|
||||
"""
|
||||
|
||||
cls = _type_to_class.get(otype)
|
||||
if cls is None:
|
||||
cls = GenericOption
|
||||
return cls
|
||||
|
||||
|
||||
def option_from_wire_parser(otype, parser):
|
||||
"""Build an EDNS option object from wire format.
|
||||
|
||||
*otype*, an ``int``, is the option type.
|
||||
|
||||
*parser*, a ``dns.wire.Parser``, the parser, which should be
|
||||
restricted to the option length.
|
||||
|
||||
Returns an instance of a subclass of ``dns.edns.Option``.
|
||||
"""
|
||||
cls = get_option_class(otype)
|
||||
otype = OptionType.make(otype)
|
||||
return cls.from_wire_parser(otype, parser)
|
||||
|
||||
|
||||
def option_from_wire(otype, wire, current, olen):
|
||||
"""Build an EDNS option object from wire format.
|
||||
|
||||
*otype*, an ``int``, is the option type.
|
||||
|
||||
*wire*, a ``bytes``, is the wire-format message.
|
||||
|
||||
*current*, an ``int``, is the offset in *wire* of the beginning
|
||||
of the rdata.
|
||||
|
||||
*olen*, an ``int``, is the length of the wire-format option data
|
||||
|
||||
Returns an instance of a subclass of ``dns.edns.Option``.
|
||||
"""
|
||||
parser = dns.wire.Parser(wire, current)
|
||||
with parser.restrict_to(olen):
|
||||
return option_from_wire_parser(otype, parser)
|
||||
|
||||
def register_type(implementation, otype):
|
||||
"""Register the implementation of an option type.
|
||||
|
||||
*implementation*, a ``class``, is a subclass of ``dns.edns.Option``.
|
||||
|
||||
*otype*, an ``int``, is the option type.
|
||||
"""
|
||||
|
||||
_type_to_class[otype] = implementation
|
||||
|
||||
### BEGIN generated OptionType constants
|
||||
|
||||
NSID = OptionType.NSID
|
||||
DAU = OptionType.DAU
|
||||
DHU = OptionType.DHU
|
||||
N3U = OptionType.N3U
|
||||
ECS = OptionType.ECS
|
||||
EXPIRE = OptionType.EXPIRE
|
||||
COOKIE = OptionType.COOKIE
|
||||
KEEPALIVE = OptionType.KEEPALIVE
|
||||
PADDING = OptionType.PADDING
|
||||
CHAIN = OptionType.CHAIN
|
||||
|
||||
### END generated OptionType constants
|
129
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/entropy.py
vendored
Normal file
129
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/entropy.py
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2009-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import random
|
||||
import time
|
||||
try:
|
||||
import threading as _threading
|
||||
except ImportError: # pragma: no cover
|
||||
import dummy_threading as _threading # type: ignore
|
||||
|
||||
|
||||
class EntropyPool:
|
||||
|
||||
# This is an entropy pool for Python implementations that do not
|
||||
# have a working SystemRandom. I'm not sure there are any, but
|
||||
# leaving this code doesn't hurt anything as the library code
|
||||
# is used if present.
|
||||
|
||||
def __init__(self, seed=None):
|
||||
self.pool_index = 0
|
||||
self.digest = None
|
||||
self.next_byte = 0
|
||||
self.lock = _threading.Lock()
|
||||
self.hash = hashlib.sha1()
|
||||
self.hash_len = 20
|
||||
self.pool = bytearray(b'\0' * self.hash_len)
|
||||
if seed is not None:
|
||||
self._stir(bytearray(seed))
|
||||
self.seeded = True
|
||||
self.seed_pid = os.getpid()
|
||||
else:
|
||||
self.seeded = False
|
||||
self.seed_pid = 0
|
||||
|
||||
def _stir(self, entropy):
|
||||
for c in entropy:
|
||||
if self.pool_index == self.hash_len:
|
||||
self.pool_index = 0
|
||||
b = c & 0xff
|
||||
self.pool[self.pool_index] ^= b
|
||||
self.pool_index += 1
|
||||
|
||||
def stir(self, entropy):
|
||||
with self.lock:
|
||||
self._stir(entropy)
|
||||
|
||||
def _maybe_seed(self):
|
||||
if not self.seeded or self.seed_pid != os.getpid():
|
||||
try:
|
||||
seed = os.urandom(16)
|
||||
except Exception: # pragma: no cover
|
||||
try:
|
||||
with open('/dev/urandom', 'rb', 0) as r:
|
||||
seed = r.read(16)
|
||||
except Exception:
|
||||
seed = str(time.time())
|
||||
self.seeded = True
|
||||
self.seed_pid = os.getpid()
|
||||
self.digest = None
|
||||
seed = bytearray(seed)
|
||||
self._stir(seed)
|
||||
|
||||
def random_8(self):
|
||||
with self.lock:
|
||||
self._maybe_seed()
|
||||
if self.digest is None or self.next_byte == self.hash_len:
|
||||
self.hash.update(bytes(self.pool))
|
||||
self.digest = bytearray(self.hash.digest())
|
||||
self._stir(self.digest)
|
||||
self.next_byte = 0
|
||||
value = self.digest[self.next_byte]
|
||||
self.next_byte += 1
|
||||
return value
|
||||
|
||||
def random_16(self):
|
||||
return self.random_8() * 256 + self.random_8()
|
||||
|
||||
def random_32(self):
|
||||
return self.random_16() * 65536 + self.random_16()
|
||||
|
||||
def random_between(self, first, last):
|
||||
size = last - first + 1
|
||||
if size > 4294967296:
|
||||
raise ValueError('too big')
|
||||
if size > 65536:
|
||||
rand = self.random_32
|
||||
max = 4294967295
|
||||
elif size > 256:
|
||||
rand = self.random_16
|
||||
max = 65535
|
||||
else:
|
||||
rand = self.random_8
|
||||
max = 255
|
||||
return first + size * rand() // (max + 1)
|
||||
|
||||
pool = EntropyPool()
|
||||
|
||||
try:
|
||||
system_random = random.SystemRandom()
|
||||
except Exception: # pragma: no cover
|
||||
system_random = None
|
||||
|
||||
def random_16():
|
||||
if system_random is not None:
|
||||
return system_random.randrange(0, 65536)
|
||||
else:
|
||||
return pool.random_16()
|
||||
|
||||
def between(first, last):
|
||||
if system_random is not None:
|
||||
return system_random.randrange(first, last + 1)
|
||||
else:
|
||||
return pool.random_between(first, last)
|
90
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/enum.py
vendored
Normal file
90
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/enum.py
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import enum
|
||||
|
||||
class IntEnum(enum.IntEnum):
|
||||
@classmethod
|
||||
def _check_value(cls, value):
|
||||
max = cls._maximum()
|
||||
if value < 0 or value > max:
|
||||
name = cls._short_name()
|
||||
raise ValueError(f"{name} must be between >= 0 and <= {max}")
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, text):
|
||||
text = text.upper()
|
||||
try:
|
||||
return cls[text]
|
||||
except KeyError:
|
||||
pass
|
||||
prefix = cls._prefix()
|
||||
if text.startswith(prefix) and text[len(prefix):].isdigit():
|
||||
value = int(text[len(prefix):])
|
||||
cls._check_value(value)
|
||||
try:
|
||||
return cls(value)
|
||||
except ValueError:
|
||||
return value
|
||||
raise cls._unknown_exception_class()
|
||||
|
||||
@classmethod
|
||||
def to_text(cls, value):
|
||||
cls._check_value(value)
|
||||
try:
|
||||
return cls(value).name
|
||||
except ValueError:
|
||||
return f"{cls._prefix()}{value}"
|
||||
|
||||
@classmethod
|
||||
def make(cls, value):
|
||||
"""Convert text or a value into an enumerated type, if possible.
|
||||
|
||||
*value*, the ``int`` or ``str`` to convert.
|
||||
|
||||
Raises a class-specific exception if a ``str`` is provided that
|
||||
cannot be converted.
|
||||
|
||||
Raises ``ValueError`` if the value is out of range.
|
||||
|
||||
Returns an enumeration from the calling class corresponding to the
|
||||
value, if one is defined, or an ``int`` otherwise.
|
||||
"""
|
||||
|
||||
if isinstance(value, str):
|
||||
return cls.from_text(value)
|
||||
cls._check_value(value)
|
||||
try:
|
||||
return cls(value)
|
||||
except ValueError:
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
@classmethod
|
||||
def _short_name(cls):
|
||||
return cls.__name__.lower()
|
||||
|
||||
@classmethod
|
||||
def _prefix(cls):
|
||||
return ''
|
||||
|
||||
@classmethod
|
||||
def _unknown_exception_class(cls):
|
||||
return ValueError
|
142
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/exception.py
vendored
Normal file
142
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/exception.py
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Common DNS Exceptions.
|
||||
|
||||
Dnspython modules may also define their own exceptions, which will
|
||||
always be subclasses of ``DNSException``.
|
||||
"""
|
||||
|
||||
class DNSException(Exception):
|
||||
"""Abstract base class shared by all dnspython exceptions.
|
||||
|
||||
It supports two basic modes of operation:
|
||||
|
||||
a) Old/compatible mode is used if ``__init__`` was called with
|
||||
empty *kwargs*. In compatible mode all *args* are passed
|
||||
to the standard Python Exception class as before and all *args* are
|
||||
printed by the standard ``__str__`` implementation. Class variable
|
||||
``msg`` (or doc string if ``msg`` is ``None``) is returned from ``str()``
|
||||
if *args* is empty.
|
||||
|
||||
b) New/parametrized mode is used if ``__init__`` was called with
|
||||
non-empty *kwargs*.
|
||||
In the new mode *args* must be empty and all kwargs must match
|
||||
those set in class variable ``supp_kwargs``. All kwargs are stored inside
|
||||
``self.kwargs`` and used in a new ``__str__`` implementation to construct
|
||||
a formatted message based on the ``fmt`` class variable, a ``string``.
|
||||
|
||||
In the simplest case it is enough to override the ``supp_kwargs``
|
||||
and ``fmt`` class variables to get nice parametrized messages.
|
||||
"""
|
||||
|
||||
msg = None # non-parametrized message
|
||||
supp_kwargs = set() # accepted parameters for _fmt_kwargs (sanity check)
|
||||
fmt = None # message parametrized with results from _fmt_kwargs
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._check_params(*args, **kwargs)
|
||||
if kwargs:
|
||||
self.kwargs = self._check_kwargs(**kwargs)
|
||||
self.msg = str(self)
|
||||
else:
|
||||
self.kwargs = dict() # defined but empty for old mode exceptions
|
||||
if self.msg is None:
|
||||
# doc string is better implicit message than empty string
|
||||
self.msg = self.__doc__
|
||||
if args:
|
||||
super().__init__(*args)
|
||||
else:
|
||||
super().__init__(self.msg)
|
||||
|
||||
def _check_params(self, *args, **kwargs):
|
||||
"""Old exceptions supported only args and not kwargs.
|
||||
|
||||
For sanity we do not allow to mix old and new behavior."""
|
||||
if args or kwargs:
|
||||
assert bool(args) != bool(kwargs), \
|
||||
'keyword arguments are mutually exclusive with positional args'
|
||||
|
||||
def _check_kwargs(self, **kwargs):
|
||||
if kwargs:
|
||||
assert set(kwargs.keys()) == self.supp_kwargs, \
|
||||
'following set of keyword args is required: %s' % (
|
||||
self.supp_kwargs)
|
||||
return kwargs
|
||||
|
||||
def _fmt_kwargs(self, **kwargs):
|
||||
"""Format kwargs before printing them.
|
||||
|
||||
Resulting dictionary has to have keys necessary for str.format call
|
||||
on fmt class variable.
|
||||
"""
|
||||
fmtargs = {}
|
||||
for kw, data in kwargs.items():
|
||||
if isinstance(data, (list, set)):
|
||||
# convert list of <someobj> to list of str(<someobj>)
|
||||
fmtargs[kw] = list(map(str, data))
|
||||
if len(fmtargs[kw]) == 1:
|
||||
# remove list brackets [] from single-item lists
|
||||
fmtargs[kw] = fmtargs[kw].pop()
|
||||
else:
|
||||
fmtargs[kw] = data
|
||||
return fmtargs
|
||||
|
||||
def __str__(self):
|
||||
if self.kwargs and self.fmt:
|
||||
# provide custom message constructed from keyword arguments
|
||||
fmtargs = self._fmt_kwargs(**self.kwargs)
|
||||
return self.fmt.format(**fmtargs)
|
||||
else:
|
||||
# print *args directly in the same way as old DNSException
|
||||
return super().__str__()
|
||||
|
||||
|
||||
class FormError(DNSException):
|
||||
"""DNS message is malformed."""
|
||||
|
||||
|
||||
class SyntaxError(DNSException):
|
||||
"""Text input is malformed."""
|
||||
|
||||
|
||||
class UnexpectedEnd(SyntaxError):
|
||||
"""Text input ended unexpectedly."""
|
||||
|
||||
|
||||
class TooBig(DNSException):
|
||||
"""The DNS message is too big."""
|
||||
|
||||
|
||||
class Timeout(DNSException):
|
||||
"""The DNS operation timed out."""
|
||||
supp_kwargs = {'timeout'}
|
||||
fmt = "The DNS operation timed out after {timeout} seconds"
|
||||
|
||||
|
||||
class ExceptionWrapper:
|
||||
def __init__(self, exception_class):
|
||||
self.exception_class = exception_class
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type is not None and not isinstance(exc_val,
|
||||
self.exception_class):
|
||||
raise self.exception_class(str(exc_val)) from exc_val
|
||||
return False
|
119
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/flags.py
vendored
Normal file
119
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/flags.py
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Message Flags."""
|
||||
|
||||
import enum
|
||||
|
||||
# Standard DNS flags
|
||||
|
||||
class Flag(enum.IntFlag):
|
||||
#: Query Response
|
||||
QR = 0x8000
|
||||
#: Authoritative Answer
|
||||
AA = 0x0400
|
||||
#: Truncated Response
|
||||
TC = 0x0200
|
||||
#: Recursion Desired
|
||||
RD = 0x0100
|
||||
#: Recursion Available
|
||||
RA = 0x0080
|
||||
#: Authentic Data
|
||||
AD = 0x0020
|
||||
#: Checking Disabled
|
||||
CD = 0x0010
|
||||
|
||||
|
||||
# EDNS flags
|
||||
|
||||
class EDNSFlag(enum.IntFlag):
|
||||
#: DNSSEC answer OK
|
||||
DO = 0x8000
|
||||
|
||||
|
||||
def _from_text(text, enum_class):
|
||||
flags = 0
|
||||
tokens = text.split()
|
||||
for t in tokens:
|
||||
flags |= enum_class[t.upper()]
|
||||
return flags
|
||||
|
||||
|
||||
def _to_text(flags, enum_class):
|
||||
text_flags = []
|
||||
for k, v in enum_class.__members__.items():
|
||||
if flags & v != 0:
|
||||
text_flags.append(k)
|
||||
return ' '.join(text_flags)
|
||||
|
||||
|
||||
def from_text(text):
|
||||
"""Convert a space-separated list of flag text values into a flags
|
||||
value.
|
||||
|
||||
Returns an ``int``
|
||||
"""
|
||||
|
||||
return _from_text(text, Flag)
|
||||
|
||||
|
||||
def to_text(flags):
|
||||
"""Convert a flags value into a space-separated list of flag text
|
||||
values.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
return _to_text(flags, Flag)
|
||||
|
||||
|
||||
def edns_from_text(text):
|
||||
"""Convert a space-separated list of EDNS flag text values into a EDNS
|
||||
flags value.
|
||||
|
||||
Returns an ``int``
|
||||
"""
|
||||
|
||||
return _from_text(text, EDNSFlag)
|
||||
|
||||
|
||||
def edns_to_text(flags):
|
||||
"""Convert an EDNS flags value into a space-separated list of EDNS flag
|
||||
text values.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
return _to_text(flags, EDNSFlag)
|
||||
|
||||
### BEGIN generated Flag constants
|
||||
|
||||
QR = Flag.QR
|
||||
AA = Flag.AA
|
||||
TC = Flag.TC
|
||||
RD = Flag.RD
|
||||
RA = Flag.RA
|
||||
AD = Flag.AD
|
||||
CD = Flag.CD
|
||||
|
||||
### END generated Flag constants
|
||||
|
||||
### BEGIN generated EDNSFlag constants
|
||||
|
||||
DO = EDNSFlag.DO
|
||||
|
||||
### END generated EDNSFlag constants
|
69
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/grange.py
vendored
Normal file
69
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/grange.py
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2012-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS GENERATE range conversion."""
|
||||
|
||||
import dns
|
||||
|
||||
def from_text(text):
|
||||
"""Convert the text form of a range in a ``$GENERATE`` statement to an
|
||||
integer.
|
||||
|
||||
*text*, a ``str``, the textual range in ``$GENERATE`` form.
|
||||
|
||||
Returns a tuple of three ``int`` values ``(start, stop, step)``.
|
||||
"""
|
||||
|
||||
start = -1
|
||||
stop = -1
|
||||
step = 1
|
||||
cur = ''
|
||||
state = 0
|
||||
# state 0 1 2
|
||||
# x - y / z
|
||||
|
||||
if text and text[0] == '-':
|
||||
raise dns.exception.SyntaxError("Start cannot be a negative number")
|
||||
|
||||
for c in text:
|
||||
if c == '-' and state == 0:
|
||||
start = int(cur)
|
||||
cur = ''
|
||||
state = 1
|
||||
elif c == '/':
|
||||
stop = int(cur)
|
||||
cur = ''
|
||||
state = 2
|
||||
elif c.isdigit():
|
||||
cur += c
|
||||
else:
|
||||
raise dns.exception.SyntaxError("Could not parse %s" % (c))
|
||||
|
||||
if state == 0:
|
||||
raise dns.exception.SyntaxError("no stop value specified")
|
||||
elif state == 1:
|
||||
stop = int(cur)
|
||||
else:
|
||||
assert state == 2
|
||||
step = int(cur)
|
||||
|
||||
assert step >= 1
|
||||
assert start >= 0
|
||||
if start > stop:
|
||||
raise dns.exception.SyntaxError('start must be <= stop')
|
||||
|
||||
return (start, stop, step)
|
70
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/immutable.py
vendored
Normal file
70
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/immutable.py
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
import collections.abc
|
||||
import sys
|
||||
|
||||
# pylint: disable=unused-import
|
||||
if sys.version_info >= (3, 7):
|
||||
odict = dict
|
||||
from dns._immutable_ctx import immutable
|
||||
else:
|
||||
# pragma: no cover
|
||||
from collections import OrderedDict as odict
|
||||
from dns._immutable_attr import immutable # noqa
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
@immutable
|
||||
class Dict(collections.abc.Mapping):
|
||||
def __init__(self, dictionary, no_copy=False):
|
||||
"""Make an immutable dictionary from the specified dictionary.
|
||||
|
||||
If *no_copy* is `True`, then *dictionary* will be wrapped instead
|
||||
of copied. Only set this if you are sure there will be no external
|
||||
references to the dictionary.
|
||||
"""
|
||||
if no_copy and isinstance(dictionary, odict):
|
||||
self._odict = dictionary
|
||||
else:
|
||||
self._odict = odict(dictionary)
|
||||
self._hash = None
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._odict.__getitem__(key)
|
||||
|
||||
def __hash__(self): # pylint: disable=invalid-hash-returned
|
||||
if self._hash is None:
|
||||
h = 0
|
||||
for key in sorted(self._odict.keys()):
|
||||
h ^= hash(key)
|
||||
object.__setattr__(self, '_hash', h)
|
||||
# this does return an int, but pylint doesn't figure that out
|
||||
return self._hash
|
||||
|
||||
def __len__(self):
|
||||
return len(self._odict)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._odict)
|
||||
|
||||
|
||||
def constify(o):
|
||||
"""
|
||||
Convert mutable types to immutable types.
|
||||
"""
|
||||
if isinstance(o, bytearray):
|
||||
return bytes(o)
|
||||
if isinstance(o, tuple):
|
||||
try:
|
||||
hash(o)
|
||||
return o
|
||||
except Exception:
|
||||
return tuple(constify(elt) for elt in o)
|
||||
if isinstance(o, list):
|
||||
return tuple(constify(elt) for elt in o)
|
||||
if isinstance(o, dict):
|
||||
cdict = odict()
|
||||
for k, v in o.items():
|
||||
cdict[k] = constify(v)
|
||||
return Dict(cdict, True)
|
||||
return o
|
170
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/inet.py
vendored
Normal file
170
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/inet.py
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Generic Internet address helper functions."""
|
||||
|
||||
import socket
|
||||
|
||||
import dns.ipv4
|
||||
import dns.ipv6
|
||||
|
||||
|
||||
# We assume that AF_INET and AF_INET6 are always defined. We keep
|
||||
# these here for the benefit of any old code (unlikely though that
|
||||
# is!).
|
||||
AF_INET = socket.AF_INET
|
||||
AF_INET6 = socket.AF_INET6
|
||||
|
||||
|
||||
def inet_pton(family, text):
|
||||
"""Convert the textual form of a network address into its binary form.
|
||||
|
||||
*family* is an ``int``, the address family.
|
||||
|
||||
*text* is a ``str``, the textual address.
|
||||
|
||||
Raises ``NotImplementedError`` if the address family specified is not
|
||||
implemented.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
if family == AF_INET:
|
||||
return dns.ipv4.inet_aton(text)
|
||||
elif family == AF_INET6:
|
||||
return dns.ipv6.inet_aton(text, True)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def inet_ntop(family, address):
|
||||
"""Convert the binary form of a network address into its textual form.
|
||||
|
||||
*family* is an ``int``, the address family.
|
||||
|
||||
*address* is a ``bytes``, the network address in binary form.
|
||||
|
||||
Raises ``NotImplementedError`` if the address family specified is not
|
||||
implemented.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if family == AF_INET:
|
||||
return dns.ipv4.inet_ntoa(address)
|
||||
elif family == AF_INET6:
|
||||
return dns.ipv6.inet_ntoa(address)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def af_for_address(text):
|
||||
"""Determine the address family of a textual-form network address.
|
||||
|
||||
*text*, a ``str``, the textual address.
|
||||
|
||||
Raises ``ValueError`` if the address family cannot be determined
|
||||
from the input.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
try:
|
||||
dns.ipv4.inet_aton(text)
|
||||
return AF_INET
|
||||
except Exception:
|
||||
try:
|
||||
dns.ipv6.inet_aton(text, True)
|
||||
return AF_INET6
|
||||
except Exception:
|
||||
raise ValueError
|
||||
|
||||
|
||||
def is_multicast(text):
|
||||
"""Is the textual-form network address a multicast address?
|
||||
|
||||
*text*, a ``str``, the textual address.
|
||||
|
||||
Raises ``ValueError`` if the address family cannot be determined
|
||||
from the input.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
try:
|
||||
first = dns.ipv4.inet_aton(text)[0]
|
||||
return first >= 224 and first <= 239
|
||||
except Exception:
|
||||
try:
|
||||
first = dns.ipv6.inet_aton(text, True)[0]
|
||||
return first == 255
|
||||
except Exception:
|
||||
raise ValueError
|
||||
|
||||
|
||||
def is_address(text):
|
||||
"""Is the specified string an IPv4 or IPv6 address?
|
||||
|
||||
*text*, a ``str``, the textual address.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
try:
|
||||
dns.ipv4.inet_aton(text)
|
||||
return True
|
||||
except Exception:
|
||||
try:
|
||||
dns.ipv6.inet_aton(text, True)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def low_level_address_tuple(high_tuple, af=None):
|
||||
"""Given a "high-level" address tuple, i.e.
|
||||
an (address, port) return the appropriate "low-level" address tuple
|
||||
suitable for use in socket calls.
|
||||
|
||||
If an *af* other than ``None`` is provided, it is assumed the
|
||||
address in the high-level tuple is valid and has that af. If af
|
||||
is ``None``, then af_for_address will be called.
|
||||
|
||||
"""
|
||||
address, port = high_tuple
|
||||
if af is None:
|
||||
af = af_for_address(address)
|
||||
if af == AF_INET:
|
||||
return (address, port)
|
||||
elif af == AF_INET6:
|
||||
i = address.find('%')
|
||||
if i < 0:
|
||||
# no scope, shortcut!
|
||||
return (address, port, 0, 0)
|
||||
# try to avoid getaddrinfo()
|
||||
addrpart = address[:i]
|
||||
scope = address[i + 1:]
|
||||
if scope.isdigit():
|
||||
return (addrpart, port, 0, int(scope))
|
||||
try:
|
||||
return (addrpart, port, 0, socket.if_nametoindex(scope))
|
||||
except AttributeError: # pragma: no cover (we can't really test this)
|
||||
ai_flags = socket.AI_NUMERICHOST
|
||||
((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags)
|
||||
return tup
|
||||
else:
|
||||
raise NotImplementedError(f'unknown address family {af}')
|
60
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/ipv4.py
vendored
Normal file
60
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/ipv4.py
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""IPv4 helper functions."""
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
|
||||
def inet_ntoa(address):
|
||||
"""Convert an IPv4 address in binary form to text form.
|
||||
|
||||
*address*, a ``bytes``, the IPv4 address in binary form.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if len(address) != 4:
|
||||
raise dns.exception.SyntaxError
|
||||
return ('%u.%u.%u.%u' % (address[0], address[1],
|
||||
address[2], address[3]))
|
||||
|
||||
def inet_aton(text):
|
||||
"""Convert an IPv4 address in text form to binary form.
|
||||
|
||||
*text*, a ``str``, the IPv4 address in textual form.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
if not isinstance(text, bytes):
|
||||
text = text.encode()
|
||||
parts = text.split(b'.')
|
||||
if len(parts) != 4:
|
||||
raise dns.exception.SyntaxError
|
||||
for part in parts:
|
||||
if not part.isdigit():
|
||||
raise dns.exception.SyntaxError
|
||||
if len(part) > 1 and part[0] == ord('0'):
|
||||
# No leading zeros
|
||||
raise dns.exception.SyntaxError
|
||||
try:
|
||||
b = [int(part) for part in parts]
|
||||
return struct.pack('BBBB', *b)
|
||||
except Exception:
|
||||
raise dns.exception.SyntaxError
|
197
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/ipv6.py
vendored
Normal file
197
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/ipv6.py
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""IPv6 helper functions."""
|
||||
|
||||
import re
|
||||
import binascii
|
||||
|
||||
import dns.exception
|
||||
import dns.ipv4
|
||||
|
||||
_leading_zero = re.compile(r'0+([0-9a-f]+)')
|
||||
|
||||
def inet_ntoa(address):
|
||||
"""Convert an IPv6 address in binary form to text form.
|
||||
|
||||
*address*, a ``bytes``, the IPv6 address in binary form.
|
||||
|
||||
Raises ``ValueError`` if the address isn't 16 bytes long.
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if len(address) != 16:
|
||||
raise ValueError("IPv6 addresses are 16 bytes long")
|
||||
hex = binascii.hexlify(address)
|
||||
chunks = []
|
||||
i = 0
|
||||
l = len(hex)
|
||||
while i < l:
|
||||
chunk = hex[i:i + 4].decode()
|
||||
# strip leading zeros. we do this with an re instead of
|
||||
# with lstrip() because lstrip() didn't support chars until
|
||||
# python 2.2.2
|
||||
m = _leading_zero.match(chunk)
|
||||
if m is not None:
|
||||
chunk = m.group(1)
|
||||
chunks.append(chunk)
|
||||
i += 4
|
||||
#
|
||||
# Compress the longest subsequence of 0-value chunks to ::
|
||||
#
|
||||
best_start = 0
|
||||
best_len = 0
|
||||
start = -1
|
||||
last_was_zero = False
|
||||
for i in range(8):
|
||||
if chunks[i] != '0':
|
||||
if last_was_zero:
|
||||
end = i
|
||||
current_len = end - start
|
||||
if current_len > best_len:
|
||||
best_start = start
|
||||
best_len = current_len
|
||||
last_was_zero = False
|
||||
elif not last_was_zero:
|
||||
start = i
|
||||
last_was_zero = True
|
||||
if last_was_zero:
|
||||
end = 8
|
||||
current_len = end - start
|
||||
if current_len > best_len:
|
||||
best_start = start
|
||||
best_len = current_len
|
||||
if best_len > 1:
|
||||
if best_start == 0 and \
|
||||
(best_len == 6 or
|
||||
best_len == 5 and chunks[5] == 'ffff'):
|
||||
# We have an embedded IPv4 address
|
||||
if best_len == 6:
|
||||
prefix = '::'
|
||||
else:
|
||||
prefix = '::ffff:'
|
||||
hex = prefix + dns.ipv4.inet_ntoa(address[12:])
|
||||
else:
|
||||
hex = ':'.join(chunks[:best_start]) + '::' + \
|
||||
':'.join(chunks[best_start + best_len:])
|
||||
else:
|
||||
hex = ':'.join(chunks)
|
||||
return hex
|
||||
|
||||
_v4_ending = re.compile(br'(.*):(\d+\.\d+\.\d+\.\d+)$')
|
||||
_colon_colon_start = re.compile(br'::.*')
|
||||
_colon_colon_end = re.compile(br'.*::$')
|
||||
|
||||
def inet_aton(text, ignore_scope=False):
|
||||
"""Convert an IPv6 address in text form to binary form.
|
||||
|
||||
*text*, a ``str``, the IPv6 address in textual form.
|
||||
|
||||
*ignore_scope*, a ``bool``. If ``True``, a scope will be ignored.
|
||||
If ``False``, the default, it is an error for a scope to be present.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
#
|
||||
# Our aim here is not something fast; we just want something that works.
|
||||
#
|
||||
if not isinstance(text, bytes):
|
||||
text = text.encode()
|
||||
|
||||
if ignore_scope:
|
||||
parts = text.split(b'%')
|
||||
l = len(parts)
|
||||
if l == 2:
|
||||
text = parts[0]
|
||||
elif l > 2:
|
||||
raise dns.exception.SyntaxError
|
||||
|
||||
if text == b'':
|
||||
raise dns.exception.SyntaxError
|
||||
elif text.endswith(b':') and not text.endswith(b'::'):
|
||||
raise dns.exception.SyntaxError
|
||||
elif text.startswith(b':') and not text.startswith(b'::'):
|
||||
raise dns.exception.SyntaxError
|
||||
elif text == b'::':
|
||||
text = b'0::'
|
||||
#
|
||||
# Get rid of the icky dot-quad syntax if we have it.
|
||||
#
|
||||
m = _v4_ending.match(text)
|
||||
if m is not None:
|
||||
b = dns.ipv4.inet_aton(m.group(2))
|
||||
text = (u"{}:{:02x}{:02x}:{:02x}{:02x}".format(m.group(1).decode(),
|
||||
b[0], b[1], b[2],
|
||||
b[3])).encode()
|
||||
#
|
||||
# Try to turn '::<whatever>' into ':<whatever>'; if no match try to
|
||||
# turn '<whatever>::' into '<whatever>:'
|
||||
#
|
||||
m = _colon_colon_start.match(text)
|
||||
if m is not None:
|
||||
text = text[1:]
|
||||
else:
|
||||
m = _colon_colon_end.match(text)
|
||||
if m is not None:
|
||||
text = text[:-1]
|
||||
#
|
||||
# Now canonicalize into 8 chunks of 4 hex digits each
|
||||
#
|
||||
chunks = text.split(b':')
|
||||
l = len(chunks)
|
||||
if l > 8:
|
||||
raise dns.exception.SyntaxError
|
||||
seen_empty = False
|
||||
canonical = []
|
||||
for c in chunks:
|
||||
if c == b'':
|
||||
if seen_empty:
|
||||
raise dns.exception.SyntaxError
|
||||
seen_empty = True
|
||||
for _ in range(0, 8 - l + 1):
|
||||
canonical.append(b'0000')
|
||||
else:
|
||||
lc = len(c)
|
||||
if lc > 4:
|
||||
raise dns.exception.SyntaxError
|
||||
if lc != 4:
|
||||
c = (b'0' * (4 - lc)) + c
|
||||
canonical.append(c)
|
||||
if l < 8 and not seen_empty:
|
||||
raise dns.exception.SyntaxError
|
||||
text = b''.join(canonical)
|
||||
|
||||
#
|
||||
# Finally we can go to binary.
|
||||
#
|
||||
try:
|
||||
return binascii.unhexlify(text)
|
||||
except (binascii.Error, TypeError):
|
||||
raise dns.exception.SyntaxError
|
||||
|
||||
_mapped_prefix = b'\x00' * 10 + b'\xff\xff'
|
||||
|
||||
def is_mapped(address):
|
||||
"""Is the specified address a mapped IPv4 address?
|
||||
|
||||
*address*, a ``bytes`` is an IPv6 address in binary form.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
return address.startswith(_mapped_prefix)
|
1507
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/message.py
vendored
Normal file
1507
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/message.py
vendored
Normal file
|
@ -0,0 +1,1507 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Messages"""
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import time
|
||||
|
||||
import dns.wire
|
||||
import dns.edns
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
import dns.flags
|
||||
import dns.name
|
||||
import dns.opcode
|
||||
import dns.entropy
|
||||
import dns.rcode
|
||||
import dns.rdata
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
import dns.renderer
|
||||
import dns.ttl
|
||||
import dns.tsig
|
||||
import dns.rdtypes.ANY.OPT
|
||||
import dns.rdtypes.ANY.TSIG
|
||||
|
||||
|
||||
class ShortHeader(dns.exception.FormError):
|
||||
"""The DNS packet passed to from_wire() is too short."""
|
||||
|
||||
|
||||
class TrailingJunk(dns.exception.FormError):
|
||||
"""The DNS packet passed to from_wire() has extra junk at the end of it."""
|
||||
|
||||
|
||||
class UnknownHeaderField(dns.exception.DNSException):
|
||||
"""The header field name was not recognized when converting from text
|
||||
into a message."""
|
||||
|
||||
|
||||
class BadEDNS(dns.exception.FormError):
|
||||
"""An OPT record occurred somewhere other than
|
||||
the additional data section."""
|
||||
|
||||
|
||||
class BadTSIG(dns.exception.FormError):
|
||||
"""A TSIG record occurred somewhere other than the end of
|
||||
the additional data section."""
|
||||
|
||||
|
||||
class UnknownTSIGKey(dns.exception.DNSException):
|
||||
"""A TSIG with an unknown key was received."""
|
||||
|
||||
|
||||
class Truncated(dns.exception.DNSException):
|
||||
"""The truncated flag is set."""
|
||||
|
||||
supp_kwargs = {'message'}
|
||||
|
||||
def message(self):
|
||||
"""As much of the message as could be processed.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
return self.kwargs['message']
|
||||
|
||||
|
||||
class NotQueryResponse(dns.exception.DNSException):
|
||||
"""Message is not a response to a query."""
|
||||
|
||||
|
||||
class ChainTooLong(dns.exception.DNSException):
|
||||
"""The CNAME chain is too long."""
|
||||
|
||||
|
||||
class AnswerForNXDOMAIN(dns.exception.DNSException):
|
||||
"""The rcode is NXDOMAIN but an answer was found."""
|
||||
|
||||
class NoPreviousName(dns.exception.SyntaxError):
|
||||
"""No previous name was known."""
|
||||
|
||||
|
||||
class MessageSection(dns.enum.IntEnum):
|
||||
"""Message sections"""
|
||||
QUESTION = 0
|
||||
ANSWER = 1
|
||||
AUTHORITY = 2
|
||||
ADDITIONAL = 3
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 3
|
||||
|
||||
|
||||
DEFAULT_EDNS_PAYLOAD = 1232
|
||||
MAX_CHAIN = 16
|
||||
|
||||
class Message:
|
||||
"""A DNS message."""
|
||||
|
||||
_section_enum = MessageSection
|
||||
|
||||
def __init__(self, id=None):
|
||||
if id is None:
|
||||
self.id = dns.entropy.random_16()
|
||||
else:
|
||||
self.id = id
|
||||
self.flags = 0
|
||||
self.sections = [[], [], [], []]
|
||||
self.opt = None
|
||||
self.request_payload = 0
|
||||
self.keyring = None
|
||||
self.tsig = None
|
||||
self.request_mac = b''
|
||||
self.xfr = False
|
||||
self.origin = None
|
||||
self.tsig_ctx = None
|
||||
self.index = {}
|
||||
|
||||
@property
|
||||
def question(self):
|
||||
""" The question section."""
|
||||
return self.sections[0]
|
||||
|
||||
@question.setter
|
||||
def question(self, v):
|
||||
self.sections[0] = v
|
||||
|
||||
@property
|
||||
def answer(self):
|
||||
""" The answer section."""
|
||||
return self.sections[1]
|
||||
|
||||
@answer.setter
|
||||
def answer(self, v):
|
||||
self.sections[1] = v
|
||||
|
||||
@property
|
||||
def authority(self):
|
||||
""" The authority section."""
|
||||
return self.sections[2]
|
||||
|
||||
@authority.setter
|
||||
def authority(self, v):
|
||||
self.sections[2] = v
|
||||
|
||||
@property
|
||||
def additional(self):
|
||||
""" The additional data section."""
|
||||
return self.sections[3]
|
||||
|
||||
@additional.setter
|
||||
def additional(self, v):
|
||||
self.sections[3] = v
|
||||
|
||||
def __repr__(self):
|
||||
return '<DNS message, ID ' + repr(self.id) + '>'
|
||||
|
||||
def __str__(self):
|
||||
return self.to_text()
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
"""Convert the message to text.
|
||||
|
||||
The *origin*, *relativize*, and any other keyword
|
||||
arguments are passed to the RRset ``to_wire()`` method.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
s = io.StringIO()
|
||||
s.write('id %d\n' % self.id)
|
||||
s.write('opcode %s\n' % dns.opcode.to_text(self.opcode()))
|
||||
s.write('rcode %s\n' % dns.rcode.to_text(self.rcode()))
|
||||
s.write('flags %s\n' % dns.flags.to_text(self.flags))
|
||||
if self.edns >= 0:
|
||||
s.write('edns %s\n' % self.edns)
|
||||
if self.ednsflags != 0:
|
||||
s.write('eflags %s\n' %
|
||||
dns.flags.edns_to_text(self.ednsflags))
|
||||
s.write('payload %d\n' % self.payload)
|
||||
for opt in self.options:
|
||||
s.write('option %s\n' % opt.to_text())
|
||||
for (name, which) in self._section_enum.__members__.items():
|
||||
s.write(f';{name}\n')
|
||||
for rrset in self.section_from_number(which):
|
||||
s.write(rrset.to_text(origin, relativize, **kw))
|
||||
s.write('\n')
|
||||
#
|
||||
# We strip off the final \n so the caller can print the result without
|
||||
# doing weird things to get around eccentricities in Python print
|
||||
# formatting
|
||||
#
|
||||
return s.getvalue()[:-1]
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Two messages are equal if they have the same content in the
|
||||
header, question, answer, and authority sections.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
if not isinstance(other, Message):
|
||||
return False
|
||||
if self.id != other.id:
|
||||
return False
|
||||
if self.flags != other.flags:
|
||||
return False
|
||||
for i, section in enumerate(self.sections):
|
||||
other_section = other.sections[i]
|
||||
for n in section:
|
||||
if n not in other_section:
|
||||
return False
|
||||
for n in other_section:
|
||||
if n not in section:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def is_response(self, other):
|
||||
"""Is *other* a response this message?
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
if other.flags & dns.flags.QR == 0 or \
|
||||
self.id != other.id or \
|
||||
dns.opcode.from_flags(self.flags) != \
|
||||
dns.opcode.from_flags(other.flags):
|
||||
return False
|
||||
if other.rcode() in {dns.rcode.FORMERR, dns.rcode.SERVFAIL,
|
||||
dns.rcode.NOTIMP, dns.rcode.REFUSED}:
|
||||
# We don't check the question section in these cases if
|
||||
# the other question section is empty, even though they
|
||||
# still really ought to have a question section.
|
||||
if len(other.question) == 0:
|
||||
return True
|
||||
if dns.opcode.is_update(self.flags):
|
||||
# This is assuming the "sender doesn't include anything
|
||||
# from the update", but we don't care to check the other
|
||||
# case, which is that all the sections are returned and
|
||||
# identical.
|
||||
return True
|
||||
for n in self.question:
|
||||
if n not in other.question:
|
||||
return False
|
||||
for n in other.question:
|
||||
if n not in self.question:
|
||||
return False
|
||||
return True
|
||||
|
||||
def section_number(self, section):
|
||||
"""Return the "section number" of the specified section for use
|
||||
in indexing.
|
||||
|
||||
*section* is one of the section attributes of this message.
|
||||
|
||||
Raises ``ValueError`` if the section isn't known.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
for i, our_section in enumerate(self.sections):
|
||||
if section is our_section:
|
||||
return self._section_enum(i)
|
||||
raise ValueError('unknown section')
|
||||
|
||||
def section_from_number(self, number):
|
||||
"""Return the section list associated with the specified section
|
||||
number.
|
||||
|
||||
*number* is a section number `int` or the text form of a section
|
||||
name.
|
||||
|
||||
Raises ``ValueError`` if the section isn't known.
|
||||
|
||||
Returns a ``list``.
|
||||
"""
|
||||
|
||||
section = self._section_enum.make(number)
|
||||
return self.sections[section]
|
||||
|
||||
def find_rrset(self, section, name, rdclass, rdtype,
|
||||
covers=dns.rdatatype.NONE, deleting=None, create=False,
|
||||
force_unique=False):
|
||||
"""Find the RRset with the given attributes in the specified section.
|
||||
|
||||
*section*, an ``int`` section number, or one of the section
|
||||
attributes of this message. This specifies the
|
||||
the section of the message to search. For example::
|
||||
|
||||
my_message.find_rrset(my_message.answer, name, rdclass, rdtype)
|
||||
my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype)
|
||||
|
||||
*name*, a ``dns.name.Name``, the name of the RRset.
|
||||
|
||||
*rdclass*, an ``int``, the class of the RRset.
|
||||
|
||||
*rdtype*, an ``int``, the type of the RRset.
|
||||
|
||||
*covers*, an ``int`` or ``None``, the covers value of the RRset.
|
||||
The default is ``None``.
|
||||
|
||||
*deleting*, an ``int`` or ``None``, the deleting value of the RRset.
|
||||
The default is ``None``.
|
||||
|
||||
*create*, a ``bool``. If ``True``, create the RRset if it is not found.
|
||||
The created RRset is appended to *section*.
|
||||
|
||||
*force_unique*, a ``bool``. If ``True`` and *create* is also ``True``,
|
||||
create a new RRset regardless of whether a matching RRset exists
|
||||
already. The default is ``False``. This is useful when creating
|
||||
DDNS Update messages, as order matters for them.
|
||||
|
||||
Raises ``KeyError`` if the RRset was not found and create was
|
||||
``False``.
|
||||
|
||||
Returns a ``dns.rrset.RRset object``.
|
||||
"""
|
||||
|
||||
if isinstance(section, int):
|
||||
section_number = section
|
||||
section = self.section_from_number(section_number)
|
||||
else:
|
||||
section_number = self.section_number(section)
|
||||
key = (section_number, name, rdclass, rdtype, covers, deleting)
|
||||
if not force_unique:
|
||||
if self.index is not None:
|
||||
rrset = self.index.get(key)
|
||||
if rrset is not None:
|
||||
return rrset
|
||||
else:
|
||||
for rrset in section:
|
||||
if rrset.full_match(name, rdclass, rdtype, covers,
|
||||
deleting):
|
||||
return rrset
|
||||
if not create:
|
||||
raise KeyError
|
||||
rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting)
|
||||
section.append(rrset)
|
||||
if self.index is not None:
|
||||
self.index[key] = rrset
|
||||
return rrset
|
||||
|
||||
def get_rrset(self, section, name, rdclass, rdtype,
|
||||
covers=dns.rdatatype.NONE, deleting=None, create=False,
|
||||
force_unique=False):
|
||||
"""Get the RRset with the given attributes in the specified section.
|
||||
|
||||
If the RRset is not found, None is returned.
|
||||
|
||||
*section*, an ``int`` section number, or one of the section
|
||||
attributes of this message. This specifies the
|
||||
the section of the message to search. For example::
|
||||
|
||||
my_message.get_rrset(my_message.answer, name, rdclass, rdtype)
|
||||
my_message.get_rrset(dns.message.ANSWER, name, rdclass, rdtype)
|
||||
|
||||
*name*, a ``dns.name.Name``, the name of the RRset.
|
||||
|
||||
*rdclass*, an ``int``, the class of the RRset.
|
||||
|
||||
*rdtype*, an ``int``, the type of the RRset.
|
||||
|
||||
*covers*, an ``int`` or ``None``, the covers value of the RRset.
|
||||
The default is ``None``.
|
||||
|
||||
*deleting*, an ``int`` or ``None``, the deleting value of the RRset.
|
||||
The default is ``None``.
|
||||
|
||||
*create*, a ``bool``. If ``True``, create the RRset if it is not found.
|
||||
The created RRset is appended to *section*.
|
||||
|
||||
*force_unique*, a ``bool``. If ``True`` and *create* is also ``True``,
|
||||
create a new RRset regardless of whether a matching RRset exists
|
||||
already. The default is ``False``. This is useful when creating
|
||||
DDNS Update messages, as order matters for them.
|
||||
|
||||
Returns a ``dns.rrset.RRset object`` or ``None``.
|
||||
"""
|
||||
|
||||
try:
|
||||
rrset = self.find_rrset(section, name, rdclass, rdtype, covers,
|
||||
deleting, create, force_unique)
|
||||
except KeyError:
|
||||
rrset = None
|
||||
return rrset
|
||||
|
||||
def to_wire(self, origin=None, max_size=0, multi=False, tsig_ctx=None,
|
||||
**kw):
|
||||
"""Return a string containing the message in DNS compressed wire
|
||||
format.
|
||||
|
||||
Additional keyword arguments are passed to the RRset ``to_wire()``
|
||||
method.
|
||||
|
||||
*origin*, a ``dns.name.Name`` or ``None``, the origin to be appended
|
||||
to any relative names. If ``None``, and the message has an origin
|
||||
attribute that is not ``None``, then it will be used.
|
||||
|
||||
*max_size*, an ``int``, the maximum size of the wire format
|
||||
output; default is 0, which means "the message's request
|
||||
payload, if nonzero, or 65535".
|
||||
|
||||
*multi*, a ``bool``, should be set to ``True`` if this message is
|
||||
part of a multiple message sequence.
|
||||
|
||||
*tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the
|
||||
ongoing TSIG context, used when signing zone transfers.
|
||||
|
||||
Raises ``dns.exception.TooBig`` if *max_size* was exceeded.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
if origin is None and self.origin is not None:
|
||||
origin = self.origin
|
||||
if max_size == 0:
|
||||
if self.request_payload != 0:
|
||||
max_size = self.request_payload
|
||||
else:
|
||||
max_size = 65535
|
||||
if max_size < 512:
|
||||
max_size = 512
|
||||
elif max_size > 65535:
|
||||
max_size = 65535
|
||||
r = dns.renderer.Renderer(self.id, self.flags, max_size, origin)
|
||||
for rrset in self.question:
|
||||
r.add_question(rrset.name, rrset.rdtype, rrset.rdclass)
|
||||
for rrset in self.answer:
|
||||
r.add_rrset(dns.renderer.ANSWER, rrset, **kw)
|
||||
for rrset in self.authority:
|
||||
r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw)
|
||||
if self.opt is not None:
|
||||
r.add_rrset(dns.renderer.ADDITIONAL, self.opt)
|
||||
for rrset in self.additional:
|
||||
r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw)
|
||||
r.write_header()
|
||||
if self.tsig is not None:
|
||||
(new_tsig, ctx) = dns.tsig.sign(r.get_wire(),
|
||||
self.keyring,
|
||||
self.tsig[0],
|
||||
int(time.time()),
|
||||
self.request_mac,
|
||||
tsig_ctx,
|
||||
multi)
|
||||
self.tsig.clear()
|
||||
self.tsig.add(new_tsig)
|
||||
r.add_rrset(dns.renderer.ADDITIONAL, self.tsig)
|
||||
r.write_header()
|
||||
if multi:
|
||||
self.tsig_ctx = ctx
|
||||
return r.get_wire()
|
||||
|
||||
@staticmethod
|
||||
def _make_tsig(keyname, algorithm, time_signed, fudge, mac, original_id,
|
||||
error, other):
|
||||
tsig = dns.rdtypes.ANY.TSIG.TSIG(dns.rdataclass.ANY, dns.rdatatype.TSIG,
|
||||
algorithm, time_signed, fudge, mac,
|
||||
original_id, error, other)
|
||||
return dns.rrset.from_rdata(keyname, 0, tsig)
|
||||
|
||||
def use_tsig(self, keyring, keyname=None, fudge=300,
|
||||
original_id=None, tsig_error=0, other_data=b'',
|
||||
algorithm=dns.tsig.default_algorithm):
|
||||
"""When sending, a TSIG signature using the specified key
|
||||
should be added.
|
||||
|
||||
*key*, a ``dns.tsig.Key`` is the key to use. If a key is specified,
|
||||
the *keyring* and *algorithm* fields are not used.
|
||||
|
||||
*keyring*, a ``dict``, ``callable`` or ``dns.tsig.Key``, is either
|
||||
the TSIG keyring or key to use.
|
||||
|
||||
The format of a keyring dict is a mapping from TSIG key name, as
|
||||
``dns.name.Name`` to ``dns.tsig.Key`` or a TSIG secret, a ``bytes``.
|
||||
If a ``dict`` *keyring* is specified but a *keyname* is not, the key
|
||||
used will be the first key in the *keyring*. Note that the order of
|
||||
keys in a dictionary is not defined, so applications should supply a
|
||||
keyname when a ``dict`` keyring is used, unless they know the keyring
|
||||
contains only one key. If a ``callable`` keyring is specified, the
|
||||
callable will be called with the message and the keyname, and is
|
||||
expected to return a key.
|
||||
|
||||
*keyname*, a ``dns.name.Name``, ``str`` or ``None``, the name of
|
||||
thes TSIG key to use; defaults to ``None``. If *keyring* is a
|
||||
``dict``, the key must be defined in it. If *keyring* is a
|
||||
``dns.tsig.Key``, this is ignored.
|
||||
|
||||
*fudge*, an ``int``, the TSIG time fudge.
|
||||
|
||||
*original_id*, an ``int``, the TSIG original id. If ``None``,
|
||||
the message's id is used.
|
||||
|
||||
*tsig_error*, an ``int``, the TSIG error code.
|
||||
|
||||
*other_data*, a ``bytes``, the TSIG other data.
|
||||
|
||||
*algorithm*, a ``dns.name.Name``, the TSIG algorithm to use. This is
|
||||
only used if *keyring* is a ``dict``, and the key entry is a ``bytes``.
|
||||
"""
|
||||
|
||||
if isinstance(keyring, dns.tsig.Key):
|
||||
key = keyring
|
||||
keyname = key.name
|
||||
elif callable(keyring):
|
||||
key = keyring(self, keyname)
|
||||
else:
|
||||
if isinstance(keyname, str):
|
||||
keyname = dns.name.from_text(keyname)
|
||||
if keyname is None:
|
||||
keyname = next(iter(keyring))
|
||||
key = keyring[keyname]
|
||||
if isinstance(key, bytes):
|
||||
key = dns.tsig.Key(keyname, key, algorithm)
|
||||
self.keyring = key
|
||||
if original_id is None:
|
||||
original_id = self.id
|
||||
self.tsig = self._make_tsig(keyname, self.keyring.algorithm, 0, fudge,
|
||||
b'', original_id, tsig_error, other_data)
|
||||
|
||||
@property
|
||||
def keyname(self):
|
||||
if self.tsig:
|
||||
return self.tsig.name
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def keyalgorithm(self):
|
||||
if self.tsig:
|
||||
return self.tsig[0].algorithm
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
if self.tsig:
|
||||
return self.tsig[0].mac
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def tsig_error(self):
|
||||
if self.tsig:
|
||||
return self.tsig[0].error
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def had_tsig(self):
|
||||
return bool(self.tsig)
|
||||
|
||||
@staticmethod
|
||||
def _make_opt(flags=0, payload=DEFAULT_EDNS_PAYLOAD, options=None):
|
||||
opt = dns.rdtypes.ANY.OPT.OPT(payload, dns.rdatatype.OPT,
|
||||
options or ())
|
||||
return dns.rrset.from_rdata(dns.name.root, int(flags), opt)
|
||||
|
||||
def use_edns(self, edns=0, ednsflags=0, payload=DEFAULT_EDNS_PAYLOAD,
|
||||
request_payload=None, options=None):
|
||||
"""Configure EDNS behavior.
|
||||
|
||||
*edns*, an ``int``, is the EDNS level to use. Specifying
|
||||
``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case
|
||||
the other parameters are ignored. Specifying ``True`` is
|
||||
equivalent to specifying 0, i.e. "use EDNS0".
|
||||
|
||||
*ednsflags*, an ``int``, the EDNS flag values.
|
||||
|
||||
*payload*, an ``int``, is the EDNS sender's payload field, which is the
|
||||
maximum size of UDP datagram the sender can handle. I.e. how big
|
||||
a response to this message can be.
|
||||
|
||||
*request_payload*, an ``int``, is the EDNS payload size to use when
|
||||
sending this message. If not specified, defaults to the value of
|
||||
*payload*.
|
||||
|
||||
*options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS
|
||||
options.
|
||||
"""
|
||||
|
||||
if edns is None or edns is False:
|
||||
edns = -1
|
||||
elif edns is True:
|
||||
edns = 0
|
||||
if edns < 0:
|
||||
self.opt = None
|
||||
self.request_payload = 0
|
||||
else:
|
||||
# make sure the EDNS version in ednsflags agrees with edns
|
||||
ednsflags &= 0xFF00FFFF
|
||||
ednsflags |= (edns << 16)
|
||||
if options is None:
|
||||
options = []
|
||||
self.opt = self._make_opt(ednsflags, payload, options)
|
||||
if request_payload is None:
|
||||
request_payload = payload
|
||||
self.request_payload = request_payload
|
||||
|
||||
@property
|
||||
def edns(self):
|
||||
if self.opt:
|
||||
return (self.ednsflags & 0xff0000) >> 16
|
||||
else:
|
||||
return -1
|
||||
|
||||
@property
|
||||
def ednsflags(self):
|
||||
if self.opt:
|
||||
return self.opt.ttl
|
||||
else:
|
||||
return 0
|
||||
|
||||
@ednsflags.setter
|
||||
def ednsflags(self, v):
|
||||
if self.opt:
|
||||
self.opt.ttl = v
|
||||
elif v:
|
||||
self.opt = self._make_opt(v)
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
if self.opt:
|
||||
return self.opt[0].payload
|
||||
else:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
if self.opt:
|
||||
return self.opt[0].options
|
||||
else:
|
||||
return ()
|
||||
|
||||
def want_dnssec(self, wanted=True):
|
||||
"""Enable or disable 'DNSSEC desired' flag in requests.
|
||||
|
||||
*wanted*, a ``bool``. If ``True``, then DNSSEC data is
|
||||
desired in the response, EDNS is enabled if required, and then
|
||||
the DO bit is set. If ``False``, the DO bit is cleared if
|
||||
EDNS is enabled.
|
||||
"""
|
||||
|
||||
if wanted:
|
||||
self.ednsflags |= dns.flags.DO
|
||||
elif self.opt:
|
||||
self.ednsflags &= ~dns.flags.DO
|
||||
|
||||
def rcode(self):
|
||||
"""Return the rcode.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
return dns.rcode.from_flags(int(self.flags), int(self.ednsflags))
|
||||
|
||||
def set_rcode(self, rcode):
|
||||
"""Set the rcode.
|
||||
|
||||
*rcode*, an ``int``, is the rcode to set.
|
||||
"""
|
||||
(value, evalue) = dns.rcode.to_flags(rcode)
|
||||
self.flags &= 0xFFF0
|
||||
self.flags |= value
|
||||
self.ednsflags &= 0x00FFFFFF
|
||||
self.ednsflags |= evalue
|
||||
|
||||
def opcode(self):
|
||||
"""Return the opcode.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
return dns.opcode.from_flags(int(self.flags))
|
||||
|
||||
def set_opcode(self, opcode):
|
||||
"""Set the opcode.
|
||||
|
||||
*opcode*, an ``int``, is the opcode to set.
|
||||
"""
|
||||
self.flags &= 0x87FF
|
||||
self.flags |= dns.opcode.to_flags(opcode)
|
||||
|
||||
def _get_one_rr_per_rrset(self, value):
|
||||
# What the caller picked is fine.
|
||||
return value
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
def _parse_rr_header(self, section, name, rdclass, rdtype):
|
||||
return (rdclass, rdtype, None, False)
|
||||
|
||||
# pylint: enable=unused-argument
|
||||
|
||||
def _parse_special_rr_header(self, section, count, position,
|
||||
name, rdclass, rdtype):
|
||||
if rdtype == dns.rdatatype.OPT:
|
||||
if section != MessageSection.ADDITIONAL or self.opt or \
|
||||
name != dns.name.root:
|
||||
raise BadEDNS
|
||||
elif rdtype == dns.rdatatype.TSIG:
|
||||
if section != MessageSection.ADDITIONAL or \
|
||||
rdclass != dns.rdatatype.ANY or \
|
||||
position != count - 1:
|
||||
raise BadTSIG
|
||||
return (rdclass, rdtype, None, False)
|
||||
|
||||
|
||||
class ChainingResult:
|
||||
"""The result of a call to dns.message.QueryMessage.resolve_chaining().
|
||||
|
||||
The ``answer`` attribute is the answer RRSet, or ``None`` if it doesn't
|
||||
exist.
|
||||
|
||||
The ``canonical_name`` attribute is the canonical name after all
|
||||
chaining has been applied (this is the name as ``rrset.name`` in cases
|
||||
where rrset is not ``None``).
|
||||
|
||||
The ``minimum_ttl`` attribute is the minimum TTL, i.e. the TTL to
|
||||
use if caching the data. It is the smallest of all the CNAME TTLs
|
||||
and either the answer TTL if it exists or the SOA TTL and SOA
|
||||
minimum values for negative answers.
|
||||
|
||||
The ``cnames`` attribute is a list of all the CNAME RRSets followed to
|
||||
get to the canonical name.
|
||||
"""
|
||||
def __init__(self, canonical_name, answer, minimum_ttl, cnames):
|
||||
self.canonical_name = canonical_name
|
||||
self.answer = answer
|
||||
self.minimum_ttl = minimum_ttl
|
||||
self.cnames = cnames
|
||||
|
||||
|
||||
class QueryMessage(Message):
|
||||
def resolve_chaining(self):
|
||||
"""Follow the CNAME chain in the response to determine the answer
|
||||
RRset.
|
||||
|
||||
Raises ``dns.message.NotQueryResponse`` if the message is not
|
||||
a response.
|
||||
|
||||
Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long.
|
||||
|
||||
Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN
|
||||
but an answer was found.
|
||||
|
||||
Raises ``dns.exception.FormError`` if the question count is not 1.
|
||||
|
||||
Returns a ChainingResult object.
|
||||
"""
|
||||
if self.flags & dns.flags.QR == 0:
|
||||
raise NotQueryResponse
|
||||
if len(self.question) != 1:
|
||||
raise dns.exception.FormError
|
||||
question = self.question[0]
|
||||
qname = question.name
|
||||
min_ttl = dns.ttl.MAX_TTL
|
||||
answer = None
|
||||
count = 0
|
||||
cnames = []
|
||||
while count < MAX_CHAIN:
|
||||
try:
|
||||
answer = self.find_rrset(self.answer, qname, question.rdclass,
|
||||
question.rdtype)
|
||||
min_ttl = min(min_ttl, answer.ttl)
|
||||
break
|
||||
except KeyError:
|
||||
if question.rdtype != dns.rdatatype.CNAME:
|
||||
try:
|
||||
crrset = self.find_rrset(self.answer, qname,
|
||||
question.rdclass,
|
||||
dns.rdatatype.CNAME)
|
||||
cnames.append(crrset)
|
||||
min_ttl = min(min_ttl, crrset.ttl)
|
||||
for rd in crrset:
|
||||
qname = rd.target
|
||||
break
|
||||
count += 1
|
||||
continue
|
||||
except KeyError:
|
||||
# Exit the chaining loop
|
||||
break
|
||||
else:
|
||||
# Exit the chaining loop
|
||||
break
|
||||
if count >= MAX_CHAIN:
|
||||
raise ChainTooLong
|
||||
if self.rcode() == dns.rcode.NXDOMAIN and answer is not None:
|
||||
raise AnswerForNXDOMAIN
|
||||
if answer is None:
|
||||
# Further minimize the TTL with NCACHE.
|
||||
auname = qname
|
||||
while True:
|
||||
# Look for an SOA RR whose owner name is a superdomain
|
||||
# of qname.
|
||||
try:
|
||||
srrset = self.find_rrset(self.authority, auname,
|
||||
question.rdclass,
|
||||
dns.rdatatype.SOA)
|
||||
min_ttl = min(min_ttl, srrset.ttl, srrset[0].minimum)
|
||||
break
|
||||
except KeyError:
|
||||
try:
|
||||
auname = auname.parent()
|
||||
except dns.name.NoParent:
|
||||
break
|
||||
return ChainingResult(qname, answer, min_ttl, cnames)
|
||||
|
||||
def canonical_name(self):
|
||||
"""Return the canonical name of the first name in the question
|
||||
section.
|
||||
|
||||
Raises ``dns.message.NotQueryResponse`` if the message is not
|
||||
a response.
|
||||
|
||||
Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long.
|
||||
|
||||
Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN
|
||||
but an answer was found.
|
||||
|
||||
Raises ``dns.exception.FormError`` if the question count is not 1.
|
||||
"""
|
||||
return self.resolve_chaining().canonical_name
|
||||
|
||||
|
||||
def _maybe_import_update():
|
||||
# We avoid circular imports by doing this here. We do it in another
|
||||
# function as doing it in _message_factory_from_opcode() makes "dns"
|
||||
# a local symbol, and the first line fails :)
|
||||
|
||||
# pylint: disable=redefined-outer-name,import-outside-toplevel,unused-import
|
||||
import dns.update # noqa: F401
|
||||
|
||||
|
||||
def _message_factory_from_opcode(opcode):
|
||||
if opcode == dns.opcode.QUERY:
|
||||
return QueryMessage
|
||||
elif opcode == dns.opcode.UPDATE:
|
||||
_maybe_import_update()
|
||||
return dns.update.UpdateMessage
|
||||
else:
|
||||
return Message
|
||||
|
||||
|
||||
class _WireReader:
|
||||
|
||||
"""Wire format reader.
|
||||
|
||||
parser: the binary parser
|
||||
message: The message object being built
|
||||
initialize_message: Callback to set message parsing options
|
||||
question_only: Are we only reading the question?
|
||||
one_rr_per_rrset: Put each RR into its own RRset?
|
||||
keyring: TSIG keyring
|
||||
ignore_trailing: Ignore trailing junk at end of request?
|
||||
multi: Is this message part of a multi-message sequence?
|
||||
DNS dynamic updates.
|
||||
"""
|
||||
|
||||
def __init__(self, wire, initialize_message, question_only=False,
|
||||
one_rr_per_rrset=False, ignore_trailing=False,
|
||||
keyring=None, multi=False):
|
||||
self.parser = dns.wire.Parser(wire)
|
||||
self.message = None
|
||||
self.initialize_message = initialize_message
|
||||
self.question_only = question_only
|
||||
self.one_rr_per_rrset = one_rr_per_rrset
|
||||
self.ignore_trailing = ignore_trailing
|
||||
self.keyring = keyring
|
||||
self.multi = multi
|
||||
|
||||
def _get_question(self, section_number, qcount):
|
||||
"""Read the next *qcount* records from the wire data and add them to
|
||||
the question section.
|
||||
"""
|
||||
|
||||
section = self.message.sections[section_number]
|
||||
for _ in range(qcount):
|
||||
qname = self.parser.get_name(self.message.origin)
|
||||
(rdtype, rdclass) = self.parser.get_struct('!HH')
|
||||
(rdclass, rdtype, _, _) = \
|
||||
self.message._parse_rr_header(section_number, qname, rdclass,
|
||||
rdtype)
|
||||
self.message.find_rrset(section, qname, rdclass, rdtype,
|
||||
create=True, force_unique=True)
|
||||
|
||||
def _get_section(self, section_number, count):
|
||||
"""Read the next I{count} records from the wire data and add them to
|
||||
the specified section.
|
||||
|
||||
section: the section of the message to which to add records
|
||||
count: the number of records to read
|
||||
"""
|
||||
|
||||
section = self.message.sections[section_number]
|
||||
force_unique = self.one_rr_per_rrset
|
||||
for i in range(count):
|
||||
rr_start = self.parser.current
|
||||
absolute_name = self.parser.get_name()
|
||||
if self.message.origin is not None:
|
||||
name = absolute_name.relativize(self.message.origin)
|
||||
else:
|
||||
name = absolute_name
|
||||
(rdtype, rdclass, ttl, rdlen) = self.parser.get_struct('!HHIH')
|
||||
if rdtype in (dns.rdatatype.OPT, dns.rdatatype.TSIG):
|
||||
(rdclass, rdtype, deleting, empty) = \
|
||||
self.message._parse_special_rr_header(section_number,
|
||||
count, i, name,
|
||||
rdclass, rdtype)
|
||||
else:
|
||||
(rdclass, rdtype, deleting, empty) = \
|
||||
self.message._parse_rr_header(section_number,
|
||||
name, rdclass, rdtype)
|
||||
if empty:
|
||||
if rdlen > 0:
|
||||
raise dns.exception.FormError
|
||||
rd = None
|
||||
covers = dns.rdatatype.NONE
|
||||
else:
|
||||
with self.parser.restrict_to(rdlen):
|
||||
rd = dns.rdata.from_wire_parser(rdclass, rdtype,
|
||||
self.parser,
|
||||
self.message.origin)
|
||||
covers = rd.covers()
|
||||
if self.message.xfr and rdtype == dns.rdatatype.SOA:
|
||||
force_unique = True
|
||||
if rdtype == dns.rdatatype.OPT:
|
||||
self.message.opt = dns.rrset.from_rdata(name, ttl, rd)
|
||||
elif rdtype == dns.rdatatype.TSIG:
|
||||
if self.keyring is None:
|
||||
raise UnknownTSIGKey('got signed message without keyring')
|
||||
if isinstance(self.keyring, dict):
|
||||
key = self.keyring.get(absolute_name)
|
||||
if isinstance(key, bytes):
|
||||
key = dns.tsig.Key(absolute_name, key, rd.algorithm)
|
||||
elif callable(self.keyring):
|
||||
key = self.keyring(self.message, absolute_name)
|
||||
else:
|
||||
key = self.keyring
|
||||
if key is None:
|
||||
raise UnknownTSIGKey("key '%s' unknown" % name)
|
||||
self.message.keyring = key
|
||||
self.message.tsig_ctx = \
|
||||
dns.tsig.validate(self.parser.wire,
|
||||
key,
|
||||
absolute_name,
|
||||
rd,
|
||||
int(time.time()),
|
||||
self.message.request_mac,
|
||||
rr_start,
|
||||
self.message.tsig_ctx,
|
||||
self.multi)
|
||||
self.message.tsig = dns.rrset.from_rdata(absolute_name, 0, rd)
|
||||
else:
|
||||
rrset = self.message.find_rrset(section, name,
|
||||
rdclass, rdtype, covers,
|
||||
deleting, True,
|
||||
force_unique)
|
||||
if rd is not None:
|
||||
if ttl > 0x7fffffff:
|
||||
ttl = 0
|
||||
rrset.add(rd, ttl)
|
||||
|
||||
def read(self):
|
||||
"""Read a wire format DNS message and build a dns.message.Message
|
||||
object."""
|
||||
|
||||
if self.parser.remaining() < 12:
|
||||
raise ShortHeader
|
||||
(id, flags, qcount, ancount, aucount, adcount) = \
|
||||
self.parser.get_struct('!HHHHHH')
|
||||
factory = _message_factory_from_opcode(dns.opcode.from_flags(flags))
|
||||
self.message = factory(id=id)
|
||||
self.message.flags = dns.flags.Flag(flags)
|
||||
self.initialize_message(self.message)
|
||||
self.one_rr_per_rrset = \
|
||||
self.message._get_one_rr_per_rrset(self.one_rr_per_rrset)
|
||||
self._get_question(MessageSection.QUESTION, qcount)
|
||||
if self.question_only:
|
||||
return self.message
|
||||
self._get_section(MessageSection.ANSWER, ancount)
|
||||
self._get_section(MessageSection.AUTHORITY, aucount)
|
||||
self._get_section(MessageSection.ADDITIONAL, adcount)
|
||||
if not self.ignore_trailing and self.parser.remaining() != 0:
|
||||
raise TrailingJunk
|
||||
if self.multi and self.message.tsig_ctx and not self.message.had_tsig:
|
||||
self.message.tsig_ctx.update(self.parser.wire)
|
||||
return self.message
|
||||
|
||||
|
||||
def from_wire(wire, keyring=None, request_mac=b'', xfr=False, origin=None,
|
||||
tsig_ctx=None, multi=False,
|
||||
question_only=False, one_rr_per_rrset=False,
|
||||
ignore_trailing=False, raise_on_truncation=False):
|
||||
"""Convert a DNS wire format message into a message
|
||||
object.
|
||||
|
||||
*keyring*, a ``dns.tsig.Key`` or ``dict``, the key or keyring to use
|
||||
if the message is signed.
|
||||
|
||||
*request_mac*, a ``bytes``. If the message is a response to a
|
||||
TSIG-signed request, *request_mac* should be set to the MAC of
|
||||
that request.
|
||||
|
||||
*xfr*, a ``bool``, should be set to ``True`` if this message is part of
|
||||
a zone transfer.
|
||||
|
||||
*origin*, a ``dns.name.Name`` or ``None``. If the message is part
|
||||
of a zone transfer, *origin* should be the origin name of the
|
||||
zone. If not ``None``, names will be relativized to the origin.
|
||||
|
||||
*tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the
|
||||
ongoing TSIG context, used when validating zone transfers.
|
||||
|
||||
*multi*, a ``bool``, should be set to ``True`` if this message is
|
||||
part of a multiple message sequence.
|
||||
|
||||
*question_only*, a ``bool``. If ``True``, read only up to
|
||||
the end of the question section.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its
|
||||
own RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the message.
|
||||
|
||||
*raise_on_truncation*, a ``bool``. If ``True``, raise an exception if
|
||||
the TC bit is set.
|
||||
|
||||
Raises ``dns.message.ShortHeader`` if the message is less than 12 octets
|
||||
long.
|
||||
|
||||
Raises ``dns.message.TrailingJunk`` if there were octets in the message
|
||||
past the end of the proper DNS message, and *ignore_trailing* is ``False``.
|
||||
|
||||
Raises ``dns.message.BadEDNS`` if an OPT record was in the
|
||||
wrong section, or occurred more than once.
|
||||
|
||||
Raises ``dns.message.BadTSIG`` if a TSIG record was not the last
|
||||
record of the additional data section.
|
||||
|
||||
Raises ``dns.message.Truncated`` if the TC flag is set and
|
||||
*raise_on_truncation* is ``True``.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
|
||||
def initialize_message(message):
|
||||
message.request_mac = request_mac
|
||||
message.xfr = xfr
|
||||
message.origin = origin
|
||||
message.tsig_ctx = tsig_ctx
|
||||
|
||||
reader = _WireReader(wire, initialize_message, question_only,
|
||||
one_rr_per_rrset, ignore_trailing, keyring, multi)
|
||||
try:
|
||||
m = reader.read()
|
||||
except dns.exception.FormError:
|
||||
if reader.message and (reader.message.flags & dns.flags.TC) and \
|
||||
raise_on_truncation:
|
||||
raise Truncated(message=reader.message)
|
||||
else:
|
||||
raise
|
||||
# Reading a truncated message might not have any errors, so we
|
||||
# have to do this check here too.
|
||||
if m.flags & dns.flags.TC and raise_on_truncation:
|
||||
raise Truncated(message=m)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class _TextReader:
|
||||
|
||||
"""Text format reader.
|
||||
|
||||
tok: the tokenizer.
|
||||
message: The message object being built.
|
||||
DNS dynamic updates.
|
||||
last_name: The most recently read name when building a message object.
|
||||
one_rr_per_rrset: Put each RR into its own RRset?
|
||||
origin: The origin for relative names
|
||||
relativize: relativize names?
|
||||
relativize_to: the origin to relativize to.
|
||||
"""
|
||||
|
||||
def __init__(self, text, idna_codec, one_rr_per_rrset=False,
|
||||
origin=None, relativize=True, relativize_to=None):
|
||||
self.message = None
|
||||
self.tok = dns.tokenizer.Tokenizer(text, idna_codec=idna_codec)
|
||||
self.last_name = None
|
||||
self.one_rr_per_rrset = one_rr_per_rrset
|
||||
self.origin = origin
|
||||
self.relativize = relativize
|
||||
self.relativize_to = relativize_to
|
||||
self.id = None
|
||||
self.edns = -1
|
||||
self.ednsflags = 0
|
||||
self.payload = DEFAULT_EDNS_PAYLOAD
|
||||
self.rcode = None
|
||||
self.opcode = dns.opcode.QUERY
|
||||
self.flags = 0
|
||||
|
||||
def _header_line(self, _):
|
||||
"""Process one line from the text format header section."""
|
||||
|
||||
token = self.tok.get()
|
||||
what = token.value
|
||||
if what == 'id':
|
||||
self.id = self.tok.get_int()
|
||||
elif what == 'flags':
|
||||
while True:
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
self.tok.unget(token)
|
||||
break
|
||||
self.flags = self.flags | dns.flags.from_text(token.value)
|
||||
elif what == 'edns':
|
||||
self.edns = self.tok.get_int()
|
||||
self.ednsflags = self.ednsflags | (self.edns << 16)
|
||||
elif what == 'eflags':
|
||||
if self.edns < 0:
|
||||
self.edns = 0
|
||||
while True:
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
self.tok.unget(token)
|
||||
break
|
||||
self.ednsflags = self.ednsflags | \
|
||||
dns.flags.edns_from_text(token.value)
|
||||
elif what == 'payload':
|
||||
self.payload = self.tok.get_int()
|
||||
if self.edns < 0:
|
||||
self.edns = 0
|
||||
elif what == 'opcode':
|
||||
text = self.tok.get_string()
|
||||
self.opcode = dns.opcode.from_text(text)
|
||||
self.flags = self.flags | dns.opcode.to_flags(self.opcode)
|
||||
elif what == 'rcode':
|
||||
text = self.tok.get_string()
|
||||
self.rcode = dns.rcode.from_text(text)
|
||||
else:
|
||||
raise UnknownHeaderField
|
||||
self.tok.get_eol()
|
||||
|
||||
def _question_line(self, section_number):
|
||||
"""Process one line from the text format question section."""
|
||||
|
||||
section = self.message.sections[section_number]
|
||||
token = self.tok.get(want_leading=True)
|
||||
if not token.is_whitespace():
|
||||
self.last_name = self.tok.as_name(token, self.message.origin,
|
||||
self.relativize,
|
||||
self.relativize_to)
|
||||
name = self.last_name
|
||||
if name is None:
|
||||
raise NoPreviousName
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
raise dns.exception.SyntaxError
|
||||
# Class
|
||||
try:
|
||||
rdclass = dns.rdataclass.from_text(token.value)
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
raise dns.exception.SyntaxError
|
||||
except dns.exception.SyntaxError:
|
||||
raise dns.exception.SyntaxError
|
||||
except Exception:
|
||||
rdclass = dns.rdataclass.IN
|
||||
# Type
|
||||
rdtype = dns.rdatatype.from_text(token.value)
|
||||
(rdclass, rdtype, _, _) = \
|
||||
self.message._parse_rr_header(section_number, name, rdclass, rdtype)
|
||||
self.message.find_rrset(section, name, rdclass, rdtype, create=True,
|
||||
force_unique=True)
|
||||
self.tok.get_eol()
|
||||
|
||||
def _rr_line(self, section_number):
|
||||
"""Process one line from the text format answer, authority, or
|
||||
additional data sections.
|
||||
"""
|
||||
|
||||
section = self.message.sections[section_number]
|
||||
# Name
|
||||
token = self.tok.get(want_leading=True)
|
||||
if not token.is_whitespace():
|
||||
self.last_name = self.tok.as_name(token, self.message.origin,
|
||||
self.relativize,
|
||||
self.relativize_to)
|
||||
name = self.last_name
|
||||
if name is None:
|
||||
raise NoPreviousName
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
raise dns.exception.SyntaxError
|
||||
# TTL
|
||||
try:
|
||||
ttl = int(token.value, 0)
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
raise dns.exception.SyntaxError
|
||||
except dns.exception.SyntaxError:
|
||||
raise dns.exception.SyntaxError
|
||||
except Exception:
|
||||
ttl = 0
|
||||
# Class
|
||||
try:
|
||||
rdclass = dns.rdataclass.from_text(token.value)
|
||||
token = self.tok.get()
|
||||
if not token.is_identifier():
|
||||
raise dns.exception.SyntaxError
|
||||
except dns.exception.SyntaxError:
|
||||
raise dns.exception.SyntaxError
|
||||
except Exception:
|
||||
rdclass = dns.rdataclass.IN
|
||||
# Type
|
||||
rdtype = dns.rdatatype.from_text(token.value)
|
||||
(rdclass, rdtype, deleting, empty) = \
|
||||
self.message._parse_rr_header(section_number, name, rdclass, rdtype)
|
||||
token = self.tok.get()
|
||||
if empty and not token.is_eol_or_eof():
|
||||
raise dns.exception.SyntaxError
|
||||
if not empty and token.is_eol_or_eof():
|
||||
raise dns.exception.UnexpectedEnd
|
||||
if not token.is_eol_or_eof():
|
||||
self.tok.unget(token)
|
||||
rd = dns.rdata.from_text(rdclass, rdtype, self.tok,
|
||||
self.message.origin, self.relativize,
|
||||
self.relativize_to)
|
||||
covers = rd.covers()
|
||||
else:
|
||||
rd = None
|
||||
covers = dns.rdatatype.NONE
|
||||
rrset = self.message.find_rrset(section, name,
|
||||
rdclass, rdtype, covers,
|
||||
deleting, True, self.one_rr_per_rrset)
|
||||
if rd is not None:
|
||||
rrset.add(rd, ttl)
|
||||
|
||||
def _make_message(self):
|
||||
factory = _message_factory_from_opcode(self.opcode)
|
||||
message = factory(id=self.id)
|
||||
message.flags = self.flags
|
||||
if self.edns >= 0:
|
||||
message.use_edns(self.edns, self.ednsflags, self.payload)
|
||||
if self.rcode:
|
||||
message.set_rcode(self.rcode)
|
||||
if self.origin:
|
||||
message.origin = self.origin
|
||||
return message
|
||||
|
||||
def read(self):
|
||||
"""Read a text format DNS message and build a dns.message.Message
|
||||
object."""
|
||||
|
||||
line_method = self._header_line
|
||||
section_number = None
|
||||
while 1:
|
||||
token = self.tok.get(True, True)
|
||||
if token.is_eol_or_eof():
|
||||
break
|
||||
if token.is_comment():
|
||||
u = token.value.upper()
|
||||
if u == 'HEADER':
|
||||
line_method = self._header_line
|
||||
|
||||
if self.message:
|
||||
message = self.message
|
||||
else:
|
||||
# If we don't have a message, create one with the current
|
||||
# opcode, so that we know which section names to parse.
|
||||
message = self._make_message()
|
||||
try:
|
||||
section_number = message._section_enum.from_text(u)
|
||||
# We found a section name. If we don't have a message,
|
||||
# use the one we just created.
|
||||
if not self.message:
|
||||
self.message = message
|
||||
self.one_rr_per_rrset = \
|
||||
message._get_one_rr_per_rrset(self.one_rr_per_rrset)
|
||||
if section_number == MessageSection.QUESTION:
|
||||
line_method = self._question_line
|
||||
else:
|
||||
line_method = self._rr_line
|
||||
except Exception:
|
||||
# It's just a comment.
|
||||
pass
|
||||
self.tok.get_eol()
|
||||
continue
|
||||
self.tok.unget(token)
|
||||
line_method(section_number)
|
||||
if not self.message:
|
||||
self.message = self._make_message()
|
||||
return self.message
|
||||
|
||||
|
||||
def from_text(text, idna_codec=None, one_rr_per_rrset=False,
|
||||
origin=None, relativize=True, relativize_to=None):
|
||||
"""Convert the text format message into a message object.
|
||||
|
||||
The reader stops after reading the first blank line in the input to
|
||||
facilitate reading multiple messages from a single file with
|
||||
``dns.message.from_file()``.
|
||||
|
||||
*text*, a ``str``, the text format message.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
|
||||
is used.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put
|
||||
into its own rrset. The default is ``False``.
|
||||
|
||||
*origin*, a ``dns.name.Name`` (or ``None``), the
|
||||
origin to use for relative names.
|
||||
|
||||
*relativize*, a ``bool``. If true, name will be relativized.
|
||||
|
||||
*relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
|
||||
when relativizing names. If not set, the *origin* value will be used.
|
||||
|
||||
Raises ``dns.message.UnknownHeaderField`` if a header is unknown.
|
||||
|
||||
Raises ``dns.exception.SyntaxError`` if the text is badly formed.
|
||||
|
||||
Returns a ``dns.message.Message object``
|
||||
"""
|
||||
|
||||
# 'text' can also be a file, but we don't publish that fact
|
||||
# since it's an implementation detail. The official file
|
||||
# interface is from_file().
|
||||
|
||||
reader = _TextReader(text, idna_codec, one_rr_per_rrset, origin,
|
||||
relativize, relativize_to)
|
||||
return reader.read()
|
||||
|
||||
|
||||
def from_file(f, idna_codec=None, one_rr_per_rrset=False):
|
||||
"""Read the next text format message from the specified file.
|
||||
|
||||
Message blocks are separated by a single blank line.
|
||||
|
||||
*f*, a ``file`` or ``str``. If *f* is text, it is treated as the
|
||||
pathname of a file to open.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
|
||||
is used.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put
|
||||
into its own rrset. The default is ``False``.
|
||||
|
||||
Raises ``dns.message.UnknownHeaderField`` if a header is unknown.
|
||||
|
||||
Raises ``dns.exception.SyntaxError`` if the text is badly formed.
|
||||
|
||||
Returns a ``dns.message.Message object``
|
||||
"""
|
||||
|
||||
with contextlib.ExitStack() as stack:
|
||||
if isinstance(f, str):
|
||||
f = stack.enter_context(open(f))
|
||||
return from_text(f, idna_codec, one_rr_per_rrset)
|
||||
|
||||
|
||||
def make_query(qname, rdtype, rdclass=dns.rdataclass.IN, use_edns=None,
|
||||
want_dnssec=False, ednsflags=None, payload=None,
|
||||
request_payload=None, options=None, idna_codec=None):
|
||||
"""Make a query message.
|
||||
|
||||
The query name, type, and class may all be specified either
|
||||
as objects of the appropriate type, or as strings.
|
||||
|
||||
The query will have a randomly chosen query id, and its DNS flags
|
||||
will be set to dns.flags.RD.
|
||||
|
||||
qname, a ``dns.name.Name`` or ``str``, the query name.
|
||||
|
||||
*rdtype*, an ``int`` or ``str``, the desired rdata type.
|
||||
|
||||
*rdclass*, an ``int`` or ``str``, the desired rdata class; the default
|
||||
is class IN.
|
||||
|
||||
*use_edns*, an ``int``, ``bool`` or ``None``. The EDNS level to use; the
|
||||
default is None (no EDNS).
|
||||
See the description of dns.message.Message.use_edns() for the possible
|
||||
values for use_edns and their meanings.
|
||||
|
||||
*want_dnssec*, a ``bool``. If ``True``, DNSSEC data is desired.
|
||||
|
||||
*ednsflags*, an ``int``, the EDNS flag values.
|
||||
|
||||
*payload*, an ``int``, is the EDNS sender's payload field, which is the
|
||||
maximum size of UDP datagram the sender can handle. I.e. how big
|
||||
a response to this message can be.
|
||||
|
||||
*request_payload*, an ``int``, is the EDNS payload size to use when
|
||||
sending this message. If not specified, defaults to the value of
|
||||
*payload*.
|
||||
|
||||
*options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS
|
||||
options.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
|
||||
is used.
|
||||
|
||||
Returns a ``dns.message.QueryMessage``
|
||||
"""
|
||||
|
||||
if isinstance(qname, str):
|
||||
qname = dns.name.from_text(qname, idna_codec=idna_codec)
|
||||
rdtype = dns.rdatatype.RdataType.make(rdtype)
|
||||
rdclass = dns.rdataclass.RdataClass.make(rdclass)
|
||||
m = QueryMessage()
|
||||
m.flags |= dns.flags.RD
|
||||
m.find_rrset(m.question, qname, rdclass, rdtype, create=True,
|
||||
force_unique=True)
|
||||
# only pass keywords on to use_edns if they have been set to a
|
||||
# non-None value. Setting a field will turn EDNS on if it hasn't
|
||||
# been configured.
|
||||
kwargs = {}
|
||||
if ednsflags is not None:
|
||||
kwargs['ednsflags'] = ednsflags
|
||||
if payload is not None:
|
||||
kwargs['payload'] = payload
|
||||
if request_payload is not None:
|
||||
kwargs['request_payload'] = request_payload
|
||||
if options is not None:
|
||||
kwargs['options'] = options
|
||||
if kwargs and use_edns is None:
|
||||
use_edns = 0
|
||||
kwargs['edns'] = use_edns
|
||||
m.use_edns(**kwargs)
|
||||
m.want_dnssec(want_dnssec)
|
||||
return m
|
||||
|
||||
|
||||
def make_response(query, recursion_available=False, our_payload=8192,
|
||||
fudge=300, tsig_error=0):
|
||||
"""Make a message which is a response for the specified query.
|
||||
The message returned is really a response skeleton; it has all
|
||||
of the infrastructure required of a response, but none of the
|
||||
content.
|
||||
|
||||
The response's question section is a shallow copy of the query's
|
||||
question section, so the query's question RRsets should not be
|
||||
changed.
|
||||
|
||||
*query*, a ``dns.message.Message``, the query to respond to.
|
||||
|
||||
*recursion_available*, a ``bool``, should RA be set in the response?
|
||||
|
||||
*our_payload*, an ``int``, the payload size to advertise in EDNS
|
||||
responses.
|
||||
|
||||
*fudge*, an ``int``, the TSIG time fudge.
|
||||
|
||||
*tsig_error*, an ``int``, the TSIG error.
|
||||
|
||||
Returns a ``dns.message.Message`` object whose specific class is
|
||||
appropriate for the query. For example, if query is a
|
||||
``dns.update.UpdateMessage``, response will be too.
|
||||
"""
|
||||
|
||||
if query.flags & dns.flags.QR:
|
||||
raise dns.exception.FormError('specified query message is not a query')
|
||||
factory = _message_factory_from_opcode(query.opcode())
|
||||
response = factory(id=query.id)
|
||||
response.flags = dns.flags.QR | (query.flags & dns.flags.RD)
|
||||
if recursion_available:
|
||||
response.flags |= dns.flags.RA
|
||||
response.set_opcode(query.opcode())
|
||||
response.question = list(query.question)
|
||||
if query.edns >= 0:
|
||||
response.use_edns(0, 0, our_payload, query.payload)
|
||||
if query.had_tsig:
|
||||
response.use_tsig(query.keyring, query.keyname, fudge, None,
|
||||
tsig_error, b'', query.keyalgorithm)
|
||||
response.request_mac = query.mac
|
||||
return response
|
||||
|
||||
### BEGIN generated MessageSection constants
|
||||
|
||||
QUESTION = MessageSection.QUESTION
|
||||
ANSWER = MessageSection.ANSWER
|
||||
AUTHORITY = MessageSection.AUTHORITY
|
||||
ADDITIONAL = MessageSection.ADDITIONAL
|
||||
|
||||
### END generated MessageSection constants
|
1018
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/name.py
vendored
Normal file
1018
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/name.py
vendored
Normal file
|
@ -0,0 +1,1018 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Names.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import struct
|
||||
|
||||
import encodings.idna # type: ignore
|
||||
try:
|
||||
import idna # type: ignore
|
||||
have_idna_2008 = True
|
||||
except ImportError: # pragma: no cover
|
||||
have_idna_2008 = False
|
||||
|
||||
import dns.wire
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
|
||||
# fullcompare() result values
|
||||
|
||||
#: The compared names have no relationship to each other.
|
||||
NAMERELN_NONE = 0
|
||||
#: the first name is a superdomain of the second.
|
||||
NAMERELN_SUPERDOMAIN = 1
|
||||
#: The first name is a subdomain of the second.
|
||||
NAMERELN_SUBDOMAIN = 2
|
||||
#: The compared names are equal.
|
||||
NAMERELN_EQUAL = 3
|
||||
#: The compared names have a common ancestor.
|
||||
NAMERELN_COMMONANCESTOR = 4
|
||||
|
||||
|
||||
class EmptyLabel(dns.exception.SyntaxError):
|
||||
"""A DNS label is empty."""
|
||||
|
||||
|
||||
class BadEscape(dns.exception.SyntaxError):
|
||||
"""An escaped code in a text format of DNS name is invalid."""
|
||||
|
||||
|
||||
class BadPointer(dns.exception.FormError):
|
||||
"""A DNS compression pointer points forward instead of backward."""
|
||||
|
||||
|
||||
class BadLabelType(dns.exception.FormError):
|
||||
"""The label type in DNS name wire format is unknown."""
|
||||
|
||||
|
||||
class NeedAbsoluteNameOrOrigin(dns.exception.DNSException):
|
||||
"""An attempt was made to convert a non-absolute name to
|
||||
wire when there was also a non-absolute (or missing) origin."""
|
||||
|
||||
|
||||
class NameTooLong(dns.exception.FormError):
|
||||
"""A DNS name is > 255 octets long."""
|
||||
|
||||
|
||||
class LabelTooLong(dns.exception.SyntaxError):
|
||||
"""A DNS label is > 63 octets long."""
|
||||
|
||||
|
||||
class AbsoluteConcatenation(dns.exception.DNSException):
|
||||
"""An attempt was made to append anything other than the
|
||||
empty name to an absolute DNS name."""
|
||||
|
||||
|
||||
class NoParent(dns.exception.DNSException):
|
||||
"""An attempt was made to get the parent of the root name
|
||||
or the empty name."""
|
||||
|
||||
class NoIDNA2008(dns.exception.DNSException):
|
||||
"""IDNA 2008 processing was requested but the idna module is not
|
||||
available."""
|
||||
|
||||
|
||||
class IDNAException(dns.exception.DNSException):
|
||||
"""IDNA processing raised an exception."""
|
||||
|
||||
supp_kwargs = {'idna_exception'}
|
||||
fmt = "IDNA processing exception: {idna_exception}"
|
||||
|
||||
|
||||
class IDNACodec:
|
||||
"""Abstract base class for IDNA encoder/decoders."""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def is_idna(self, label):
|
||||
return label.lower().startswith(b'xn--')
|
||||
|
||||
def encode(self, label):
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
def decode(self, label):
|
||||
# We do not apply any IDNA policy on decode.
|
||||
if self.is_idna(label):
|
||||
try:
|
||||
label = label[4:].decode('punycode')
|
||||
except Exception as e:
|
||||
raise IDNAException(idna_exception=e)
|
||||
return _escapify(label)
|
||||
|
||||
|
||||
class IDNA2003Codec(IDNACodec):
|
||||
"""IDNA 2003 encoder/decoder."""
|
||||
|
||||
def __init__(self, strict_decode=False):
|
||||
"""Initialize the IDNA 2003 encoder/decoder.
|
||||
|
||||
*strict_decode* is a ``bool``. If `True`, then IDNA2003 checking
|
||||
is done when decoding. This can cause failures if the name
|
||||
was encoded with IDNA2008. The default is `False`.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self.strict_decode = strict_decode
|
||||
|
||||
def encode(self, label):
|
||||
"""Encode *label*."""
|
||||
|
||||
if label == '':
|
||||
return b''
|
||||
try:
|
||||
return encodings.idna.ToASCII(label)
|
||||
except UnicodeError:
|
||||
raise LabelTooLong
|
||||
|
||||
def decode(self, label):
|
||||
"""Decode *label*."""
|
||||
if not self.strict_decode:
|
||||
return super().decode(label)
|
||||
if label == b'':
|
||||
return ''
|
||||
try:
|
||||
return _escapify(encodings.idna.ToUnicode(label))
|
||||
except Exception as e:
|
||||
raise IDNAException(idna_exception=e)
|
||||
|
||||
|
||||
class IDNA2008Codec(IDNACodec):
|
||||
"""IDNA 2008 encoder/decoder.
|
||||
"""
|
||||
|
||||
def __init__(self, uts_46=False, transitional=False,
|
||||
allow_pure_ascii=False, strict_decode=False):
|
||||
"""Initialize the IDNA 2008 encoder/decoder.
|
||||
|
||||
*uts_46* is a ``bool``. If True, apply Unicode IDNA
|
||||
compatibility processing as described in Unicode Technical
|
||||
Standard #46 (http://unicode.org/reports/tr46/).
|
||||
If False, do not apply the mapping. The default is False.
|
||||
|
||||
*transitional* is a ``bool``: If True, use the
|
||||
"transitional" mode described in Unicode Technical Standard
|
||||
#46. The default is False.
|
||||
|
||||
*allow_pure_ascii* is a ``bool``. If True, then a label which
|
||||
consists of only ASCII characters is allowed. This is less
|
||||
strict than regular IDNA 2008, but is also necessary for mixed
|
||||
names, e.g. a name with starting with "_sip._tcp." and ending
|
||||
in an IDN suffix which would otherwise be disallowed. The
|
||||
default is False.
|
||||
|
||||
*strict_decode* is a ``bool``: If True, then IDNA2008 checking
|
||||
is done when decoding. This can cause failures if the name
|
||||
was encoded with IDNA2003. The default is False.
|
||||
"""
|
||||
super().__init__()
|
||||
self.uts_46 = uts_46
|
||||
self.transitional = transitional
|
||||
self.allow_pure_ascii = allow_pure_ascii
|
||||
self.strict_decode = strict_decode
|
||||
|
||||
def encode(self, label):
|
||||
if label == '':
|
||||
return b''
|
||||
if self.allow_pure_ascii and is_all_ascii(label):
|
||||
encoded = label.encode('ascii')
|
||||
if len(encoded) > 63:
|
||||
raise LabelTooLong
|
||||
return encoded
|
||||
if not have_idna_2008:
|
||||
raise NoIDNA2008
|
||||
try:
|
||||
if self.uts_46:
|
||||
label = idna.uts46_remap(label, False, self.transitional)
|
||||
return idna.alabel(label)
|
||||
except idna.IDNAError as e:
|
||||
if e.args[0] == 'Label too long':
|
||||
raise LabelTooLong
|
||||
else:
|
||||
raise IDNAException(idna_exception=e)
|
||||
|
||||
def decode(self, label):
|
||||
if not self.strict_decode:
|
||||
return super().decode(label)
|
||||
if label == b'':
|
||||
return ''
|
||||
if not have_idna_2008:
|
||||
raise NoIDNA2008
|
||||
try:
|
||||
ulabel = idna.ulabel(label)
|
||||
if self.uts_46:
|
||||
ulabel = idna.uts46_remap(ulabel, False, self.transitional)
|
||||
return _escapify(ulabel)
|
||||
except (idna.IDNAError, UnicodeError) as e:
|
||||
raise IDNAException(idna_exception=e)
|
||||
|
||||
_escaped = b'"().;\\@$'
|
||||
_escaped_text = '"().;\\@$'
|
||||
|
||||
IDNA_2003_Practical = IDNA2003Codec(False)
|
||||
IDNA_2003_Strict = IDNA2003Codec(True)
|
||||
IDNA_2003 = IDNA_2003_Practical
|
||||
IDNA_2008_Practical = IDNA2008Codec(True, False, True, False)
|
||||
IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False)
|
||||
IDNA_2008_Strict = IDNA2008Codec(False, False, False, True)
|
||||
IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False)
|
||||
IDNA_2008 = IDNA_2008_Practical
|
||||
|
||||
def _escapify(label):
|
||||
"""Escape the characters in label which need it.
|
||||
@returns: the escaped string
|
||||
@rtype: string"""
|
||||
if isinstance(label, bytes):
|
||||
# Ordinary DNS label mode. Escape special characters and values
|
||||
# < 0x20 or > 0x7f.
|
||||
text = ''
|
||||
for c in label:
|
||||
if c in _escaped:
|
||||
text += '\\' + chr(c)
|
||||
elif c > 0x20 and c < 0x7F:
|
||||
text += chr(c)
|
||||
else:
|
||||
text += '\\%03d' % c
|
||||
return text
|
||||
|
||||
# Unicode label mode. Escape only special characters and values < 0x20
|
||||
text = ''
|
||||
for c in label:
|
||||
if c in _escaped_text:
|
||||
text += '\\' + c
|
||||
elif c <= '\x20':
|
||||
text += '\\%03d' % ord(c)
|
||||
else:
|
||||
text += c
|
||||
return text
|
||||
|
||||
def _validate_labels(labels):
|
||||
"""Check for empty labels in the middle of a label sequence,
|
||||
labels that are too long, and for too many labels.
|
||||
|
||||
Raises ``dns.name.NameTooLong`` if the name as a whole is too long.
|
||||
|
||||
Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root
|
||||
label) and appears in a position other than the end of the label
|
||||
sequence
|
||||
|
||||
"""
|
||||
|
||||
l = len(labels)
|
||||
total = 0
|
||||
i = -1
|
||||
j = 0
|
||||
for label in labels:
|
||||
ll = len(label)
|
||||
total += ll + 1
|
||||
if ll > 63:
|
||||
raise LabelTooLong
|
||||
if i < 0 and label == b'':
|
||||
i = j
|
||||
j += 1
|
||||
if total > 255:
|
||||
raise NameTooLong
|
||||
if i >= 0 and i != l - 1:
|
||||
raise EmptyLabel
|
||||
|
||||
|
||||
def _maybe_convert_to_binary(label):
|
||||
"""If label is ``str``, convert it to ``bytes``. If it is already
|
||||
``bytes`` just return it.
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(label, bytes):
|
||||
return label
|
||||
if isinstance(label, str):
|
||||
return label.encode()
|
||||
raise ValueError # pragma: no cover
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class Name:
|
||||
|
||||
"""A DNS name.
|
||||
|
||||
The dns.name.Name class represents a DNS name as a tuple of
|
||||
labels. Each label is a ``bytes`` in DNS wire format. Instances
|
||||
of the class are immutable.
|
||||
"""
|
||||
|
||||
__slots__ = ['labels']
|
||||
|
||||
def __init__(self, labels):
|
||||
"""*labels* is any iterable whose values are ``str`` or ``bytes``.
|
||||
"""
|
||||
|
||||
labels = [_maybe_convert_to_binary(x) for x in labels]
|
||||
self.labels = tuple(labels)
|
||||
_validate_labels(self.labels)
|
||||
|
||||
def __copy__(self):
|
||||
return Name(self.labels)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return Name(copy.deepcopy(self.labels, memo))
|
||||
|
||||
def __getstate__(self):
|
||||
# Names can be pickled
|
||||
return {'labels': self.labels}
|
||||
|
||||
def __setstate__(self, state):
|
||||
super().__setattr__('labels', state['labels'])
|
||||
_validate_labels(self.labels)
|
||||
|
||||
def is_absolute(self):
|
||||
"""Is the most significant label of this name the root label?
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
return len(self.labels) > 0 and self.labels[-1] == b''
|
||||
|
||||
def is_wild(self):
|
||||
"""Is this name wild? (I.e. Is the least significant label '*'?)
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
return len(self.labels) > 0 and self.labels[0] == b'*'
|
||||
|
||||
def __hash__(self):
|
||||
"""Return a case-insensitive hash of the name.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
h = 0
|
||||
for label in self.labels:
|
||||
for c in label.lower():
|
||||
h += (h << 3) + c
|
||||
return h
|
||||
|
||||
def fullcompare(self, other):
|
||||
"""Compare two names, returning a 3-tuple
|
||||
``(relation, order, nlabels)``.
|
||||
|
||||
*relation* describes the relation ship between the names,
|
||||
and is one of: ``dns.name.NAMERELN_NONE``,
|
||||
``dns.name.NAMERELN_SUPERDOMAIN``, ``dns.name.NAMERELN_SUBDOMAIN``,
|
||||
``dns.name.NAMERELN_EQUAL``, or ``dns.name.NAMERELN_COMMONANCESTOR``.
|
||||
|
||||
*order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and ==
|
||||
0 if *self* == *other*. A relative name is always less than an
|
||||
absolute name. If both names have the same relativity, then
|
||||
the DNSSEC order relation is used to order them.
|
||||
|
||||
*nlabels* is the number of significant labels that the two names
|
||||
have in common.
|
||||
|
||||
Here are some examples. Names ending in "." are absolute names,
|
||||
those not ending in "." are relative names.
|
||||
|
||||
============= ============= =========== ===== =======
|
||||
self other relation order nlabels
|
||||
============= ============= =========== ===== =======
|
||||
www.example. www.example. equal 0 3
|
||||
www.example. example. subdomain > 0 2
|
||||
example. www.example. superdomain < 0 2
|
||||
example1.com. example2.com. common anc. < 0 2
|
||||
example1 example2. none < 0 0
|
||||
example1. example2 none > 0 0
|
||||
============= ============= =========== ===== =======
|
||||
"""
|
||||
|
||||
sabs = self.is_absolute()
|
||||
oabs = other.is_absolute()
|
||||
if sabs != oabs:
|
||||
if sabs:
|
||||
return (NAMERELN_NONE, 1, 0)
|
||||
else:
|
||||
return (NAMERELN_NONE, -1, 0)
|
||||
l1 = len(self.labels)
|
||||
l2 = len(other.labels)
|
||||
ldiff = l1 - l2
|
||||
if ldiff < 0:
|
||||
l = l1
|
||||
else:
|
||||
l = l2
|
||||
|
||||
order = 0
|
||||
nlabels = 0
|
||||
namereln = NAMERELN_NONE
|
||||
while l > 0:
|
||||
l -= 1
|
||||
l1 -= 1
|
||||
l2 -= 1
|
||||
label1 = self.labels[l1].lower()
|
||||
label2 = other.labels[l2].lower()
|
||||
if label1 < label2:
|
||||
order = -1
|
||||
if nlabels > 0:
|
||||
namereln = NAMERELN_COMMONANCESTOR
|
||||
return (namereln, order, nlabels)
|
||||
elif label1 > label2:
|
||||
order = 1
|
||||
if nlabels > 0:
|
||||
namereln = NAMERELN_COMMONANCESTOR
|
||||
return (namereln, order, nlabels)
|
||||
nlabels += 1
|
||||
order = ldiff
|
||||
if ldiff < 0:
|
||||
namereln = NAMERELN_SUPERDOMAIN
|
||||
elif ldiff > 0:
|
||||
namereln = NAMERELN_SUBDOMAIN
|
||||
else:
|
||||
namereln = NAMERELN_EQUAL
|
||||
return (namereln, order, nlabels)
|
||||
|
||||
def is_subdomain(self, other):
|
||||
"""Is self a subdomain of other?
|
||||
|
||||
Note that the notion of subdomain includes equality, e.g.
|
||||
"dnpython.org" is a subdomain of itself.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
(nr, _, _) = self.fullcompare(other)
|
||||
if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_superdomain(self, other):
|
||||
"""Is self a superdomain of other?
|
||||
|
||||
Note that the notion of superdomain includes equality, e.g.
|
||||
"dnpython.org" is a superdomain of itself.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
(nr, _, _) = self.fullcompare(other)
|
||||
if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL:
|
||||
return True
|
||||
return False
|
||||
|
||||
def canonicalize(self):
|
||||
"""Return a name which is equal to the current name, but is in
|
||||
DNSSEC canonical form.
|
||||
"""
|
||||
|
||||
return Name([x.lower() for x in self.labels])
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] == 0
|
||||
else:
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] != 0
|
||||
else:
|
||||
return True
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] < 0
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] <= 0
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] >= 0
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, Name):
|
||||
return self.fullcompare(other)[1] > 0
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __repr__(self):
|
||||
return '<DNS name ' + self.__str__() + '>'
|
||||
|
||||
def __str__(self):
|
||||
return self.to_text(False)
|
||||
|
||||
def to_text(self, omit_final_dot=False):
|
||||
"""Convert name to DNS text format.
|
||||
|
||||
*omit_final_dot* is a ``bool``. If True, don't emit the final
|
||||
dot (denoting the root label) for absolute names. The default
|
||||
is False.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if len(self.labels) == 0:
|
||||
return '@'
|
||||
if len(self.labels) == 1 and self.labels[0] == b'':
|
||||
return '.'
|
||||
if omit_final_dot and self.is_absolute():
|
||||
l = self.labels[:-1]
|
||||
else:
|
||||
l = self.labels
|
||||
s = '.'.join(map(_escapify, l))
|
||||
return s
|
||||
|
||||
def to_unicode(self, omit_final_dot=False, idna_codec=None):
|
||||
"""Convert name to Unicode text format.
|
||||
|
||||
IDN ACE labels are converted to Unicode.
|
||||
|
||||
*omit_final_dot* is a ``bool``. If True, don't emit the final
|
||||
dot (denoting the root label) for absolute names. The default
|
||||
is False.
|
||||
*idna_codec* specifies the IDNA encoder/decoder. If None, the
|
||||
dns.name.IDNA_2003_Practical encoder/decoder is used.
|
||||
The IDNA_2003_Practical decoder does
|
||||
not impose any policy, it just decodes punycode, so if you
|
||||
don't want checking for compliance, you can use this decoder
|
||||
for IDNA2008 as well.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if len(self.labels) == 0:
|
||||
return '@'
|
||||
if len(self.labels) == 1 and self.labels[0] == b'':
|
||||
return '.'
|
||||
if omit_final_dot and self.is_absolute():
|
||||
l = self.labels[:-1]
|
||||
else:
|
||||
l = self.labels
|
||||
if idna_codec is None:
|
||||
idna_codec = IDNA_2003_Practical
|
||||
return '.'.join([idna_codec.decode(x) for x in l])
|
||||
|
||||
def to_digestable(self, origin=None):
|
||||
"""Convert name to a format suitable for digesting in hashes.
|
||||
|
||||
The name is canonicalized and converted to uncompressed wire
|
||||
format. All names in wire format are absolute. If the name
|
||||
is a relative name, then an origin must be supplied.
|
||||
|
||||
*origin* is a ``dns.name.Name`` or ``None``. If the name is
|
||||
relative and origin is not ``None``, then origin will be appended
|
||||
to the name.
|
||||
|
||||
Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
|
||||
relative and no origin was provided.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
return self.to_wire(origin=origin, canonicalize=True)
|
||||
|
||||
def to_wire(self, file=None, compress=None, origin=None,
|
||||
canonicalize=False):
|
||||
"""Convert name to wire format, possibly compressing it.
|
||||
|
||||
*file* is the file where the name is emitted (typically an
|
||||
io.BytesIO file). If ``None`` (the default), a ``bytes``
|
||||
containing the wire name will be returned.
|
||||
|
||||
*compress*, a ``dict``, is the compression table to use. If
|
||||
``None`` (the default), names will not be compressed. Note that
|
||||
the compression code assumes that compression offset 0 is the
|
||||
start of *file*, and thus compression will not be correct
|
||||
if this is not the case.
|
||||
|
||||
*origin* is a ``dns.name.Name`` or ``None``. If the name is
|
||||
relative and origin is not ``None``, then *origin* will be appended
|
||||
to it.
|
||||
|
||||
*canonicalize*, a ``bool``, indicates whether the name should
|
||||
be canonicalized; that is, converted to a format suitable for
|
||||
digesting in hashes.
|
||||
|
||||
Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
|
||||
relative and no origin was provided.
|
||||
|
||||
Returns a ``bytes`` or ``None``.
|
||||
"""
|
||||
|
||||
if file is None:
|
||||
out = bytearray()
|
||||
for label in self.labels:
|
||||
out.append(len(label))
|
||||
if canonicalize:
|
||||
out += label.lower()
|
||||
else:
|
||||
out += label
|
||||
if not self.is_absolute():
|
||||
if origin is None or not origin.is_absolute():
|
||||
raise NeedAbsoluteNameOrOrigin
|
||||
for label in origin.labels:
|
||||
out.append(len(label))
|
||||
if canonicalize:
|
||||
out += label.lower()
|
||||
else:
|
||||
out += label
|
||||
return bytes(out)
|
||||
|
||||
if not self.is_absolute():
|
||||
if origin is None or not origin.is_absolute():
|
||||
raise NeedAbsoluteNameOrOrigin
|
||||
labels = list(self.labels)
|
||||
labels.extend(list(origin.labels))
|
||||
else:
|
||||
labels = self.labels
|
||||
i = 0
|
||||
for label in labels:
|
||||
n = Name(labels[i:])
|
||||
i += 1
|
||||
if compress is not None:
|
||||
pos = compress.get(n)
|
||||
else:
|
||||
pos = None
|
||||
if pos is not None:
|
||||
value = 0xc000 + pos
|
||||
s = struct.pack('!H', value)
|
||||
file.write(s)
|
||||
break
|
||||
else:
|
||||
if compress is not None and len(n) > 1:
|
||||
pos = file.tell()
|
||||
if pos <= 0x3fff:
|
||||
compress[n] = pos
|
||||
l = len(label)
|
||||
file.write(struct.pack('!B', l))
|
||||
if l > 0:
|
||||
if canonicalize:
|
||||
file.write(label.lower())
|
||||
else:
|
||||
file.write(label)
|
||||
|
||||
def __len__(self):
|
||||
"""The length of the name (in labels).
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return len(self.labels)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.labels[index]
|
||||
|
||||
def __add__(self, other):
|
||||
return self.concatenate(other)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.relativize(other)
|
||||
|
||||
def split(self, depth):
|
||||
"""Split a name into a prefix and suffix names at the specified depth.
|
||||
|
||||
*depth* is an ``int`` specifying the number of labels in the suffix
|
||||
|
||||
Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the
|
||||
name.
|
||||
|
||||
Returns the tuple ``(prefix, suffix)``.
|
||||
"""
|
||||
|
||||
l = len(self.labels)
|
||||
if depth == 0:
|
||||
return (self, dns.name.empty)
|
||||
elif depth == l:
|
||||
return (dns.name.empty, self)
|
||||
elif depth < 0 or depth > l:
|
||||
raise ValueError(
|
||||
'depth must be >= 0 and <= the length of the name')
|
||||
return (Name(self[: -depth]), Name(self[-depth:]))
|
||||
|
||||
def concatenate(self, other):
|
||||
"""Return a new name which is the concatenation of self and other.
|
||||
|
||||
Raises ``dns.name.AbsoluteConcatenation`` if the name is
|
||||
absolute and *other* is not the empty name.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if self.is_absolute() and len(other) > 0:
|
||||
raise AbsoluteConcatenation
|
||||
labels = list(self.labels)
|
||||
labels.extend(list(other.labels))
|
||||
return Name(labels)
|
||||
|
||||
def relativize(self, origin):
|
||||
"""If the name is a subdomain of *origin*, return a new name which is
|
||||
the name relative to origin. Otherwise return the name.
|
||||
|
||||
For example, relativizing ``www.dnspython.org.`` to origin
|
||||
``dnspython.org.`` returns the name ``www``. Relativizing ``example.``
|
||||
to origin ``dnspython.org.`` returns ``example.``.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if origin is not None and self.is_subdomain(origin):
|
||||
return Name(self[: -len(origin)])
|
||||
else:
|
||||
return self
|
||||
|
||||
def derelativize(self, origin):
|
||||
"""If the name is a relative name, return a new name which is the
|
||||
concatenation of the name and origin. Otherwise return the name.
|
||||
|
||||
For example, derelativizing ``www`` to origin ``dnspython.org.``
|
||||
returns the name ``www.dnspython.org.``. Derelativizing ``example.``
|
||||
to origin ``dnspython.org.`` returns ``example.``.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if not self.is_absolute():
|
||||
return self.concatenate(origin)
|
||||
else:
|
||||
return self
|
||||
|
||||
def choose_relativity(self, origin=None, relativize=True):
|
||||
"""Return a name with the relativity desired by the caller.
|
||||
|
||||
If *origin* is ``None``, then the name is returned.
|
||||
Otherwise, if *relativize* is ``True`` the name is
|
||||
relativized, and if *relativize* is ``False`` the name is
|
||||
derelativized.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if origin:
|
||||
if relativize:
|
||||
return self.relativize(origin)
|
||||
else:
|
||||
return self.derelativize(origin)
|
||||
else:
|
||||
return self
|
||||
|
||||
def parent(self):
|
||||
"""Return the parent of the name.
|
||||
|
||||
For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``.
|
||||
|
||||
Raises ``dns.name.NoParent`` if the name is either the root name or the
|
||||
empty name, and thus has no parent.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if self == root or self == empty:
|
||||
raise NoParent
|
||||
return Name(self.labels[1:])
|
||||
|
||||
#: The root name, '.'
|
||||
root = Name([b''])
|
||||
|
||||
#: The empty name.
|
||||
empty = Name([])
|
||||
|
||||
def from_unicode(text, origin=root, idna_codec=None):
|
||||
"""Convert unicode text into a Name object.
|
||||
|
||||
Labels are encoded in IDN ACE form according to rules specified by
|
||||
the IDNA codec.
|
||||
|
||||
*text*, a ``str``, is the text to convert into a name.
|
||||
|
||||
*origin*, a ``dns.name.Name``, specifies the origin to
|
||||
append to non-absolute names. The default is the root name.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
|
||||
is used.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if not isinstance(text, str):
|
||||
raise ValueError("input to from_unicode() must be a unicode string")
|
||||
if not (origin is None or isinstance(origin, Name)):
|
||||
raise ValueError("origin must be a Name or None")
|
||||
labels = []
|
||||
label = ''
|
||||
escaping = False
|
||||
edigits = 0
|
||||
total = 0
|
||||
if idna_codec is None:
|
||||
idna_codec = IDNA_2003
|
||||
if text == '@':
|
||||
text = ''
|
||||
if text:
|
||||
if text in ['.', '\u3002', '\uff0e', '\uff61']:
|
||||
return Name([b'']) # no Unicode "u" on this constant!
|
||||
for c in text:
|
||||
if escaping:
|
||||
if edigits == 0:
|
||||
if c.isdigit():
|
||||
total = int(c)
|
||||
edigits += 1
|
||||
else:
|
||||
label += c
|
||||
escaping = False
|
||||
else:
|
||||
if not c.isdigit():
|
||||
raise BadEscape
|
||||
total *= 10
|
||||
total += int(c)
|
||||
edigits += 1
|
||||
if edigits == 3:
|
||||
escaping = False
|
||||
label += chr(total)
|
||||
elif c in ['.', '\u3002', '\uff0e', '\uff61']:
|
||||
if len(label) == 0:
|
||||
raise EmptyLabel
|
||||
labels.append(idna_codec.encode(label))
|
||||
label = ''
|
||||
elif c == '\\':
|
||||
escaping = True
|
||||
edigits = 0
|
||||
total = 0
|
||||
else:
|
||||
label += c
|
||||
if escaping:
|
||||
raise BadEscape
|
||||
if len(label) > 0:
|
||||
labels.append(idna_codec.encode(label))
|
||||
else:
|
||||
labels.append(b'')
|
||||
|
||||
if (len(labels) == 0 or labels[-1] != b'') and origin is not None:
|
||||
labels.extend(list(origin.labels))
|
||||
return Name(labels)
|
||||
|
||||
def is_all_ascii(text):
|
||||
for c in text:
|
||||
if ord(c) > 0x7f:
|
||||
return False
|
||||
return True
|
||||
|
||||
def from_text(text, origin=root, idna_codec=None):
|
||||
"""Convert text into a Name object.
|
||||
|
||||
*text*, a ``str``, is the text to convert into a name.
|
||||
|
||||
*origin*, a ``dns.name.Name``, specifies the origin to
|
||||
append to non-absolute names. The default is the root name.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
|
||||
is used.
|
||||
|
||||
Returns a ``dns.name.Name``.
|
||||
"""
|
||||
|
||||
if isinstance(text, str):
|
||||
if not is_all_ascii(text):
|
||||
# Some codepoint in the input text is > 127, so IDNA applies.
|
||||
return from_unicode(text, origin, idna_codec)
|
||||
# The input is all ASCII, so treat this like an ordinary non-IDNA
|
||||
# domain name. Note that "all ASCII" is about the input text,
|
||||
# not the codepoints in the domain name. E.g. if text has value
|
||||
#
|
||||
# r'\150\151\152\153\154\155\156\157\158\159'
|
||||
#
|
||||
# then it's still "all ASCII" even though the domain name has
|
||||
# codepoints > 127.
|
||||
text = text.encode('ascii')
|
||||
if not isinstance(text, bytes):
|
||||
raise ValueError("input to from_text() must be a string")
|
||||
if not (origin is None or isinstance(origin, Name)):
|
||||
raise ValueError("origin must be a Name or None")
|
||||
labels = []
|
||||
label = b''
|
||||
escaping = False
|
||||
edigits = 0
|
||||
total = 0
|
||||
if text == b'@':
|
||||
text = b''
|
||||
if text:
|
||||
if text == b'.':
|
||||
return Name([b''])
|
||||
for c in text:
|
||||
byte_ = struct.pack('!B', c)
|
||||
if escaping:
|
||||
if edigits == 0:
|
||||
if byte_.isdigit():
|
||||
total = int(byte_)
|
||||
edigits += 1
|
||||
else:
|
||||
label += byte_
|
||||
escaping = False
|
||||
else:
|
||||
if not byte_.isdigit():
|
||||
raise BadEscape
|
||||
total *= 10
|
||||
total += int(byte_)
|
||||
edigits += 1
|
||||
if edigits == 3:
|
||||
escaping = False
|
||||
label += struct.pack('!B', total)
|
||||
elif byte_ == b'.':
|
||||
if len(label) == 0:
|
||||
raise EmptyLabel
|
||||
labels.append(label)
|
||||
label = b''
|
||||
elif byte_ == b'\\':
|
||||
escaping = True
|
||||
edigits = 0
|
||||
total = 0
|
||||
else:
|
||||
label += byte_
|
||||
if escaping:
|
||||
raise BadEscape
|
||||
if len(label) > 0:
|
||||
labels.append(label)
|
||||
else:
|
||||
labels.append(b'')
|
||||
if (len(labels) == 0 or labels[-1] != b'') and origin is not None:
|
||||
labels.extend(list(origin.labels))
|
||||
return Name(labels)
|
||||
|
||||
|
||||
def from_wire_parser(parser):
|
||||
"""Convert possibly compressed wire format into a Name.
|
||||
|
||||
*parser* is a dns.wire.Parser.
|
||||
|
||||
Raises ``dns.name.BadPointer`` if a compression pointer did not
|
||||
point backwards in the message.
|
||||
|
||||
Raises ``dns.name.BadLabelType`` if an invalid label type was encountered.
|
||||
|
||||
Returns a ``dns.name.Name``
|
||||
"""
|
||||
|
||||
labels = []
|
||||
biggest_pointer = parser.current
|
||||
with parser.restore_furthest():
|
||||
count = parser.get_uint8()
|
||||
while count != 0:
|
||||
if count < 64:
|
||||
labels.append(parser.get_bytes(count))
|
||||
elif count >= 192:
|
||||
current = (count & 0x3f) * 256 + parser.get_uint8()
|
||||
if current >= biggest_pointer:
|
||||
raise BadPointer
|
||||
biggest_pointer = current
|
||||
parser.seek(current)
|
||||
else:
|
||||
raise BadLabelType
|
||||
count = parser.get_uint8()
|
||||
labels.append(b'')
|
||||
return Name(labels)
|
||||
|
||||
|
||||
def from_wire(message, current):
|
||||
"""Convert possibly compressed wire format into a Name.
|
||||
|
||||
*message* is a ``bytes`` containing an entire DNS message in DNS
|
||||
wire form.
|
||||
|
||||
*current*, an ``int``, is the offset of the beginning of the name
|
||||
from the start of the message
|
||||
|
||||
Raises ``dns.name.BadPointer`` if a compression pointer did not
|
||||
point backwards in the message.
|
||||
|
||||
Raises ``dns.name.BadLabelType`` if an invalid label type was encountered.
|
||||
|
||||
Returns a ``(dns.name.Name, int)`` tuple consisting of the name
|
||||
that was read and the number of bytes of the wire format message
|
||||
which were consumed reading it.
|
||||
"""
|
||||
|
||||
if not isinstance(message, bytes):
|
||||
raise ValueError("input to from_wire() must be a byte string")
|
||||
parser = dns.wire.Parser(message, current)
|
||||
name = from_wire_parser(parser)
|
||||
return (name, parser.current - current)
|
108
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/namedict.py
vendored
Normal file
108
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/namedict.py
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
# Copyright (C) 2016 Coresec Systems AB
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL
|
||||
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC
|
||||
# SYSTEMS AB BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS name dictionary"""
|
||||
|
||||
from collections.abc import MutableMapping
|
||||
|
||||
import dns.name
|
||||
|
||||
|
||||
class NameDict(MutableMapping):
|
||||
"""A dictionary whose keys are dns.name.Name objects.
|
||||
|
||||
In addition to being like a regular Python dictionary, this
|
||||
dictionary can also get the deepest match for a given key.
|
||||
"""
|
||||
|
||||
__slots__ = ["max_depth", "max_depth_items", "__store"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__()
|
||||
self.__store = dict()
|
||||
#: the maximum depth of the keys that have ever been added
|
||||
self.max_depth = 0
|
||||
#: the number of items of maximum depth
|
||||
self.max_depth_items = 0
|
||||
self.update(dict(*args, **kwargs))
|
||||
|
||||
def __update_max_depth(self, key):
|
||||
if len(key) == self.max_depth:
|
||||
self.max_depth_items = self.max_depth_items + 1
|
||||
elif len(key) > self.max_depth:
|
||||
self.max_depth = len(key)
|
||||
self.max_depth_items = 1
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__store[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if not isinstance(key, dns.name.Name):
|
||||
raise ValueError('NameDict key must be a name')
|
||||
self.__store[key] = value
|
||||
self.__update_max_depth(key)
|
||||
|
||||
def __delitem__(self, key):
|
||||
self.__store.pop(key)
|
||||
if len(key) == self.max_depth:
|
||||
self.max_depth_items = self.max_depth_items - 1
|
||||
if self.max_depth_items == 0:
|
||||
self.max_depth = 0
|
||||
for k in self.__store:
|
||||
self.__update_max_depth(k)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.__store)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__store)
|
||||
|
||||
def has_key(self, key):
|
||||
return key in self.__store
|
||||
|
||||
def get_deepest_match(self, name):
|
||||
"""Find the deepest match to *fname* in the dictionary.
|
||||
|
||||
The deepest match is the longest name in the dictionary which is
|
||||
a superdomain of *name*. Note that *superdomain* includes matching
|
||||
*name* itself.
|
||||
|
||||
*name*, a ``dns.name.Name``, the name to find.
|
||||
|
||||
Returns a ``(key, value)`` where *key* is the deepest
|
||||
``dns.name.Name``, and *value* is the value associated with *key*.
|
||||
"""
|
||||
|
||||
depth = len(name)
|
||||
if depth > self.max_depth:
|
||||
depth = self.max_depth
|
||||
for i in range(-depth, 0):
|
||||
n = dns.name.Name(name[i:])
|
||||
if n in self:
|
||||
return (n, self[n])
|
||||
v = self[dns.name.empty]
|
||||
return (dns.name.empty, v)
|
189
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/node.py
vendored
Normal file
189
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/node.py
vendored
Normal file
|
@ -0,0 +1,189 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS nodes. A node is a set of rdatasets."""
|
||||
|
||||
import io
|
||||
|
||||
import dns.rdataset
|
||||
import dns.rdatatype
|
||||
import dns.renderer
|
||||
|
||||
|
||||
class Node:
|
||||
|
||||
"""A Node is a set of rdatasets."""
|
||||
|
||||
__slots__ = ['rdatasets']
|
||||
|
||||
def __init__(self):
|
||||
# the set of rdatasets, represented as a list.
|
||||
self.rdatasets = []
|
||||
|
||||
def to_text(self, name, **kw):
|
||||
"""Convert a node to text format.
|
||||
|
||||
Each rdataset at the node is printed. Any keyword arguments
|
||||
to this method are passed on to the rdataset's to_text() method.
|
||||
|
||||
*name*, a ``dns.name.Name`` or ``str``, the owner name of the
|
||||
rdatasets.
|
||||
|
||||
Returns a ``str``.
|
||||
|
||||
"""
|
||||
|
||||
s = io.StringIO()
|
||||
for rds in self.rdatasets:
|
||||
if len(rds) > 0:
|
||||
s.write(rds.to_text(name, **kw))
|
||||
s.write('\n')
|
||||
return s.getvalue()[:-1]
|
||||
|
||||
def __repr__(self):
|
||||
return '<DNS node ' + str(id(self)) + '>'
|
||||
|
||||
def __eq__(self, other):
|
||||
#
|
||||
# This is inefficient. Good thing we don't need to do it much.
|
||||
#
|
||||
for rd in self.rdatasets:
|
||||
if rd not in other.rdatasets:
|
||||
return False
|
||||
for rd in other.rdatasets:
|
||||
if rd not in self.rdatasets:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.rdatasets)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.rdatasets)
|
||||
|
||||
def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
|
||||
create=False):
|
||||
"""Find an rdataset matching the specified properties in the
|
||||
current node.
|
||||
|
||||
*rdclass*, an ``int``, the class of the rdataset.
|
||||
|
||||
*rdtype*, an ``int``, the type of the rdataset.
|
||||
|
||||
*covers*, an ``int`` or ``None``, the covered type.
|
||||
Usually this value is ``dns.rdatatype.NONE``, but if the
|
||||
rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
|
||||
then the covers value will be the rdata type the SIG/RRSIG
|
||||
covers. The library treats the SIG and RRSIG types as if they
|
||||
were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
|
||||
This makes RRSIGs much easier to work with than if RRSIGs
|
||||
covering different rdata types were aggregated into a single
|
||||
RRSIG rdataset.
|
||||
|
||||
*create*, a ``bool``. If True, create the rdataset if it is not found.
|
||||
|
||||
Raises ``KeyError`` if an rdataset of the desired type and class does
|
||||
not exist and *create* is not ``True``.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset``.
|
||||
"""
|
||||
|
||||
for rds in self.rdatasets:
|
||||
if rds.match(rdclass, rdtype, covers):
|
||||
return rds
|
||||
if not create:
|
||||
raise KeyError
|
||||
rds = dns.rdataset.Rdataset(rdclass, rdtype)
|
||||
self.rdatasets.append(rds)
|
||||
return rds
|
||||
|
||||
def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
|
||||
create=False):
|
||||
"""Get an rdataset matching the specified properties in the
|
||||
current node.
|
||||
|
||||
None is returned if an rdataset of the specified type and
|
||||
class does not exist and *create* is not ``True``.
|
||||
|
||||
*rdclass*, an ``int``, the class of the rdataset.
|
||||
|
||||
*rdtype*, an ``int``, the type of the rdataset.
|
||||
|
||||
*covers*, an ``int``, the covered type. Usually this value is
|
||||
dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
|
||||
dns.rdatatype.RRSIG, then the covers value will be the rdata
|
||||
type the SIG/RRSIG covers. The library treats the SIG and RRSIG
|
||||
types as if they were a family of
|
||||
types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much
|
||||
easier to work with than if RRSIGs covering different rdata
|
||||
types were aggregated into a single RRSIG rdataset.
|
||||
|
||||
*create*, a ``bool``. If True, create the rdataset if it is not found.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset`` or ``None``.
|
||||
"""
|
||||
|
||||
try:
|
||||
rds = self.find_rdataset(rdclass, rdtype, covers, create)
|
||||
except KeyError:
|
||||
rds = None
|
||||
return rds
|
||||
|
||||
def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
|
||||
"""Delete the rdataset matching the specified properties in the
|
||||
current node.
|
||||
|
||||
If a matching rdataset does not exist, it is not an error.
|
||||
|
||||
*rdclass*, an ``int``, the class of the rdataset.
|
||||
|
||||
*rdtype*, an ``int``, the type of the rdataset.
|
||||
|
||||
*covers*, an ``int``, the covered type.
|
||||
"""
|
||||
|
||||
rds = self.get_rdataset(rdclass, rdtype, covers)
|
||||
if rds is not None:
|
||||
self.rdatasets.remove(rds)
|
||||
|
||||
def replace_rdataset(self, replacement):
|
||||
"""Replace an rdataset.
|
||||
|
||||
It is not an error if there is no rdataset matching *replacement*.
|
||||
|
||||
Ownership of the *replacement* object is transferred to the node;
|
||||
in other words, this method does not store a copy of *replacement*
|
||||
at the node, it stores *replacement* itself.
|
||||
|
||||
*replacement*, a ``dns.rdataset.Rdataset``.
|
||||
|
||||
Raises ``ValueError`` if *replacement* is not a
|
||||
``dns.rdataset.Rdataset``.
|
||||
"""
|
||||
|
||||
if not isinstance(replacement, dns.rdataset.Rdataset):
|
||||
raise ValueError('replacement is not an rdataset')
|
||||
if isinstance(replacement, dns.rrset.RRset):
|
||||
# RRsets are not good replacements as the match() method
|
||||
# is not compatible.
|
||||
replacement = replacement.to_rdataset()
|
||||
self.delete_rdataset(replacement.rdclass, replacement.rdtype,
|
||||
replacement.covers)
|
||||
self.rdatasets.append(replacement)
|
115
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/opcode.py
vendored
Normal file
115
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/opcode.py
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Opcodes."""
|
||||
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
|
||||
class Opcode(dns.enum.IntEnum):
|
||||
#: Query
|
||||
QUERY = 0
|
||||
#: Inverse Query (historical)
|
||||
IQUERY = 1
|
||||
#: Server Status (unspecified and unimplemented anywhere)
|
||||
STATUS = 2
|
||||
#: Notify
|
||||
NOTIFY = 4
|
||||
#: Dynamic Update
|
||||
UPDATE = 5
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 15
|
||||
|
||||
@classmethod
|
||||
def _unknown_exception_class(cls):
|
||||
return UnknownOpcode
|
||||
|
||||
|
||||
class UnknownOpcode(dns.exception.DNSException):
|
||||
"""An DNS opcode is unknown."""
|
||||
|
||||
|
||||
def from_text(text):
|
||||
"""Convert text into an opcode.
|
||||
|
||||
*text*, a ``str``, the textual opcode
|
||||
|
||||
Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return Opcode.from_text(text)
|
||||
|
||||
|
||||
def from_flags(flags):
|
||||
"""Extract an opcode from DNS message flags.
|
||||
|
||||
*flags*, an ``int``, the DNS flags.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return (flags & 0x7800) >> 11
|
||||
|
||||
|
||||
def to_flags(value):
|
||||
"""Convert an opcode to a value suitable for ORing into DNS message
|
||||
flags.
|
||||
|
||||
*value*, an ``int``, the DNS opcode value.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return (value << 11) & 0x7800
|
||||
|
||||
|
||||
def to_text(value):
|
||||
"""Convert an opcode to text.
|
||||
|
||||
*value*, an ``int`` the opcode value,
|
||||
|
||||
Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
return Opcode.to_text(value)
|
||||
|
||||
|
||||
def is_update(flags):
|
||||
"""Is the opcode in flags UPDATE?
|
||||
|
||||
*flags*, an ``int``, the DNS message flags.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
return from_flags(flags) == Opcode.UPDATE
|
||||
|
||||
### BEGIN generated Opcode constants
|
||||
|
||||
QUERY = Opcode.QUERY
|
||||
IQUERY = Opcode.IQUERY
|
||||
STATUS = Opcode.STATUS
|
||||
NOTIFY = Opcode.NOTIFY
|
||||
UPDATE = Opcode.UPDATE
|
||||
|
||||
### END generated Opcode constants
|
0
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/py.typed
vendored
Normal file
0
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/py.typed
vendored
Normal file
1094
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/query.py
vendored
Normal file
1094
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/query.py
vendored
Normal file
|
@ -0,0 +1,1094 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""Talk to a DNS server."""
|
||||
|
||||
import contextlib
|
||||
import enum
|
||||
import errno
|
||||
import os
|
||||
import selectors
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
import base64
|
||||
import urllib.parse
|
||||
|
||||
import dns.exception
|
||||
import dns.inet
|
||||
import dns.name
|
||||
import dns.message
|
||||
import dns.rcode
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.serial
|
||||
import dns.xfr
|
||||
|
||||
try:
|
||||
import requests
|
||||
from requests_toolbelt.adapters.source import SourceAddressAdapter
|
||||
from requests_toolbelt.adapters.host_header_ssl import HostHeaderSSLAdapter
|
||||
have_doh = True
|
||||
except ImportError: # pragma: no cover
|
||||
have_doh = False
|
||||
|
||||
try:
|
||||
import ssl
|
||||
except ImportError: # pragma: no cover
|
||||
class ssl: # type: ignore
|
||||
|
||||
class WantReadException(Exception):
|
||||
pass
|
||||
|
||||
class WantWriteException(Exception):
|
||||
pass
|
||||
|
||||
class SSLSocket:
|
||||
pass
|
||||
|
||||
def create_default_context(self, *args, **kwargs):
|
||||
raise Exception('no ssl support')
|
||||
|
||||
# Function used to create a socket. Can be overridden if needed in special
|
||||
# situations.
|
||||
socket_factory = socket.socket
|
||||
|
||||
class UnexpectedSource(dns.exception.DNSException):
|
||||
"""A DNS query response came from an unexpected address or port."""
|
||||
|
||||
|
||||
class BadResponse(dns.exception.FormError):
|
||||
"""A DNS query response does not respond to the question asked."""
|
||||
|
||||
|
||||
class NoDOH(dns.exception.DNSException):
|
||||
"""DNS over HTTPS (DOH) was requested but the requests module is not
|
||||
available."""
|
||||
|
||||
|
||||
# for backwards compatibility
|
||||
TransferError = dns.xfr.TransferError
|
||||
|
||||
|
||||
def _compute_times(timeout):
|
||||
now = time.time()
|
||||
if timeout is None:
|
||||
return (now, None)
|
||||
else:
|
||||
return (now, now + timeout)
|
||||
|
||||
|
||||
def _wait_for(fd, readable, writable, _, expiration):
|
||||
# Use the selected selector class to wait for any of the specified
|
||||
# events. An "expiration" absolute time is converted into a relative
|
||||
# timeout.
|
||||
#
|
||||
# The unused parameter is 'error', which is always set when
|
||||
# selecting for read or write, and we have no error-only selects.
|
||||
|
||||
if readable and isinstance(fd, ssl.SSLSocket) and fd.pending() > 0:
|
||||
return True
|
||||
sel = _selector_class()
|
||||
events = 0
|
||||
if readable:
|
||||
events |= selectors.EVENT_READ
|
||||
if writable:
|
||||
events |= selectors.EVENT_WRITE
|
||||
if events:
|
||||
sel.register(fd, events)
|
||||
if expiration is None:
|
||||
timeout = None
|
||||
else:
|
||||
timeout = expiration - time.time()
|
||||
if timeout <= 0.0:
|
||||
raise dns.exception.Timeout
|
||||
if not sel.select(timeout):
|
||||
raise dns.exception.Timeout
|
||||
|
||||
|
||||
def _set_selector_class(selector_class):
|
||||
# Internal API. Do not use.
|
||||
|
||||
global _selector_class
|
||||
|
||||
_selector_class = selector_class
|
||||
|
||||
if hasattr(selectors, 'PollSelector'):
|
||||
# Prefer poll() on platforms that support it because it has no
|
||||
# limits on the maximum value of a file descriptor (plus it will
|
||||
# be more efficient for high values).
|
||||
_selector_class = selectors.PollSelector
|
||||
else:
|
||||
_selector_class = selectors.SelectSelector # pragma: no cover
|
||||
|
||||
|
||||
def _wait_for_readable(s, expiration):
|
||||
_wait_for(s, True, False, True, expiration)
|
||||
|
||||
|
||||
def _wait_for_writable(s, expiration):
|
||||
_wait_for(s, False, True, True, expiration)
|
||||
|
||||
|
||||
def _addresses_equal(af, a1, a2):
|
||||
# Convert the first value of the tuple, which is a textual format
|
||||
# address into binary form, so that we are not confused by different
|
||||
# textual representations of the same address
|
||||
try:
|
||||
n1 = dns.inet.inet_pton(af, a1[0])
|
||||
n2 = dns.inet.inet_pton(af, a2[0])
|
||||
except dns.exception.SyntaxError:
|
||||
return False
|
||||
return n1 == n2 and a1[1:] == a2[1:]
|
||||
|
||||
|
||||
def _matches_destination(af, from_address, destination, ignore_unexpected):
|
||||
# Check that from_address is appropriate for a response to a query
|
||||
# sent to destination.
|
||||
if not destination:
|
||||
return True
|
||||
if _addresses_equal(af, from_address, destination) or \
|
||||
(dns.inet.is_multicast(destination[0]) and
|
||||
from_address[1:] == destination[1:]):
|
||||
return True
|
||||
elif ignore_unexpected:
|
||||
return False
|
||||
raise UnexpectedSource(f'got a response from {from_address} instead of '
|
||||
f'{destination}')
|
||||
|
||||
|
||||
def _destination_and_source(where, port, source, source_port,
|
||||
where_must_be_address=True):
|
||||
# Apply defaults and compute destination and source tuples
|
||||
# suitable for use in connect(), sendto(), or bind().
|
||||
af = None
|
||||
destination = None
|
||||
try:
|
||||
af = dns.inet.af_for_address(where)
|
||||
destination = where
|
||||
except Exception:
|
||||
if where_must_be_address:
|
||||
raise
|
||||
# URLs are ok so eat the exception
|
||||
if source:
|
||||
saf = dns.inet.af_for_address(source)
|
||||
if af:
|
||||
# We know the destination af, so source had better agree!
|
||||
if saf != af:
|
||||
raise ValueError('different address families for source ' +
|
||||
'and destination')
|
||||
else:
|
||||
# We didn't know the destination af, but we know the source,
|
||||
# so that's our af.
|
||||
af = saf
|
||||
if source_port and not source:
|
||||
# Caller has specified a source_port but not an address, so we
|
||||
# need to return a source, and we need to use the appropriate
|
||||
# wildcard address as the address.
|
||||
if af == socket.AF_INET:
|
||||
source = '0.0.0.0'
|
||||
elif af == socket.AF_INET6:
|
||||
source = '::'
|
||||
else:
|
||||
raise ValueError('source_port specified but address family is '
|
||||
'unknown')
|
||||
# Convert high-level (address, port) tuples into low-level address
|
||||
# tuples.
|
||||
if destination:
|
||||
destination = dns.inet.low_level_address_tuple((destination, port), af)
|
||||
if source:
|
||||
source = dns.inet.low_level_address_tuple((source, source_port), af)
|
||||
return (af, destination, source)
|
||||
|
||||
def _make_socket(af, type, source, ssl_context=None, server_hostname=None):
|
||||
s = socket_factory(af, type)
|
||||
try:
|
||||
s.setblocking(False)
|
||||
if source is not None:
|
||||
s.bind(source)
|
||||
if ssl_context:
|
||||
return ssl_context.wrap_socket(s, do_handshake_on_connect=False,
|
||||
server_hostname=server_hostname)
|
||||
else:
|
||||
return s
|
||||
except Exception:
|
||||
s.close()
|
||||
raise
|
||||
|
||||
def https(q, where, timeout=None, port=443, source=None, source_port=0,
|
||||
one_rr_per_rrset=False, ignore_trailing=False,
|
||||
session=None, path='/dns-query', post=True,
|
||||
bootstrap_address=None, verify=True):
|
||||
"""Return the response obtained after sending a query via DNS-over-HTTPS.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send.
|
||||
|
||||
*where*, a ``str``, the nameserver IP address or the full URL. If an IP
|
||||
address is given, the URL will be constructed using the following schema:
|
||||
https://<IP-address>:<port>/<path>.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to
|
||||
wait before the query times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, a ``int``, the port to send the query to. The default is 443.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*session*, a ``requests.session.Session``. If provided, the session to use
|
||||
to send the queries.
|
||||
|
||||
*path*, a ``str``. If *where* is an IP address, then *path* will be used to
|
||||
construct the URL to send the DNS query to.
|
||||
|
||||
*post*, a ``bool``. If ``True``, the default, POST method will be used.
|
||||
|
||||
*bootstrap_address*, a ``str``, the IP address to use to bypass the
|
||||
system's DNS resolver.
|
||||
|
||||
*verify*, a ``str``, containing a path to a certificate file or directory.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
|
||||
if not have_doh:
|
||||
raise NoDOH # pragma: no cover
|
||||
|
||||
wire = q.to_wire()
|
||||
(af, _, source) = _destination_and_source(where, port, source, source_port,
|
||||
False)
|
||||
transport_adapter = None
|
||||
headers = {
|
||||
"accept": "application/dns-message"
|
||||
}
|
||||
if af is not None:
|
||||
if af == socket.AF_INET:
|
||||
url = 'https://{}:{}{}'.format(where, port, path)
|
||||
elif af == socket.AF_INET6:
|
||||
url = 'https://[{}]:{}{}'.format(where, port, path)
|
||||
elif bootstrap_address is not None:
|
||||
split_url = urllib.parse.urlsplit(where)
|
||||
headers['Host'] = split_url.hostname
|
||||
url = where.replace(split_url.hostname, bootstrap_address)
|
||||
transport_adapter = HostHeaderSSLAdapter()
|
||||
else:
|
||||
url = where
|
||||
if source is not None:
|
||||
# set source port and source address
|
||||
transport_adapter = SourceAddressAdapter(source)
|
||||
|
||||
with contextlib.ExitStack() as stack:
|
||||
if not session:
|
||||
session = stack.enter_context(requests.sessions.Session())
|
||||
|
||||
if transport_adapter:
|
||||
session.mount(url, transport_adapter)
|
||||
|
||||
# see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH
|
||||
# GET and POST examples
|
||||
if post:
|
||||
headers.update({
|
||||
"content-type": "application/dns-message",
|
||||
"content-length": str(len(wire))
|
||||
})
|
||||
response = session.post(url, headers=headers, data=wire,
|
||||
timeout=timeout, verify=verify)
|
||||
else:
|
||||
wire = base64.urlsafe_b64encode(wire).rstrip(b"=")
|
||||
response = session.get(url, headers=headers,
|
||||
timeout=timeout, verify=verify,
|
||||
params={"dns": wire})
|
||||
|
||||
# see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH
|
||||
# status codes
|
||||
if response.status_code < 200 or response.status_code > 299:
|
||||
raise ValueError('{} responded with status code {}'
|
||||
'\nResponse body: {}'.format(where,
|
||||
response.status_code,
|
||||
response.content))
|
||||
r = dns.message.from_wire(response.content,
|
||||
keyring=q.keyring,
|
||||
request_mac=q.request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing)
|
||||
r.time = response.elapsed
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
|
||||
def _udp_recv(sock, max_size, expiration):
|
||||
"""Reads a datagram from the socket.
|
||||
A Timeout exception will be raised if the operation is not completed
|
||||
by the expiration time.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
return sock.recvfrom(max_size)
|
||||
except BlockingIOError:
|
||||
_wait_for_readable(sock, expiration)
|
||||
|
||||
|
||||
def _udp_send(sock, data, destination, expiration):
|
||||
"""Sends the specified datagram to destination over the socket.
|
||||
A Timeout exception will be raised if the operation is not completed
|
||||
by the expiration time.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
if destination:
|
||||
return sock.sendto(data, destination)
|
||||
else:
|
||||
return sock.send(data)
|
||||
except BlockingIOError: # pragma: no cover
|
||||
_wait_for_writable(sock, expiration)
|
||||
|
||||
|
||||
def send_udp(sock, what, destination, expiration=None):
|
||||
"""Send a DNS message to the specified UDP socket.
|
||||
|
||||
*sock*, a ``socket``.
|
||||
|
||||
*what*, a ``bytes`` or ``dns.message.Message``, the message to send.
|
||||
|
||||
*destination*, a destination tuple appropriate for the address family
|
||||
of the socket, specifying where to send the query.
|
||||
|
||||
*expiration*, a ``float`` or ``None``, the absolute time at which
|
||||
a timeout exception should be raised. If ``None``, no timeout will
|
||||
occur.
|
||||
|
||||
Returns an ``(int, float)`` tuple of bytes sent and the sent time.
|
||||
"""
|
||||
|
||||
if isinstance(what, dns.message.Message):
|
||||
what = what.to_wire()
|
||||
sent_time = time.time()
|
||||
n = _udp_send(sock, what, destination, expiration)
|
||||
return (n, sent_time)
|
||||
|
||||
|
||||
def receive_udp(sock, destination=None, expiration=None,
|
||||
ignore_unexpected=False, one_rr_per_rrset=False,
|
||||
keyring=None, request_mac=b'', ignore_trailing=False,
|
||||
raise_on_truncation=False):
|
||||
"""Read a DNS message from a UDP socket.
|
||||
|
||||
*sock*, a ``socket``.
|
||||
|
||||
*destination*, a destination tuple appropriate for the address family
|
||||
of the socket, specifying where the message is expected to arrive from.
|
||||
When receiving a response, this would be where the associated query was
|
||||
sent.
|
||||
|
||||
*expiration*, a ``float`` or ``None``, the absolute time at which
|
||||
a timeout exception should be raised. If ``None``, no timeout will
|
||||
occur.
|
||||
|
||||
*ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
|
||||
unexpected sources.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*keyring*, a ``dict``, the keyring to use for TSIG.
|
||||
|
||||
*request_mac*, a ``bytes``, the MAC of the request (for TSIG).
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*raise_on_truncation*, a ``bool``. If ``True``, raise an exception if
|
||||
the TC bit is set.
|
||||
|
||||
Raises if the message is malformed, if network errors occur, of if
|
||||
there is a timeout.
|
||||
|
||||
If *destination* is not ``None``, returns a ``(dns.message.Message, float)``
|
||||
tuple of the received message and the received time.
|
||||
|
||||
If *destination* is ``None``, returns a
|
||||
``(dns.message.Message, float, tuple)``
|
||||
tuple of the received message, the received time, and the address where
|
||||
the message arrived from.
|
||||
"""
|
||||
|
||||
wire = b''
|
||||
while True:
|
||||
(wire, from_address) = _udp_recv(sock, 65535, expiration)
|
||||
if _matches_destination(sock.family, from_address, destination,
|
||||
ignore_unexpected):
|
||||
break
|
||||
received_time = time.time()
|
||||
r = dns.message.from_wire(wire, keyring=keyring, request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing,
|
||||
raise_on_truncation=raise_on_truncation)
|
||||
if destination:
|
||||
return (r, received_time)
|
||||
else:
|
||||
return (r, received_time, from_address)
|
||||
|
||||
def udp(q, where, timeout=None, port=53, source=None, source_port=0,
|
||||
ignore_unexpected=False, one_rr_per_rrset=False, ignore_trailing=False,
|
||||
raise_on_truncation=False, sock=None):
|
||||
"""Return the response obtained after sending a query via UDP.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the
|
||||
query times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
|
||||
unexpected sources.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*raise_on_truncation*, a ``bool``. If ``True``, raise an exception if
|
||||
the TC bit is set.
|
||||
|
||||
*sock*, a ``socket.socket``, or ``None``, the socket to use for the
|
||||
query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking datagram socket,
|
||||
and the *source* and *source_port* are ignored.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
|
||||
wire = q.to_wire()
|
||||
(af, destination, source) = _destination_and_source(where, port,
|
||||
source, source_port)
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
with contextlib.ExitStack() as stack:
|
||||
if sock:
|
||||
s = sock
|
||||
else:
|
||||
s = stack.enter_context(_make_socket(af, socket.SOCK_DGRAM, source))
|
||||
send_udp(s, wire, destination, expiration)
|
||||
(r, received_time) = receive_udp(s, destination, expiration,
|
||||
ignore_unexpected, one_rr_per_rrset,
|
||||
q.keyring, q.mac, ignore_trailing,
|
||||
raise_on_truncation)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
|
||||
def udp_with_fallback(q, where, timeout=None, port=53, source=None,
|
||||
source_port=0, ignore_unexpected=False,
|
||||
one_rr_per_rrset=False, ignore_trailing=False,
|
||||
udp_sock=None, tcp_sock=None):
|
||||
"""Return the response to the query, trying UDP first and falling back
|
||||
to TCP if UDP results in a truncated response.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the
|
||||
query times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
|
||||
unexpected sources.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the
|
||||
UDP query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking datagram socket,
|
||||
and the *source* and *source_port* are ignored for the UDP query.
|
||||
|
||||
*tcp_sock*, a ``socket.socket``, or ``None``, the socket to use for the
|
||||
TCP query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking connected stream
|
||||
socket, and *where*, *source* and *source_port* are ignored for the TCP
|
||||
query.
|
||||
|
||||
Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True``
|
||||
if and only if TCP was used.
|
||||
"""
|
||||
try:
|
||||
response = udp(q, where, timeout, port, source, source_port,
|
||||
ignore_unexpected, one_rr_per_rrset,
|
||||
ignore_trailing, True, udp_sock)
|
||||
return (response, False)
|
||||
except dns.message.Truncated:
|
||||
response = tcp(q, where, timeout, port, source, source_port,
|
||||
one_rr_per_rrset, ignore_trailing, tcp_sock)
|
||||
return (response, True)
|
||||
|
||||
def _net_read(sock, count, expiration):
|
||||
"""Read the specified number of bytes from sock. Keep trying until we
|
||||
either get the desired amount, or we hit EOF.
|
||||
A Timeout exception will be raised if the operation is not completed
|
||||
by the expiration time.
|
||||
"""
|
||||
s = b''
|
||||
while count > 0:
|
||||
try:
|
||||
n = sock.recv(count)
|
||||
if n == b'':
|
||||
raise EOFError
|
||||
count -= len(n)
|
||||
s += n
|
||||
except (BlockingIOError, ssl.SSLWantReadError):
|
||||
_wait_for_readable(sock, expiration)
|
||||
except ssl.SSLWantWriteError: # pragma: no cover
|
||||
_wait_for_writable(sock, expiration)
|
||||
return s
|
||||
|
||||
|
||||
def _net_write(sock, data, expiration):
|
||||
"""Write the specified data to the socket.
|
||||
A Timeout exception will be raised if the operation is not completed
|
||||
by the expiration time.
|
||||
"""
|
||||
current = 0
|
||||
l = len(data)
|
||||
while current < l:
|
||||
try:
|
||||
current += sock.send(data[current:])
|
||||
except (BlockingIOError, ssl.SSLWantWriteError):
|
||||
_wait_for_writable(sock, expiration)
|
||||
except ssl.SSLWantReadError: # pragma: no cover
|
||||
_wait_for_readable(sock, expiration)
|
||||
|
||||
|
||||
def send_tcp(sock, what, expiration=None):
|
||||
"""Send a DNS message to the specified TCP socket.
|
||||
|
||||
*sock*, a ``socket``.
|
||||
|
||||
*what*, a ``bytes`` or ``dns.message.Message``, the message to send.
|
||||
|
||||
*expiration*, a ``float`` or ``None``, the absolute time at which
|
||||
a timeout exception should be raised. If ``None``, no timeout will
|
||||
occur.
|
||||
|
||||
Returns an ``(int, float)`` tuple of bytes sent and the sent time.
|
||||
"""
|
||||
|
||||
if isinstance(what, dns.message.Message):
|
||||
what = what.to_wire()
|
||||
l = len(what)
|
||||
# copying the wire into tcpmsg is inefficient, but lets us
|
||||
# avoid writev() or doing a short write that would get pushed
|
||||
# onto the net
|
||||
tcpmsg = struct.pack("!H", l) + what
|
||||
sent_time = time.time()
|
||||
_net_write(sock, tcpmsg, expiration)
|
||||
return (len(tcpmsg), sent_time)
|
||||
|
||||
def receive_tcp(sock, expiration=None, one_rr_per_rrset=False,
|
||||
keyring=None, request_mac=b'', ignore_trailing=False):
|
||||
"""Read a DNS message from a TCP socket.
|
||||
|
||||
*sock*, a ``socket``.
|
||||
|
||||
*expiration*, a ``float`` or ``None``, the absolute time at which
|
||||
a timeout exception should be raised. If ``None``, no timeout will
|
||||
occur.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*keyring*, a ``dict``, the keyring to use for TSIG.
|
||||
|
||||
*request_mac*, a ``bytes``, the MAC of the request (for TSIG).
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
Raises if the message is malformed, if network errors occur, of if
|
||||
there is a timeout.
|
||||
|
||||
Returns a ``(dns.message.Message, float)`` tuple of the received message
|
||||
and the received time.
|
||||
"""
|
||||
|
||||
ldata = _net_read(sock, 2, expiration)
|
||||
(l,) = struct.unpack("!H", ldata)
|
||||
wire = _net_read(sock, l, expiration)
|
||||
received_time = time.time()
|
||||
r = dns.message.from_wire(wire, keyring=keyring, request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing)
|
||||
return (r, received_time)
|
||||
|
||||
def _connect(s, address, expiration):
|
||||
err = s.connect_ex(address)
|
||||
if err == 0:
|
||||
return
|
||||
if err in (errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY):
|
||||
_wait_for_writable(s, expiration)
|
||||
err = s.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
||||
if err != 0:
|
||||
raise OSError(err, os.strerror(err))
|
||||
|
||||
|
||||
def tcp(q, where, timeout=None, port=53, source=None, source_port=0,
|
||||
one_rr_per_rrset=False, ignore_trailing=False, sock=None):
|
||||
"""Return the response obtained after sending a query via TCP.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the
|
||||
query times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*sock*, a ``socket.socket``, or ``None``, the socket to use for the
|
||||
query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking connected stream
|
||||
socket, and *where*, *port*, *source* and *source_port* are ignored.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
|
||||
wire = q.to_wire()
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
with contextlib.ExitStack() as stack:
|
||||
if sock:
|
||||
s = sock
|
||||
else:
|
||||
(af, destination, source) = _destination_and_source(where, port,
|
||||
source,
|
||||
source_port)
|
||||
s = stack.enter_context(_make_socket(af, socket.SOCK_STREAM,
|
||||
source))
|
||||
_connect(s, destination, expiration)
|
||||
send_tcp(s, wire, expiration)
|
||||
(r, received_time) = receive_tcp(s, expiration, one_rr_per_rrset,
|
||||
q.keyring, q.mac, ignore_trailing)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
|
||||
|
||||
def _tls_handshake(s, expiration):
|
||||
while True:
|
||||
try:
|
||||
s.do_handshake()
|
||||
return
|
||||
except ssl.SSLWantReadError:
|
||||
_wait_for_readable(s, expiration)
|
||||
except ssl.SSLWantWriteError: # pragma: no cover
|
||||
_wait_for_writable(s, expiration)
|
||||
|
||||
|
||||
def tls(q, where, timeout=None, port=853, source=None, source_port=0,
|
||||
one_rr_per_rrset=False, ignore_trailing=False, sock=None,
|
||||
ssl_context=None, server_hostname=None):
|
||||
"""Return the response obtained after sending a query via TLS.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the
|
||||
query times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 853.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
|
||||
*sock*, an ``ssl.SSLSocket``, or ``None``, the socket to use for
|
||||
the query. If ``None``, the default, a socket is created. Note
|
||||
that if a socket is provided, it must be a nonblocking connected
|
||||
SSL stream socket, and *where*, *port*, *source*, *source_port*,
|
||||
and *ssl_context* are ignored.
|
||||
|
||||
*ssl_context*, an ``ssl.SSLContext``, the context to use when establishing
|
||||
a TLS connection. If ``None``, the default, creates one with the default
|
||||
configuration.
|
||||
|
||||
*server_hostname*, a ``str`` containing the server's hostname. The
|
||||
default is ``None``, which means that no hostname is known, and if an
|
||||
SSL context is created, hostname checking will be disabled.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
|
||||
"""
|
||||
|
||||
if sock:
|
||||
#
|
||||
# If a socket was provided, there's no special TLS handling needed.
|
||||
#
|
||||
return tcp(q, where, timeout, port, source, source_port,
|
||||
one_rr_per_rrset, ignore_trailing, sock)
|
||||
|
||||
wire = q.to_wire()
|
||||
(begin_time, expiration) = _compute_times(timeout)
|
||||
(af, destination, source) = _destination_and_source(where, port,
|
||||
source, source_port)
|
||||
if ssl_context is None and not sock:
|
||||
ssl_context = ssl.create_default_context()
|
||||
if server_hostname is None:
|
||||
ssl_context.check_hostname = False
|
||||
|
||||
with _make_socket(af, socket.SOCK_STREAM, source, ssl_context=ssl_context,
|
||||
server_hostname=server_hostname) as s:
|
||||
_connect(s, destination, expiration)
|
||||
_tls_handshake(s, expiration)
|
||||
send_tcp(s, wire, expiration)
|
||||
(r, received_time) = receive_tcp(s, expiration, one_rr_per_rrset,
|
||||
q.keyring, q.mac, ignore_trailing)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
raise BadResponse
|
||||
return r
|
||||
|
||||
|
||||
def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
|
||||
timeout=None, port=53, keyring=None, keyname=None, relativize=True,
|
||||
lifetime=None, source=None, source_port=0, serial=0,
|
||||
use_udp=False, keyalgorithm=dns.tsig.default_algorithm):
|
||||
"""Return a generator for the responses to a zone transfer.
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*zone*, a ``dns.name.Name`` or ``str``, the name of the zone to transfer.
|
||||
|
||||
*rdtype*, an ``int`` or ``str``, the type of zone transfer. The
|
||||
default is ``dns.rdatatype.AXFR``. ``dns.rdatatype.IXFR`` can be
|
||||
used to do an incremental transfer instead.
|
||||
|
||||
*rdclass*, an ``int`` or ``str``, the class of the zone transfer.
|
||||
The default is ``dns.rdataclass.IN``.
|
||||
|
||||
*timeout*, a ``float``, the number of seconds to wait for each
|
||||
response message. If None, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*keyring*, a ``dict``, the keyring to use for TSIG.
|
||||
|
||||
*keyname*, a ``dns.name.Name`` or ``str``, the name of the TSIG
|
||||
key to use.
|
||||
|
||||
*relativize*, a ``bool``. If ``True``, all names in the zone will be
|
||||
relativized to the zone origin. It is essential that the
|
||||
relativize setting matches the one specified to
|
||||
``dns.zone.from_xfr()`` if using this generator to make a zone.
|
||||
|
||||
*lifetime*, a ``float``, the total number of seconds to spend
|
||||
doing the transfer. If ``None``, the default, then there is no
|
||||
limit on the time the transfer may take.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*serial*, an ``int``, the SOA serial number to use as the base for
|
||||
an IXFR diff sequence (only meaningful if *rdtype* is
|
||||
``dns.rdatatype.IXFR``).
|
||||
|
||||
*use_udp*, a ``bool``. If ``True``, use UDP (only meaningful for IXFR).
|
||||
|
||||
*keyalgorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use.
|
||||
|
||||
Raises on errors, and so does the generator.
|
||||
|
||||
Returns a generator of ``dns.message.Message`` objects.
|
||||
"""
|
||||
|
||||
if isinstance(zone, str):
|
||||
zone = dns.name.from_text(zone)
|
||||
rdtype = dns.rdatatype.RdataType.make(rdtype)
|
||||
q = dns.message.make_query(zone, rdtype, rdclass)
|
||||
if rdtype == dns.rdatatype.IXFR:
|
||||
rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA',
|
||||
'. . %u 0 0 0 0' % serial)
|
||||
q.authority.append(rrset)
|
||||
if keyring is not None:
|
||||
q.use_tsig(keyring, keyname, algorithm=keyalgorithm)
|
||||
wire = q.to_wire()
|
||||
(af, destination, source) = _destination_and_source(where, port,
|
||||
source, source_port)
|
||||
if use_udp and rdtype != dns.rdatatype.IXFR:
|
||||
raise ValueError('cannot do a UDP AXFR')
|
||||
sock_type = socket.SOCK_DGRAM if use_udp else socket.SOCK_STREAM
|
||||
with _make_socket(af, sock_type, source) as s:
|
||||
(_, expiration) = _compute_times(lifetime)
|
||||
_connect(s, destination, expiration)
|
||||
l = len(wire)
|
||||
if use_udp:
|
||||
_udp_send(s, wire, None, expiration)
|
||||
else:
|
||||
tcpmsg = struct.pack("!H", l) + wire
|
||||
_net_write(s, tcpmsg, expiration)
|
||||
done = False
|
||||
delete_mode = True
|
||||
expecting_SOA = False
|
||||
soa_rrset = None
|
||||
if relativize:
|
||||
origin = zone
|
||||
oname = dns.name.empty
|
||||
else:
|
||||
origin = None
|
||||
oname = zone
|
||||
tsig_ctx = None
|
||||
while not done:
|
||||
(_, mexpiration) = _compute_times(timeout)
|
||||
if mexpiration is None or \
|
||||
(expiration is not None and mexpiration > expiration):
|
||||
mexpiration = expiration
|
||||
if use_udp:
|
||||
(wire, _) = _udp_recv(s, 65535, mexpiration)
|
||||
else:
|
||||
ldata = _net_read(s, 2, mexpiration)
|
||||
(l,) = struct.unpack("!H", ldata)
|
||||
wire = _net_read(s, l, mexpiration)
|
||||
is_ixfr = (rdtype == dns.rdatatype.IXFR)
|
||||
r = dns.message.from_wire(wire, keyring=q.keyring,
|
||||
request_mac=q.mac, xfr=True,
|
||||
origin=origin, tsig_ctx=tsig_ctx,
|
||||
multi=True, one_rr_per_rrset=is_ixfr)
|
||||
rcode = r.rcode()
|
||||
if rcode != dns.rcode.NOERROR:
|
||||
raise TransferError(rcode)
|
||||
tsig_ctx = r.tsig_ctx
|
||||
answer_index = 0
|
||||
if soa_rrset is None:
|
||||
if not r.answer or r.answer[0].name != oname:
|
||||
raise dns.exception.FormError(
|
||||
"No answer or RRset not for qname")
|
||||
rrset = r.answer[0]
|
||||
if rrset.rdtype != dns.rdatatype.SOA:
|
||||
raise dns.exception.FormError("first RRset is not an SOA")
|
||||
answer_index = 1
|
||||
soa_rrset = rrset.copy()
|
||||
if rdtype == dns.rdatatype.IXFR:
|
||||
if dns.serial.Serial(soa_rrset[0].serial) <= serial:
|
||||
#
|
||||
# We're already up-to-date.
|
||||
#
|
||||
done = True
|
||||
else:
|
||||
expecting_SOA = True
|
||||
#
|
||||
# Process SOAs in the answer section (other than the initial
|
||||
# SOA in the first message).
|
||||
#
|
||||
for rrset in r.answer[answer_index:]:
|
||||
if done:
|
||||
raise dns.exception.FormError("answers after final SOA")
|
||||
if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname:
|
||||
if expecting_SOA:
|
||||
if rrset[0].serial != serial:
|
||||
raise dns.exception.FormError(
|
||||
"IXFR base serial mismatch")
|
||||
expecting_SOA = False
|
||||
elif rdtype == dns.rdatatype.IXFR:
|
||||
delete_mode = not delete_mode
|
||||
#
|
||||
# If this SOA RRset is equal to the first we saw then we're
|
||||
# finished. If this is an IXFR we also check that we're
|
||||
# seeing the record in the expected part of the response.
|
||||
#
|
||||
if rrset == soa_rrset and \
|
||||
(rdtype == dns.rdatatype.AXFR or
|
||||
(rdtype == dns.rdatatype.IXFR and delete_mode)):
|
||||
done = True
|
||||
elif expecting_SOA:
|
||||
#
|
||||
# We made an IXFR request and are expecting another
|
||||
# SOA RR, but saw something else, so this must be an
|
||||
# AXFR response.
|
||||
#
|
||||
rdtype = dns.rdatatype.AXFR
|
||||
expecting_SOA = False
|
||||
if done and q.keyring and not r.had_tsig:
|
||||
raise dns.exception.FormError("missing TSIG")
|
||||
yield r
|
||||
|
||||
|
||||
class UDPMode(enum.IntEnum):
|
||||
"""How should UDP be used in an IXFR from :py:func:`inbound_xfr()`?
|
||||
|
||||
NEVER means "never use UDP; always use TCP"
|
||||
TRY_FIRST means "try to use UDP but fall back to TCP if needed"
|
||||
ONLY means "raise ``dns.xfr.UseTCP`` if trying UDP does not succeed"
|
||||
"""
|
||||
NEVER = 0
|
||||
TRY_FIRST = 1
|
||||
ONLY = 2
|
||||
|
||||
|
||||
def inbound_xfr(where, txn_manager, query=None,
|
||||
port=53, timeout=None, lifetime=None, source=None,
|
||||
source_port=0, udp_mode=UDPMode.NEVER):
|
||||
"""Conduct an inbound transfer and apply it via a transaction from the
|
||||
txn_manager.
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
|
||||
*txn_manager*, a ``dns.transaction.TransactionManager``, the txn_manager
|
||||
for this transfer (typically a ``dns.zone.Zone``).
|
||||
|
||||
*query*, the query to send. If not supplied, a default query is
|
||||
constructed using information from the *txn_manager*.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*timeout*, a ``float``, the number of seconds to wait for each
|
||||
response message. If None, the default, wait forever.
|
||||
|
||||
*lifetime*, a ``float``, the total number of seconds to spend
|
||||
doing the transfer. If ``None``, the default, then there is no
|
||||
limit on the time the transfer may take.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
|
||||
*udp_mode*, a ``dns.query.UDPMode``, determines how UDP is used
|
||||
for IXFRs. The default is ``dns.UDPMode.NEVER``, i.e. only use
|
||||
TCP. Other possibilites are ``dns.UDPMode.TRY_FIRST``, which
|
||||
means "try UDP but fallback to TCP if needed", and
|
||||
``dns.UDPMode.ONLY``, which means "try UDP and raise
|
||||
``dns.xfr.UseTCP`` if it does not succeeed.
|
||||
|
||||
Raises on errors.
|
||||
"""
|
||||
if query is None:
|
||||
(query, serial) = dns.xfr.make_query(txn_manager)
|
||||
rdtype = query.question[0].rdtype
|
||||
is_ixfr = rdtype == dns.rdatatype.IXFR
|
||||
origin = txn_manager.from_wire_origin()
|
||||
wire = query.to_wire()
|
||||
(af, destination, source) = _destination_and_source(where, port,
|
||||
source, source_port)
|
||||
(_, expiration) = _compute_times(lifetime)
|
||||
retry = True
|
||||
while retry:
|
||||
retry = False
|
||||
if is_ixfr and udp_mode != UDPMode.NEVER:
|
||||
sock_type = socket.SOCK_DGRAM
|
||||
is_udp = True
|
||||
else:
|
||||
sock_type = socket.SOCK_STREAM
|
||||
is_udp = False
|
||||
with _make_socket(af, sock_type, source) as s:
|
||||
_connect(s, destination, expiration)
|
||||
if is_udp:
|
||||
_udp_send(s, wire, None, expiration)
|
||||
else:
|
||||
tcpmsg = struct.pack("!H", len(wire)) + wire
|
||||
_net_write(s, tcpmsg, expiration)
|
||||
with dns.xfr.Inbound(txn_manager, rdtype, serial,
|
||||
is_udp) as inbound:
|
||||
done = False
|
||||
tsig_ctx = None
|
||||
while not done:
|
||||
(_, mexpiration) = _compute_times(timeout)
|
||||
if mexpiration is None or \
|
||||
(expiration is not None and mexpiration > expiration):
|
||||
mexpiration = expiration
|
||||
if is_udp:
|
||||
(rwire, _) = _udp_recv(s, 65535, mexpiration)
|
||||
else:
|
||||
ldata = _net_read(s, 2, mexpiration)
|
||||
(l,) = struct.unpack("!H", ldata)
|
||||
rwire = _net_read(s, l, mexpiration)
|
||||
r = dns.message.from_wire(rwire, keyring=query.keyring,
|
||||
request_mac=query.mac, xfr=True,
|
||||
origin=origin, tsig_ctx=tsig_ctx,
|
||||
multi=(not is_udp),
|
||||
one_rr_per_rrset=is_ixfr)
|
||||
try:
|
||||
done = inbound.process_message(r)
|
||||
except dns.xfr.UseTCP:
|
||||
assert is_udp # should not happen if we used TCP!
|
||||
if udp_mode == UDPMode.ONLY:
|
||||
raise
|
||||
done = True
|
||||
retry = True
|
||||
udp_mode = UDPMode.NEVER
|
||||
continue
|
||||
tsig_ctx = r.tsig_ctx
|
||||
if not retry and query.keyring and not r.had_tsig:
|
||||
raise dns.exception.FormError("missing TSIG")
|
164
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rcode.py
vendored
Normal file
164
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rcode.py
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Result Codes."""
|
||||
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
|
||||
class Rcode(dns.enum.IntEnum):
|
||||
#: No error
|
||||
NOERROR = 0
|
||||
#: Format error
|
||||
FORMERR = 1
|
||||
#: Server failure
|
||||
SERVFAIL = 2
|
||||
#: Name does not exist ("Name Error" in RFC 1025 terminology).
|
||||
NXDOMAIN = 3
|
||||
#: Not implemented
|
||||
NOTIMP = 4
|
||||
#: Refused
|
||||
REFUSED = 5
|
||||
#: Name exists.
|
||||
YXDOMAIN = 6
|
||||
#: RRset exists.
|
||||
YXRRSET = 7
|
||||
#: RRset does not exist.
|
||||
NXRRSET = 8
|
||||
#: Not authoritative.
|
||||
NOTAUTH = 9
|
||||
#: Name not in zone.
|
||||
NOTZONE = 10
|
||||
#: DSO-TYPE Not Implemented
|
||||
DSOTYPENI = 11
|
||||
#: Bad EDNS version.
|
||||
BADVERS = 16
|
||||
#: TSIG Signature Failure
|
||||
BADSIG = 16
|
||||
#: Key not recognized.
|
||||
BADKEY = 17
|
||||
#: Signature out of time window.
|
||||
BADTIME = 18
|
||||
#: Bad TKEY Mode.
|
||||
BADMODE = 19
|
||||
#: Duplicate key name.
|
||||
BADNAME = 20
|
||||
#: Algorithm not supported.
|
||||
BADALG = 21
|
||||
#: Bad Truncation
|
||||
BADTRUNC = 22
|
||||
#: Bad/missing Server Cookie
|
||||
BADCOOKIE = 23
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 4095
|
||||
|
||||
@classmethod
|
||||
def _unknown_exception_class(cls):
|
||||
return UnknownRcode
|
||||
|
||||
|
||||
class UnknownRcode(dns.exception.DNSException):
|
||||
"""A DNS rcode is unknown."""
|
||||
|
||||
|
||||
def from_text(text):
|
||||
"""Convert text into an rcode.
|
||||
|
||||
*text*, a ``str``, the textual rcode or an integer in textual form.
|
||||
|
||||
Raises ``dns.rcode.UnknownRcode`` if the rcode mnemonic is unknown.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return Rcode.from_text(text)
|
||||
|
||||
|
||||
def from_flags(flags, ednsflags):
|
||||
"""Return the rcode value encoded by flags and ednsflags.
|
||||
|
||||
*flags*, an ``int``, the DNS flags field.
|
||||
|
||||
*ednsflags*, an ``int``, the EDNS flags field.
|
||||
|
||||
Raises ``ValueError`` if rcode is < 0 or > 4095
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0)
|
||||
return value
|
||||
|
||||
|
||||
def to_flags(value):
|
||||
"""Return a (flags, ednsflags) tuple which encodes the rcode.
|
||||
|
||||
*value*, an ``int``, the rcode.
|
||||
|
||||
Raises ``ValueError`` if rcode is < 0 or > 4095.
|
||||
|
||||
Returns an ``(int, int)`` tuple.
|
||||
"""
|
||||
|
||||
if value < 0 or value > 4095:
|
||||
raise ValueError('rcode must be >= 0 and <= 4095')
|
||||
v = value & 0xf
|
||||
ev = (value & 0xff0) << 20
|
||||
return (v, ev)
|
||||
|
||||
|
||||
def to_text(value, tsig=False):
|
||||
"""Convert rcode into text.
|
||||
|
||||
*value*, an ``int``, the rcode.
|
||||
|
||||
Raises ``ValueError`` if rcode is < 0 or > 4095.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
if tsig and value == Rcode.BADVERS:
|
||||
return 'BADSIG'
|
||||
return Rcode.to_text(value)
|
||||
|
||||
### BEGIN generated Rcode constants
|
||||
|
||||
NOERROR = Rcode.NOERROR
|
||||
FORMERR = Rcode.FORMERR
|
||||
SERVFAIL = Rcode.SERVFAIL
|
||||
NXDOMAIN = Rcode.NXDOMAIN
|
||||
NOTIMP = Rcode.NOTIMP
|
||||
REFUSED = Rcode.REFUSED
|
||||
YXDOMAIN = Rcode.YXDOMAIN
|
||||
YXRRSET = Rcode.YXRRSET
|
||||
NXRRSET = Rcode.NXRRSET
|
||||
NOTAUTH = Rcode.NOTAUTH
|
||||
NOTZONE = Rcode.NOTZONE
|
||||
DSOTYPENI = Rcode.DSOTYPENI
|
||||
BADVERS = Rcode.BADVERS
|
||||
BADSIG = Rcode.BADSIG
|
||||
BADKEY = Rcode.BADKEY
|
||||
BADTIME = Rcode.BADTIME
|
||||
BADMODE = Rcode.BADMODE
|
||||
BADNAME = Rcode.BADNAME
|
||||
BADALG = Rcode.BADALG
|
||||
BADTRUNC = Rcode.BADTRUNC
|
||||
BADCOOKIE = Rcode.BADCOOKIE
|
||||
|
||||
### END generated Rcode constants
|
719
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdata.py
vendored
Normal file
719
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdata.py
vendored
Normal file
|
@ -0,0 +1,719 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS rdata."""
|
||||
|
||||
from importlib import import_module
|
||||
import base64
|
||||
import binascii
|
||||
import io
|
||||
import inspect
|
||||
import itertools
|
||||
import random
|
||||
|
||||
import dns.wire
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.ipv4
|
||||
import dns.ipv6
|
||||
import dns.name
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.tokenizer
|
||||
import dns.ttl
|
||||
|
||||
_chunksize = 32
|
||||
|
||||
|
||||
def _wordbreak(data, chunksize=_chunksize):
|
||||
"""Break a binary string into chunks of chunksize characters separated by
|
||||
a space.
|
||||
"""
|
||||
|
||||
if not chunksize:
|
||||
return data.decode()
|
||||
return b' '.join([data[i:i + chunksize]
|
||||
for i
|
||||
in range(0, len(data), chunksize)]).decode()
|
||||
|
||||
|
||||
def _hexify(data, chunksize=_chunksize, **kw):
|
||||
"""Convert a binary string into its hex encoding, broken up into chunks
|
||||
of chunksize characters separated by a space.
|
||||
"""
|
||||
|
||||
return _wordbreak(binascii.hexlify(data), chunksize)
|
||||
|
||||
|
||||
def _base64ify(data, chunksize=_chunksize, **kw):
|
||||
"""Convert a binary string into its base64 encoding, broken up into chunks
|
||||
of chunksize characters separated by a space.
|
||||
"""
|
||||
|
||||
return _wordbreak(base64.b64encode(data), chunksize)
|
||||
|
||||
|
||||
__escaped = b'"\\'
|
||||
|
||||
def _escapify(qstring):
|
||||
"""Escape the characters in a quoted string which need it."""
|
||||
|
||||
if isinstance(qstring, str):
|
||||
qstring = qstring.encode()
|
||||
if not isinstance(qstring, bytearray):
|
||||
qstring = bytearray(qstring)
|
||||
|
||||
text = ''
|
||||
for c in qstring:
|
||||
if c in __escaped:
|
||||
text += '\\' + chr(c)
|
||||
elif c >= 0x20 and c < 0x7F:
|
||||
text += chr(c)
|
||||
else:
|
||||
text += '\\%03d' % c
|
||||
return text
|
||||
|
||||
|
||||
def _truncate_bitmap(what):
|
||||
"""Determine the index of greatest byte that isn't all zeros, and
|
||||
return the bitmap that contains all the bytes less than that index.
|
||||
"""
|
||||
|
||||
for i in range(len(what) - 1, -1, -1):
|
||||
if what[i] != 0:
|
||||
return what[0: i + 1]
|
||||
return what[0:1]
|
||||
|
||||
# So we don't have to edit all the rdata classes...
|
||||
_constify = dns.immutable.constify
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class Rdata:
|
||||
"""Base class for all DNS rdata types."""
|
||||
|
||||
__slots__ = ['rdclass', 'rdtype', 'rdcomment']
|
||||
|
||||
def __init__(self, rdclass, rdtype):
|
||||
"""Initialize an rdata.
|
||||
|
||||
*rdclass*, an ``int`` is the rdataclass of the Rdata.
|
||||
|
||||
*rdtype*, an ``int`` is the rdatatype of the Rdata.
|
||||
"""
|
||||
|
||||
self.rdclass = self._as_rdataclass(rdclass)
|
||||
self.rdtype = self._as_rdatatype(rdtype)
|
||||
self.rdcomment = None
|
||||
|
||||
def _get_all_slots(self):
|
||||
return itertools.chain.from_iterable(getattr(cls, '__slots__', [])
|
||||
for cls in self.__class__.__mro__)
|
||||
|
||||
def __getstate__(self):
|
||||
# We used to try to do a tuple of all slots here, but it
|
||||
# doesn't work as self._all_slots isn't available at
|
||||
# __setstate__() time. Before that we tried to store a tuple
|
||||
# of __slots__, but that didn't work as it didn't store the
|
||||
# slots defined by ancestors. This older way didn't fail
|
||||
# outright, but ended up with partially broken objects, e.g.
|
||||
# if you unpickled an A RR it wouldn't have rdclass and rdtype
|
||||
# attributes, and would compare badly.
|
||||
state = {}
|
||||
for slot in self._get_all_slots():
|
||||
state[slot] = getattr(self, slot)
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
for slot, val in state.items():
|
||||
object.__setattr__(self, slot, val)
|
||||
if not hasattr(self, 'rdcomment'):
|
||||
# Pickled rdata from 2.0.x might not have a rdcomment, so add
|
||||
# it if needed.
|
||||
object.__setattr__(self, 'rdcomment', None)
|
||||
|
||||
def covers(self):
|
||||
"""Return the type a Rdata covers.
|
||||
|
||||
DNS SIG/RRSIG rdatas apply to a specific type; this type is
|
||||
returned by the covers() function. If the rdata type is not
|
||||
SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when
|
||||
creating rdatasets, allowing the rdataset to contain only RRSIGs
|
||||
of a particular type, e.g. RRSIG(NS).
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return dns.rdatatype.NONE
|
||||
|
||||
def extended_rdatatype(self):
|
||||
"""Return a 32-bit type value, the least significant 16 bits of
|
||||
which are the ordinary DNS type, and the upper 16 bits of which are
|
||||
the "covered" type, if any.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return self.covers() << 16 | self.rdtype
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
"""Convert an rdata to text format.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
def to_wire(self, file=None, compress=None, origin=None,
|
||||
canonicalize=False):
|
||||
"""Convert an rdata to wire format.
|
||||
|
||||
Returns a ``bytes`` or ``None``.
|
||||
"""
|
||||
|
||||
if file:
|
||||
return self._to_wire(file, compress, origin, canonicalize)
|
||||
else:
|
||||
f = io.BytesIO()
|
||||
self._to_wire(f, compress, origin, canonicalize)
|
||||
return f.getvalue()
|
||||
|
||||
def to_generic(self, origin=None):
|
||||
"""Creates a dns.rdata.GenericRdata equivalent of this rdata.
|
||||
|
||||
Returns a ``dns.rdata.GenericRdata``.
|
||||
"""
|
||||
return dns.rdata.GenericRdata(self.rdclass, self.rdtype,
|
||||
self.to_wire(origin=origin))
|
||||
|
||||
def to_digestable(self, origin=None):
|
||||
"""Convert rdata to a format suitable for digesting in hashes. This
|
||||
is also the DNSSEC canonical form.
|
||||
|
||||
Returns a ``bytes``.
|
||||
"""
|
||||
|
||||
return self.to_wire(origin=origin, canonicalize=True)
|
||||
|
||||
def __repr__(self):
|
||||
covers = self.covers()
|
||||
if covers == dns.rdatatype.NONE:
|
||||
ctext = ''
|
||||
else:
|
||||
ctext = '(' + dns.rdatatype.to_text(covers) + ')'
|
||||
return '<DNS ' + dns.rdataclass.to_text(self.rdclass) + ' ' + \
|
||||
dns.rdatatype.to_text(self.rdtype) + ctext + ' rdata: ' + \
|
||||
str(self) + '>'
|
||||
|
||||
def __str__(self):
|
||||
return self.to_text()
|
||||
|
||||
def _cmp(self, other):
|
||||
"""Compare an rdata with another rdata of the same rdtype and
|
||||
rdclass.
|
||||
|
||||
Return < 0 if self < other in the DNSSEC ordering, 0 if self
|
||||
== other, and > 0 if self > other.
|
||||
|
||||
"""
|
||||
our = self.to_digestable(dns.name.root)
|
||||
their = other.to_digestable(dns.name.root)
|
||||
if our == their:
|
||||
return 0
|
||||
elif our > their:
|
||||
return 1
|
||||
else:
|
||||
return -1
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Rdata):
|
||||
return False
|
||||
if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
return False
|
||||
return self._cmp(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
if not isinstance(other, Rdata):
|
||||
return True
|
||||
if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
return True
|
||||
return self._cmp(other) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Rdata) or \
|
||||
self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
|
||||
return NotImplemented
|
||||
return self._cmp(other) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
if not isinstance(other, Rdata) or \
|
||||
self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) <= 0
|
||||
|
||||
def __ge__(self, other):
|
||||
if not isinstance(other, Rdata) or \
|
||||
self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) >= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
if not isinstance(other, Rdata) or \
|
||||
self.rdclass != other.rdclass or self.rdtype != other.rdtype:
|
||||
return NotImplemented
|
||||
return self._cmp(other) > 0
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.to_digestable(dns.name.root))
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
raise NotImplementedError # pragma: no cover
|
||||
|
||||
def replace(self, **kwargs):
|
||||
"""
|
||||
Create a new Rdata instance based on the instance replace was
|
||||
invoked on. It is possible to pass different parameters to
|
||||
override the corresponding properties of the base Rdata.
|
||||
|
||||
Any field specific to the Rdata type can be replaced, but the
|
||||
*rdtype* and *rdclass* fields cannot.
|
||||
|
||||
Returns an instance of the same Rdata subclass as *self*.
|
||||
"""
|
||||
|
||||
# Get the constructor parameters.
|
||||
parameters = inspect.signature(self.__init__).parameters
|
||||
|
||||
# Ensure that all of the arguments correspond to valid fields.
|
||||
# Don't allow rdclass or rdtype to be changed, though.
|
||||
for key in kwargs:
|
||||
if key == 'rdcomment':
|
||||
continue
|
||||
if key not in parameters:
|
||||
raise AttributeError("'{}' object has no attribute '{}'"
|
||||
.format(self.__class__.__name__, key))
|
||||
if key in ('rdclass', 'rdtype'):
|
||||
raise AttributeError("Cannot overwrite '{}' attribute '{}'"
|
||||
.format(self.__class__.__name__, key))
|
||||
|
||||
# Construct the parameter list. For each field, use the value in
|
||||
# kwargs if present, and the current value otherwise.
|
||||
args = (kwargs.get(key, getattr(self, key)) for key in parameters)
|
||||
|
||||
# Create, validate, and return the new object.
|
||||
rd = self.__class__(*args)
|
||||
# The comment is not set in the constructor, so give it special
|
||||
# handling.
|
||||
rdcomment = kwargs.get('rdcomment', self.rdcomment)
|
||||
if rdcomment is not None:
|
||||
object.__setattr__(rd, 'rdcomment', rdcomment)
|
||||
return rd
|
||||
|
||||
# Type checking and conversion helpers. These are class methods as
|
||||
# they don't touch object state and may be useful to others.
|
||||
|
||||
@classmethod
|
||||
def _as_rdataclass(cls, value):
|
||||
return dns.rdataclass.RdataClass.make(value)
|
||||
|
||||
@classmethod
|
||||
def _as_rdatatype(cls, value):
|
||||
return dns.rdatatype.RdataType.make(value)
|
||||
|
||||
@classmethod
|
||||
def _as_bytes(cls, value, encode=False, max_length=None, empty_ok=True):
|
||||
if encode and isinstance(value, str):
|
||||
value = value.encode()
|
||||
elif isinstance(value, bytearray):
|
||||
value = bytes(value)
|
||||
elif not isinstance(value, bytes):
|
||||
raise ValueError('not bytes')
|
||||
if max_length is not None and len(value) > max_length:
|
||||
raise ValueError('too long')
|
||||
if not empty_ok and len(value) == 0:
|
||||
raise ValueError('empty bytes not allowed')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_name(cls, value):
|
||||
# Note that proper name conversion (e.g. with origin and IDNA
|
||||
# awareness) is expected to be done via from_text. This is just
|
||||
# a simple thing for people invoking the constructor directly.
|
||||
if isinstance(value, str):
|
||||
return dns.name.from_text(value)
|
||||
elif not isinstance(value, dns.name.Name):
|
||||
raise ValueError('not a name')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_uint8(cls, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError('not an integer')
|
||||
if value < 0 or value > 255:
|
||||
raise ValueError('not a uint8')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_uint16(cls, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError('not an integer')
|
||||
if value < 0 or value > 65535:
|
||||
raise ValueError('not a uint16')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_uint32(cls, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError('not an integer')
|
||||
if value < 0 or value > 4294967295:
|
||||
raise ValueError('not a uint32')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_uint48(cls, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError('not an integer')
|
||||
if value < 0 or value > 281474976710655:
|
||||
raise ValueError('not a uint48')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_int(cls, value, low=None, high=None):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError('not an integer')
|
||||
if low is not None and value < low:
|
||||
raise ValueError('value too small')
|
||||
if high is not None and value > high:
|
||||
raise ValueError('value too large')
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _as_ipv4_address(cls, value):
|
||||
if isinstance(value, str):
|
||||
# call to check validity
|
||||
dns.ipv4.inet_aton(value)
|
||||
return value
|
||||
elif isinstance(value, bytes):
|
||||
return dns.ipv4.inet_ntoa(value)
|
||||
else:
|
||||
raise ValueError('not an IPv4 address')
|
||||
|
||||
@classmethod
|
||||
def _as_ipv6_address(cls, value):
|
||||
if isinstance(value, str):
|
||||
# call to check validity
|
||||
dns.ipv6.inet_aton(value)
|
||||
return value
|
||||
elif isinstance(value, bytes):
|
||||
return dns.ipv6.inet_ntoa(value)
|
||||
else:
|
||||
raise ValueError('not an IPv6 address')
|
||||
|
||||
@classmethod
|
||||
def _as_bool(cls, value):
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
else:
|
||||
raise ValueError('not a boolean')
|
||||
|
||||
@classmethod
|
||||
def _as_ttl(cls, value):
|
||||
if isinstance(value, int):
|
||||
return cls._as_int(value, 0, dns.ttl.MAX_TTL)
|
||||
elif isinstance(value, str):
|
||||
return dns.ttl.from_text(value)
|
||||
else:
|
||||
raise ValueError('not a TTL')
|
||||
|
||||
@classmethod
|
||||
def _as_tuple(cls, value, as_value):
|
||||
try:
|
||||
# For user convenience, if value is a singleton of the list
|
||||
# element type, wrap it in a tuple.
|
||||
return (as_value(value),)
|
||||
except Exception:
|
||||
# Otherwise, check each element of the iterable *value*
|
||||
# against *as_value*.
|
||||
return tuple(as_value(v) for v in value)
|
||||
|
||||
# Processing order
|
||||
|
||||
@classmethod
|
||||
def _processing_order(cls, iterable):
|
||||
items = list(iterable)
|
||||
random.shuffle(items)
|
||||
return items
|
||||
|
||||
|
||||
class GenericRdata(Rdata):
|
||||
|
||||
"""Generic Rdata Class
|
||||
|
||||
This class is used for rdata types for which we have no better
|
||||
implementation. It implements the DNS "unknown RRs" scheme.
|
||||
"""
|
||||
|
||||
__slots__ = ['data']
|
||||
|
||||
def __init__(self, rdclass, rdtype, data):
|
||||
super().__init__(rdclass, rdtype)
|
||||
object.__setattr__(self, 'data', data)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return r'\# %d ' % len(self.data) + _hexify(self.data, **kw)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
token = tok.get()
|
||||
if not token.is_identifier() or token.value != r'\#':
|
||||
raise dns.exception.SyntaxError(
|
||||
r'generic rdata does not start with \#')
|
||||
length = tok.get_int()
|
||||
hex = tok.concatenate_remaining_identifiers().encode()
|
||||
data = binascii.unhexlify(hex)
|
||||
if len(data) != length:
|
||||
raise dns.exception.SyntaxError(
|
||||
'generic rdata hex data has wrong length')
|
||||
return cls(rdclass, rdtype, data)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
file.write(self.data)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
return cls(rdclass, rdtype, parser.get_remaining())
|
||||
|
||||
_rdata_classes = {}
|
||||
_module_prefix = 'dns.rdtypes'
|
||||
|
||||
def get_rdata_class(rdclass, rdtype):
|
||||
cls = _rdata_classes.get((rdclass, rdtype))
|
||||
if not cls:
|
||||
cls = _rdata_classes.get((dns.rdatatype.ANY, rdtype))
|
||||
if not cls:
|
||||
rdclass_text = dns.rdataclass.to_text(rdclass)
|
||||
rdtype_text = dns.rdatatype.to_text(rdtype)
|
||||
rdtype_text = rdtype_text.replace('-', '_')
|
||||
try:
|
||||
mod = import_module('.'.join([_module_prefix,
|
||||
rdclass_text, rdtype_text]))
|
||||
cls = getattr(mod, rdtype_text)
|
||||
_rdata_classes[(rdclass, rdtype)] = cls
|
||||
except ImportError:
|
||||
try:
|
||||
mod = import_module('.'.join([_module_prefix,
|
||||
'ANY', rdtype_text]))
|
||||
cls = getattr(mod, rdtype_text)
|
||||
_rdata_classes[(dns.rdataclass.ANY, rdtype)] = cls
|
||||
_rdata_classes[(rdclass, rdtype)] = cls
|
||||
except ImportError:
|
||||
pass
|
||||
if not cls:
|
||||
cls = GenericRdata
|
||||
_rdata_classes[(rdclass, rdtype)] = cls
|
||||
return cls
|
||||
|
||||
|
||||
def from_text(rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None, idna_codec=None):
|
||||
"""Build an rdata object from text format.
|
||||
|
||||
This function attempts to dynamically load a class which
|
||||
implements the specified rdata class and type. If there is no
|
||||
class-and-type-specific implementation, the GenericRdata class
|
||||
is used.
|
||||
|
||||
Once a class is chosen, its from_text() class method is called
|
||||
with the parameters to this function.
|
||||
|
||||
If *tok* is a ``str``, then a tokenizer is created and the string
|
||||
is used as its input.
|
||||
|
||||
*rdclass*, an ``int``, the rdataclass.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype.
|
||||
|
||||
*tok*, a ``dns.tokenizer.Tokenizer`` or a ``str``.
|
||||
|
||||
*origin*, a ``dns.name.Name`` (or ``None``), the
|
||||
origin to use for relative names.
|
||||
|
||||
*relativize*, a ``bool``. If true, name will be relativized.
|
||||
|
||||
*relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
|
||||
when relativizing names. If not set, the *origin* value will be used.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder to use if a tokenizer needs to be created. If
|
||||
``None``, the default IDNA 2003 encoder/decoder is used. If a
|
||||
tokenizer is not created, then the codec associated with the tokenizer
|
||||
is the one that is used.
|
||||
|
||||
Returns an instance of the chosen Rdata subclass.
|
||||
|
||||
"""
|
||||
if isinstance(tok, str):
|
||||
tok = dns.tokenizer.Tokenizer(tok, idna_codec=idna_codec)
|
||||
rdclass = dns.rdataclass.RdataClass.make(rdclass)
|
||||
rdtype = dns.rdatatype.RdataType.make(rdtype)
|
||||
cls = get_rdata_class(rdclass, rdtype)
|
||||
with dns.exception.ExceptionWrapper(dns.exception.SyntaxError):
|
||||
rdata = None
|
||||
if cls != GenericRdata:
|
||||
# peek at first token
|
||||
token = tok.get()
|
||||
tok.unget(token)
|
||||
if token.is_identifier() and \
|
||||
token.value == r'\#':
|
||||
#
|
||||
# Known type using the generic syntax. Extract the
|
||||
# wire form from the generic syntax, and then run
|
||||
# from_wire on it.
|
||||
#
|
||||
grdata = GenericRdata.from_text(rdclass, rdtype, tok, origin,
|
||||
relativize, relativize_to)
|
||||
rdata = from_wire(rdclass, rdtype, grdata.data, 0,
|
||||
len(grdata.data), origin)
|
||||
#
|
||||
# If this comparison isn't equal, then there must have been
|
||||
# compressed names in the wire format, which is an error,
|
||||
# there being no reasonable context to decompress with.
|
||||
#
|
||||
rwire = rdata.to_wire()
|
||||
if rwire != grdata.data:
|
||||
raise dns.exception.SyntaxError('compressed data in '
|
||||
'generic syntax form '
|
||||
'of known rdatatype')
|
||||
if rdata is None:
|
||||
rdata = cls.from_text(rdclass, rdtype, tok, origin, relativize,
|
||||
relativize_to)
|
||||
token = tok.get_eol_as_token()
|
||||
if token.comment is not None:
|
||||
object.__setattr__(rdata, 'rdcomment', token.comment)
|
||||
return rdata
|
||||
|
||||
|
||||
def from_wire_parser(rdclass, rdtype, parser, origin=None):
|
||||
"""Build an rdata object from wire format
|
||||
|
||||
This function attempts to dynamically load a class which
|
||||
implements the specified rdata class and type. If there is no
|
||||
class-and-type-specific implementation, the GenericRdata class
|
||||
is used.
|
||||
|
||||
Once a class is chosen, its from_wire() class method is called
|
||||
with the parameters to this function.
|
||||
|
||||
*rdclass*, an ``int``, the rdataclass.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype.
|
||||
|
||||
*parser*, a ``dns.wire.Parser``, the parser, which should be
|
||||
restricted to the rdata length.
|
||||
|
||||
*origin*, a ``dns.name.Name`` (or ``None``). If not ``None``,
|
||||
then names will be relativized to this origin.
|
||||
|
||||
Returns an instance of the chosen Rdata subclass.
|
||||
"""
|
||||
|
||||
rdclass = dns.rdataclass.RdataClass.make(rdclass)
|
||||
rdtype = dns.rdatatype.RdataType.make(rdtype)
|
||||
cls = get_rdata_class(rdclass, rdtype)
|
||||
with dns.exception.ExceptionWrapper(dns.exception.FormError):
|
||||
return cls.from_wire_parser(rdclass, rdtype, parser, origin)
|
||||
|
||||
|
||||
def from_wire(rdclass, rdtype, wire, current, rdlen, origin=None):
|
||||
"""Build an rdata object from wire format
|
||||
|
||||
This function attempts to dynamically load a class which
|
||||
implements the specified rdata class and type. If there is no
|
||||
class-and-type-specific implementation, the GenericRdata class
|
||||
is used.
|
||||
|
||||
Once a class is chosen, its from_wire() class method is called
|
||||
with the parameters to this function.
|
||||
|
||||
*rdclass*, an ``int``, the rdataclass.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype.
|
||||
|
||||
*wire*, a ``bytes``, the wire-format message.
|
||||
|
||||
*current*, an ``int``, the offset in wire of the beginning of
|
||||
the rdata.
|
||||
|
||||
*rdlen*, an ``int``, the length of the wire-format rdata
|
||||
|
||||
*origin*, a ``dns.name.Name`` (or ``None``). If not ``None``,
|
||||
then names will be relativized to this origin.
|
||||
|
||||
Returns an instance of the chosen Rdata subclass.
|
||||
"""
|
||||
parser = dns.wire.Parser(wire, current)
|
||||
with parser.restrict_to(rdlen):
|
||||
return from_wire_parser(rdclass, rdtype, parser, origin)
|
||||
|
||||
|
||||
class RdatatypeExists(dns.exception.DNSException):
|
||||
"""DNS rdatatype already exists."""
|
||||
supp_kwargs = {'rdclass', 'rdtype'}
|
||||
fmt = "The rdata type with class {rdclass} and rdtype {rdtype} " + \
|
||||
"already exists."
|
||||
|
||||
|
||||
def register_type(implementation, rdtype, rdtype_text, is_singleton=False,
|
||||
rdclass=dns.rdataclass.IN):
|
||||
"""Dynamically register a module to handle an rdatatype.
|
||||
|
||||
*implementation*, a module implementing the type in the usual dnspython
|
||||
way.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype to register.
|
||||
|
||||
*rdtype_text*, a ``str``, the textual form of the rdatatype.
|
||||
|
||||
*is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
|
||||
RRsets of the type can have only one member.)
|
||||
|
||||
*rdclass*, the rdataclass of the type, or ``dns.rdataclass.ANY`` if
|
||||
it applies to all classes.
|
||||
"""
|
||||
|
||||
existing_cls = get_rdata_class(rdclass, rdtype)
|
||||
if existing_cls != GenericRdata or dns.rdatatype.is_metatype(rdtype):
|
||||
raise RdatatypeExists(rdclass=rdclass, rdtype=rdtype)
|
||||
try:
|
||||
if dns.rdatatype.RdataType(rdtype).name != rdtype_text:
|
||||
raise RdatatypeExists(rdclass=rdclass, rdtype=rdtype)
|
||||
except ValueError:
|
||||
pass
|
||||
_rdata_classes[(rdclass, rdtype)] = getattr(implementation,
|
||||
rdtype_text.replace('-', '_'))
|
||||
dns.rdatatype.register_type(rdtype, rdtype_text, is_singleton)
|
115
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdataclass.py
vendored
Normal file
115
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdataclass.py
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Rdata Classes."""
|
||||
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
|
||||
class RdataClass(dns.enum.IntEnum):
|
||||
"""DNS Rdata Class"""
|
||||
RESERVED0 = 0
|
||||
IN = 1
|
||||
INTERNET = IN
|
||||
CH = 3
|
||||
CHAOS = CH
|
||||
HS = 4
|
||||
HESIOD = HS
|
||||
NONE = 254
|
||||
ANY = 255
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 65535
|
||||
|
||||
@classmethod
|
||||
def _short_name(cls):
|
||||
return "class"
|
||||
|
||||
@classmethod
|
||||
def _prefix(cls):
|
||||
return "CLASS"
|
||||
|
||||
@classmethod
|
||||
def _unknown_exception_class(cls):
|
||||
return UnknownRdataclass
|
||||
|
||||
|
||||
_metaclasses = {RdataClass.NONE, RdataClass.ANY}
|
||||
|
||||
|
||||
class UnknownRdataclass(dns.exception.DNSException):
|
||||
"""A DNS class is unknown."""
|
||||
|
||||
|
||||
def from_text(text):
|
||||
"""Convert text into a DNS rdata class value.
|
||||
|
||||
The input text can be a defined DNS RR class mnemonic or
|
||||
instance of the DNS generic class syntax.
|
||||
|
||||
For example, "IN" and "CLASS1" will both result in a value of 1.
|
||||
|
||||
Raises ``dns.rdatatype.UnknownRdataclass`` if the class is unknown.
|
||||
|
||||
Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
return RdataClass.from_text(text)
|
||||
|
||||
|
||||
def to_text(value):
|
||||
"""Convert a DNS rdata class value to text.
|
||||
|
||||
If the value has a known mnemonic, it will be used, otherwise the
|
||||
DNS generic class syntax will be used.
|
||||
|
||||
Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
return RdataClass.to_text(value)
|
||||
|
||||
|
||||
def is_metaclass(rdclass):
|
||||
"""True if the specified class is a metaclass.
|
||||
|
||||
The currently defined metaclasses are ANY and NONE.
|
||||
|
||||
*rdclass* is an ``int``.
|
||||
"""
|
||||
|
||||
if rdclass in _metaclasses:
|
||||
return True
|
||||
return False
|
||||
|
||||
### BEGIN generated RdataClass constants
|
||||
|
||||
RESERVED0 = RdataClass.RESERVED0
|
||||
IN = RdataClass.IN
|
||||
INTERNET = RdataClass.INTERNET
|
||||
CH = RdataClass.CH
|
||||
CHAOS = RdataClass.CHAOS
|
||||
HS = RdataClass.HS
|
||||
HESIOD = RdataClass.HESIOD
|
||||
NONE = RdataClass.NONE
|
||||
ANY = RdataClass.ANY
|
||||
|
||||
### END generated RdataClass constants
|
456
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdataset.py
vendored
Normal file
456
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdataset.py
vendored
Normal file
|
@ -0,0 +1,456 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)"""
|
||||
|
||||
import io
|
||||
import random
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdatatype
|
||||
import dns.rdataclass
|
||||
import dns.rdata
|
||||
import dns.set
|
||||
|
||||
# define SimpleSet here for backwards compatibility
|
||||
SimpleSet = dns.set.Set
|
||||
|
||||
|
||||
class DifferingCovers(dns.exception.DNSException):
|
||||
"""An attempt was made to add a DNS SIG/RRSIG whose covered type
|
||||
is not the same as that of the other rdatas in the rdataset."""
|
||||
|
||||
|
||||
class IncompatibleTypes(dns.exception.DNSException):
|
||||
"""An attempt was made to add DNS RR data of an incompatible type."""
|
||||
|
||||
|
||||
class Rdataset(dns.set.Set):
|
||||
|
||||
"""A DNS rdataset."""
|
||||
|
||||
__slots__ = ['rdclass', 'rdtype', 'covers', 'ttl']
|
||||
|
||||
def __init__(self, rdclass, rdtype, covers=dns.rdatatype.NONE, ttl=0):
|
||||
"""Create a new rdataset of the specified class and type.
|
||||
|
||||
*rdclass*, an ``int``, the rdataclass.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype.
|
||||
|
||||
*covers*, an ``int``, the covered rdatatype.
|
||||
|
||||
*ttl*, an ``int``, the TTL.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self.rdclass = rdclass
|
||||
self.rdtype = rdtype
|
||||
self.covers = covers
|
||||
self.ttl = ttl
|
||||
|
||||
def _clone(self):
|
||||
obj = super()._clone()
|
||||
obj.rdclass = self.rdclass
|
||||
obj.rdtype = self.rdtype
|
||||
obj.covers = self.covers
|
||||
obj.ttl = self.ttl
|
||||
return obj
|
||||
|
||||
def update_ttl(self, ttl):
|
||||
"""Perform TTL minimization.
|
||||
|
||||
Set the TTL of the rdataset to be the lesser of the set's current
|
||||
TTL or the specified TTL. If the set contains no rdatas, set the TTL
|
||||
to the specified TTL.
|
||||
|
||||
*ttl*, an ``int`` or ``str``.
|
||||
"""
|
||||
ttl = dns.ttl.make(ttl)
|
||||
if len(self) == 0:
|
||||
self.ttl = ttl
|
||||
elif ttl < self.ttl:
|
||||
self.ttl = ttl
|
||||
|
||||
def add(self, rd, ttl=None): # pylint: disable=arguments-differ
|
||||
"""Add the specified rdata to the rdataset.
|
||||
|
||||
If the optional *ttl* parameter is supplied, then
|
||||
``self.update_ttl(ttl)`` will be called prior to adding the rdata.
|
||||
|
||||
*rd*, a ``dns.rdata.Rdata``, the rdata
|
||||
|
||||
*ttl*, an ``int``, the TTL.
|
||||
|
||||
Raises ``dns.rdataset.IncompatibleTypes`` if the type and class
|
||||
do not match the type and class of the rdataset.
|
||||
|
||||
Raises ``dns.rdataset.DifferingCovers`` if the type is a signature
|
||||
type and the covered type does not match that of the rdataset.
|
||||
"""
|
||||
|
||||
#
|
||||
# If we're adding a signature, do some special handling to
|
||||
# check that the signature covers the same type as the
|
||||
# other rdatas in this rdataset. If this is the first rdata
|
||||
# in the set, initialize the covers field.
|
||||
#
|
||||
if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype:
|
||||
raise IncompatibleTypes
|
||||
if ttl is not None:
|
||||
self.update_ttl(ttl)
|
||||
if self.rdtype == dns.rdatatype.RRSIG or \
|
||||
self.rdtype == dns.rdatatype.SIG:
|
||||
covers = rd.covers()
|
||||
if len(self) == 0 and self.covers == dns.rdatatype.NONE:
|
||||
self.covers = covers
|
||||
elif self.covers != covers:
|
||||
raise DifferingCovers
|
||||
if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0:
|
||||
self.clear()
|
||||
super().add(rd)
|
||||
|
||||
def union_update(self, other):
|
||||
self.update_ttl(other.ttl)
|
||||
super().union_update(other)
|
||||
|
||||
def intersection_update(self, other):
|
||||
self.update_ttl(other.ttl)
|
||||
super().intersection_update(other)
|
||||
|
||||
def update(self, other):
|
||||
"""Add all rdatas in other to self.
|
||||
|
||||
*other*, a ``dns.rdataset.Rdataset``, the rdataset from which
|
||||
to update.
|
||||
"""
|
||||
|
||||
self.update_ttl(other.ttl)
|
||||
super().update(other)
|
||||
|
||||
def _rdata_repr(self):
|
||||
def maybe_truncate(s):
|
||||
if len(s) > 100:
|
||||
return s[:100] + '...'
|
||||
return s
|
||||
return '[%s]' % ', '.join('<%s>' % maybe_truncate(str(rr))
|
||||
for rr in self)
|
||||
|
||||
def __repr__(self):
|
||||
if self.covers == 0:
|
||||
ctext = ''
|
||||
else:
|
||||
ctext = '(' + dns.rdatatype.to_text(self.covers) + ')'
|
||||
return '<DNS ' + dns.rdataclass.to_text(self.rdclass) + ' ' + \
|
||||
dns.rdatatype.to_text(self.rdtype) + ctext + \
|
||||
' rdataset: ' + self._rdata_repr() + '>'
|
||||
|
||||
def __str__(self):
|
||||
return self.to_text()
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Rdataset):
|
||||
return False
|
||||
if self.rdclass != other.rdclass or \
|
||||
self.rdtype != other.rdtype or \
|
||||
self.covers != other.covers:
|
||||
return False
|
||||
return super().__eq__(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def to_text(self, name=None, origin=None, relativize=True,
|
||||
override_rdclass=None, want_comments=False, **kw):
|
||||
"""Convert the rdataset into DNS zone file format.
|
||||
|
||||
See ``dns.name.Name.choose_relativity`` for more information
|
||||
on how *origin* and *relativize* determine the way names
|
||||
are emitted.
|
||||
|
||||
Any additional keyword arguments are passed on to the rdata
|
||||
``to_text()`` method.
|
||||
|
||||
*name*, a ``dns.name.Name``. If name is not ``None``, emit RRs with
|
||||
*name* as the owner name.
|
||||
|
||||
*origin*, a ``dns.name.Name`` or ``None``, the origin for relative
|
||||
names.
|
||||
|
||||
*relativize*, a ``bool``. If ``True``, names will be relativized
|
||||
to *origin*.
|
||||
|
||||
*override_rdclass*, a ``dns.rdataclass.RdataClass`` or ``None``.
|
||||
If not ``None``, use this class instead of the Rdataset's class.
|
||||
|
||||
*want_comments*, a ``bool``. If ``True``, emit comments for rdata
|
||||
which have them. The default is ``False``.
|
||||
"""
|
||||
|
||||
if name is not None:
|
||||
name = name.choose_relativity(origin, relativize)
|
||||
ntext = str(name)
|
||||
pad = ' '
|
||||
else:
|
||||
ntext = ''
|
||||
pad = ''
|
||||
s = io.StringIO()
|
||||
if override_rdclass is not None:
|
||||
rdclass = override_rdclass
|
||||
else:
|
||||
rdclass = self.rdclass
|
||||
if len(self) == 0:
|
||||
#
|
||||
# Empty rdatasets are used for the question section, and in
|
||||
# some dynamic updates, so we don't need to print out the TTL
|
||||
# (which is meaningless anyway).
|
||||
#
|
||||
s.write('{}{}{} {}\n'.format(ntext, pad,
|
||||
dns.rdataclass.to_text(rdclass),
|
||||
dns.rdatatype.to_text(self.rdtype)))
|
||||
else:
|
||||
for rd in self:
|
||||
extra = ''
|
||||
if want_comments:
|
||||
if rd.rdcomment:
|
||||
extra = f' ;{rd.rdcomment}'
|
||||
s.write('%s%s%d %s %s %s%s\n' %
|
||||
(ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass),
|
||||
dns.rdatatype.to_text(self.rdtype),
|
||||
rd.to_text(origin=origin, relativize=relativize,
|
||||
**kw),
|
||||
extra))
|
||||
#
|
||||
# We strip off the final \n for the caller's convenience in printing
|
||||
#
|
||||
return s.getvalue()[:-1]
|
||||
|
||||
def to_wire(self, name, file, compress=None, origin=None,
|
||||
override_rdclass=None, want_shuffle=True):
|
||||
"""Convert the rdataset to wire format.
|
||||
|
||||
*name*, a ``dns.name.Name`` is the owner name to use.
|
||||
|
||||
*file* is the file where the name is emitted (typically a
|
||||
BytesIO file).
|
||||
|
||||
*compress*, a ``dict``, is the compression table to use. If
|
||||
``None`` (the default), names will not be compressed.
|
||||
|
||||
*origin* is a ``dns.name.Name`` or ``None``. If the name is
|
||||
relative and origin is not ``None``, then *origin* will be appended
|
||||
to it.
|
||||
|
||||
*override_rdclass*, an ``int``, is used as the class instead of the
|
||||
class of the rdataset. This is useful when rendering rdatasets
|
||||
associated with dynamic updates.
|
||||
|
||||
*want_shuffle*, a ``bool``. If ``True``, then the order of the
|
||||
Rdatas within the Rdataset will be shuffled before rendering.
|
||||
|
||||
Returns an ``int``, the number of records emitted.
|
||||
"""
|
||||
|
||||
if override_rdclass is not None:
|
||||
rdclass = override_rdclass
|
||||
want_shuffle = False
|
||||
else:
|
||||
rdclass = self.rdclass
|
||||
file.seek(0, io.SEEK_END)
|
||||
if len(self) == 0:
|
||||
name.to_wire(file, compress, origin)
|
||||
stuff = struct.pack("!HHIH", self.rdtype, rdclass, 0, 0)
|
||||
file.write(stuff)
|
||||
return 1
|
||||
else:
|
||||
if want_shuffle:
|
||||
l = list(self)
|
||||
random.shuffle(l)
|
||||
else:
|
||||
l = self
|
||||
for rd in l:
|
||||
name.to_wire(file, compress, origin)
|
||||
stuff = struct.pack("!HHIH", self.rdtype, rdclass,
|
||||
self.ttl, 0)
|
||||
file.write(stuff)
|
||||
start = file.tell()
|
||||
rd.to_wire(file, compress, origin)
|
||||
end = file.tell()
|
||||
assert end - start < 65536
|
||||
file.seek(start - 2)
|
||||
stuff = struct.pack("!H", end - start)
|
||||
file.write(stuff)
|
||||
file.seek(0, io.SEEK_END)
|
||||
return len(self)
|
||||
|
||||
def match(self, rdclass, rdtype, covers):
|
||||
"""Returns ``True`` if this rdataset matches the specified class,
|
||||
type, and covers.
|
||||
"""
|
||||
if self.rdclass == rdclass and \
|
||||
self.rdtype == rdtype and \
|
||||
self.covers == covers:
|
||||
return True
|
||||
return False
|
||||
|
||||
def processing_order(self):
|
||||
"""Return rdatas in a valid processing order according to the type's
|
||||
specification. For example, MX records are in preference order from
|
||||
lowest to highest preferences, with items of the same perference
|
||||
shuffled.
|
||||
|
||||
For types that do not define a processing order, the rdatas are
|
||||
simply shuffled.
|
||||
"""
|
||||
if len(self) == 0:
|
||||
return []
|
||||
else:
|
||||
return self[0]._processing_order(iter(self))
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class ImmutableRdataset(Rdataset):
|
||||
|
||||
"""An immutable DNS rdataset."""
|
||||
|
||||
_clone_class = Rdataset
|
||||
|
||||
def __init__(self, rdataset):
|
||||
"""Create an immutable rdataset from the specified rdataset."""
|
||||
|
||||
super().__init__(rdataset.rdclass, rdataset.rdtype, rdataset.covers,
|
||||
rdataset.ttl)
|
||||
self.items = dns.immutable.Dict(rdataset.items)
|
||||
|
||||
def update_ttl(self, ttl):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def add(self, rd, ttl=None):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def union_update(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def intersection_update(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def update(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __delitem__(self, i):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __ior__(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __iand__(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __iadd__(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __isub__(self, other):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def clear(self):
|
||||
raise TypeError('immutable')
|
||||
|
||||
def __copy__(self):
|
||||
return ImmutableRdataset(super().copy())
|
||||
|
||||
def copy(self):
|
||||
return ImmutableRdataset(super().copy())
|
||||
|
||||
def union(self, other):
|
||||
return ImmutableRdataset(super().union(other))
|
||||
|
||||
def intersection(self, other):
|
||||
return ImmutableRdataset(super().intersection(other))
|
||||
|
||||
def difference(self, other):
|
||||
return ImmutableRdataset(super().difference(other))
|
||||
|
||||
|
||||
def from_text_list(rdclass, rdtype, ttl, text_rdatas, idna_codec=None,
|
||||
origin=None, relativize=True, relativize_to=None):
|
||||
"""Create an rdataset with the specified class, type, and TTL, and with
|
||||
the specified list of rdatas in text format.
|
||||
|
||||
*idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
|
||||
encoder/decoder to use; if ``None``, the default IDNA 2003
|
||||
encoder/decoder is used.
|
||||
|
||||
*origin*, a ``dns.name.Name`` (or ``None``), the
|
||||
origin to use for relative names.
|
||||
|
||||
*relativize*, a ``bool``. If true, name will be relativized.
|
||||
|
||||
*relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
|
||||
when relativizing names. If not set, the *origin* value will be used.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset`` object.
|
||||
"""
|
||||
|
||||
rdclass = dns.rdataclass.RdataClass.make(rdclass)
|
||||
rdtype = dns.rdatatype.RdataType.make(rdtype)
|
||||
r = Rdataset(rdclass, rdtype)
|
||||
r.update_ttl(ttl)
|
||||
for t in text_rdatas:
|
||||
rd = dns.rdata.from_text(r.rdclass, r.rdtype, t, origin, relativize,
|
||||
relativize_to, idna_codec)
|
||||
r.add(rd)
|
||||
return r
|
||||
|
||||
|
||||
def from_text(rdclass, rdtype, ttl, *text_rdatas):
|
||||
"""Create an rdataset with the specified class, type, and TTL, and with
|
||||
the specified rdatas in text format.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset`` object.
|
||||
"""
|
||||
|
||||
return from_text_list(rdclass, rdtype, ttl, text_rdatas)
|
||||
|
||||
|
||||
def from_rdata_list(ttl, rdatas):
|
||||
"""Create an rdataset with the specified TTL, and with
|
||||
the specified list of rdata objects.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset`` object.
|
||||
"""
|
||||
|
||||
if len(rdatas) == 0:
|
||||
raise ValueError("rdata list must not be empty")
|
||||
r = None
|
||||
for rd in rdatas:
|
||||
if r is None:
|
||||
r = Rdataset(rd.rdclass, rd.rdtype)
|
||||
r.update_ttl(ttl)
|
||||
r.add(rd)
|
||||
return r
|
||||
|
||||
|
||||
def from_rdata(ttl, *rdatas):
|
||||
"""Create an rdataset with the specified TTL, and with
|
||||
the specified rdata objects.
|
||||
|
||||
Returns a ``dns.rdataset.Rdataset`` object.
|
||||
"""
|
||||
|
||||
return from_rdata_list(ttl, rdatas)
|
303
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdatatype.py
vendored
Normal file
303
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdatatype.py
vendored
Normal file
|
@ -0,0 +1,303 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""DNS Rdata Types."""
|
||||
|
||||
import dns.enum
|
||||
import dns.exception
|
||||
|
||||
class RdataType(dns.enum.IntEnum):
|
||||
"""DNS Rdata Type"""
|
||||
TYPE0 = 0
|
||||
NONE = 0
|
||||
A = 1
|
||||
NS = 2
|
||||
MD = 3
|
||||
MF = 4
|
||||
CNAME = 5
|
||||
SOA = 6
|
||||
MB = 7
|
||||
MG = 8
|
||||
MR = 9
|
||||
NULL = 10
|
||||
WKS = 11
|
||||
PTR = 12
|
||||
HINFO = 13
|
||||
MINFO = 14
|
||||
MX = 15
|
||||
TXT = 16
|
||||
RP = 17
|
||||
AFSDB = 18
|
||||
X25 = 19
|
||||
ISDN = 20
|
||||
RT = 21
|
||||
NSAP = 22
|
||||
NSAP_PTR = 23
|
||||
SIG = 24
|
||||
KEY = 25
|
||||
PX = 26
|
||||
GPOS = 27
|
||||
AAAA = 28
|
||||
LOC = 29
|
||||
NXT = 30
|
||||
SRV = 33
|
||||
NAPTR = 35
|
||||
KX = 36
|
||||
CERT = 37
|
||||
A6 = 38
|
||||
DNAME = 39
|
||||
OPT = 41
|
||||
APL = 42
|
||||
DS = 43
|
||||
SSHFP = 44
|
||||
IPSECKEY = 45
|
||||
RRSIG = 46
|
||||
NSEC = 47
|
||||
DNSKEY = 48
|
||||
DHCID = 49
|
||||
NSEC3 = 50
|
||||
NSEC3PARAM = 51
|
||||
TLSA = 52
|
||||
SMIMEA = 53
|
||||
HIP = 55
|
||||
NINFO = 56
|
||||
CDS = 59
|
||||
CDNSKEY = 60
|
||||
OPENPGPKEY = 61
|
||||
CSYNC = 62
|
||||
SVCB = 64
|
||||
HTTPS = 65
|
||||
SPF = 99
|
||||
UNSPEC = 103
|
||||
EUI48 = 108
|
||||
EUI64 = 109
|
||||
TKEY = 249
|
||||
TSIG = 250
|
||||
IXFR = 251
|
||||
AXFR = 252
|
||||
MAILB = 253
|
||||
MAILA = 254
|
||||
ANY = 255
|
||||
URI = 256
|
||||
CAA = 257
|
||||
AVC = 258
|
||||
AMTRELAY = 259
|
||||
TA = 32768
|
||||
DLV = 32769
|
||||
|
||||
@classmethod
|
||||
def _maximum(cls):
|
||||
return 65535
|
||||
|
||||
@classmethod
|
||||
def _short_name(cls):
|
||||
return "type"
|
||||
|
||||
@classmethod
|
||||
def _prefix(cls):
|
||||
return "TYPE"
|
||||
|
||||
@classmethod
|
||||
def _unknown_exception_class(cls):
|
||||
return UnknownRdatatype
|
||||
|
||||
_registered_by_text = {}
|
||||
_registered_by_value = {}
|
||||
|
||||
_metatypes = {RdataType.OPT}
|
||||
|
||||
_singletons = {RdataType.SOA, RdataType.NXT, RdataType.DNAME,
|
||||
RdataType.NSEC, RdataType.CNAME}
|
||||
|
||||
|
||||
class UnknownRdatatype(dns.exception.DNSException):
|
||||
"""DNS resource record type is unknown."""
|
||||
|
||||
|
||||
def from_text(text):
|
||||
"""Convert text into a DNS rdata type value.
|
||||
|
||||
The input text can be a defined DNS RR type mnemonic or
|
||||
instance of the DNS generic type syntax.
|
||||
|
||||
For example, "NS" and "TYPE2" will both result in a value of 2.
|
||||
|
||||
Raises ``dns.rdatatype.UnknownRdatatype`` if the type is unknown.
|
||||
|
||||
Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535.
|
||||
|
||||
Returns an ``int``.
|
||||
"""
|
||||
|
||||
text = text.upper().replace('-', '_')
|
||||
try:
|
||||
return RdataType.from_text(text)
|
||||
except UnknownRdatatype:
|
||||
registered_type = _registered_by_text.get(text)
|
||||
if registered_type:
|
||||
return registered_type
|
||||
raise
|
||||
|
||||
|
||||
def to_text(value):
|
||||
"""Convert a DNS rdata type value to text.
|
||||
|
||||
If the value has a known mnemonic, it will be used, otherwise the
|
||||
DNS generic type syntax will be used.
|
||||
|
||||
Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535.
|
||||
|
||||
Returns a ``str``.
|
||||
"""
|
||||
|
||||
text = RdataType.to_text(value)
|
||||
if text.startswith("TYPE"):
|
||||
registered_text = _registered_by_value.get(value)
|
||||
if registered_text:
|
||||
text = registered_text
|
||||
return text.replace('_', '-')
|
||||
|
||||
|
||||
def is_metatype(rdtype):
|
||||
"""True if the specified type is a metatype.
|
||||
|
||||
*rdtype* is an ``int``.
|
||||
|
||||
The currently defined metatypes are TKEY, TSIG, IXFR, AXFR, MAILA,
|
||||
MAILB, ANY, and OPT.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
return (256 > rdtype >= 128) or rdtype in _metatypes
|
||||
|
||||
|
||||
def is_singleton(rdtype):
|
||||
"""Is the specified type a singleton type?
|
||||
|
||||
Singleton types can only have a single rdata in an rdataset, or a single
|
||||
RR in an RRset.
|
||||
|
||||
The currently defined singleton types are CNAME, DNAME, NSEC, NXT, and
|
||||
SOA.
|
||||
|
||||
*rdtype* is an ``int``.
|
||||
|
||||
Returns a ``bool``.
|
||||
"""
|
||||
|
||||
if rdtype in _singletons:
|
||||
return True
|
||||
return False
|
||||
|
||||
# pylint: disable=redefined-outer-name
|
||||
def register_type(rdtype, rdtype_text, is_singleton=False):
|
||||
"""Dynamically register an rdatatype.
|
||||
|
||||
*rdtype*, an ``int``, the rdatatype to register.
|
||||
|
||||
*rdtype_text*, a ``str``, the textual form of the rdatatype.
|
||||
|
||||
*is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
|
||||
RRsets of the type can have only one member.)
|
||||
"""
|
||||
|
||||
_registered_by_text[rdtype_text] = rdtype
|
||||
_registered_by_value[rdtype] = rdtype_text
|
||||
if is_singleton:
|
||||
_singletons.add(rdtype)
|
||||
|
||||
### BEGIN generated RdataType constants
|
||||
|
||||
TYPE0 = RdataType.TYPE0
|
||||
NONE = RdataType.NONE
|
||||
A = RdataType.A
|
||||
NS = RdataType.NS
|
||||
MD = RdataType.MD
|
||||
MF = RdataType.MF
|
||||
CNAME = RdataType.CNAME
|
||||
SOA = RdataType.SOA
|
||||
MB = RdataType.MB
|
||||
MG = RdataType.MG
|
||||
MR = RdataType.MR
|
||||
NULL = RdataType.NULL
|
||||
WKS = RdataType.WKS
|
||||
PTR = RdataType.PTR
|
||||
HINFO = RdataType.HINFO
|
||||
MINFO = RdataType.MINFO
|
||||
MX = RdataType.MX
|
||||
TXT = RdataType.TXT
|
||||
RP = RdataType.RP
|
||||
AFSDB = RdataType.AFSDB
|
||||
X25 = RdataType.X25
|
||||
ISDN = RdataType.ISDN
|
||||
RT = RdataType.RT
|
||||
NSAP = RdataType.NSAP
|
||||
NSAP_PTR = RdataType.NSAP_PTR
|
||||
SIG = RdataType.SIG
|
||||
KEY = RdataType.KEY
|
||||
PX = RdataType.PX
|
||||
GPOS = RdataType.GPOS
|
||||
AAAA = RdataType.AAAA
|
||||
LOC = RdataType.LOC
|
||||
NXT = RdataType.NXT
|
||||
SRV = RdataType.SRV
|
||||
NAPTR = RdataType.NAPTR
|
||||
KX = RdataType.KX
|
||||
CERT = RdataType.CERT
|
||||
A6 = RdataType.A6
|
||||
DNAME = RdataType.DNAME
|
||||
OPT = RdataType.OPT
|
||||
APL = RdataType.APL
|
||||
DS = RdataType.DS
|
||||
SSHFP = RdataType.SSHFP
|
||||
IPSECKEY = RdataType.IPSECKEY
|
||||
RRSIG = RdataType.RRSIG
|
||||
NSEC = RdataType.NSEC
|
||||
DNSKEY = RdataType.DNSKEY
|
||||
DHCID = RdataType.DHCID
|
||||
NSEC3 = RdataType.NSEC3
|
||||
NSEC3PARAM = RdataType.NSEC3PARAM
|
||||
TLSA = RdataType.TLSA
|
||||
SMIMEA = RdataType.SMIMEA
|
||||
HIP = RdataType.HIP
|
||||
NINFO = RdataType.NINFO
|
||||
CDS = RdataType.CDS
|
||||
CDNSKEY = RdataType.CDNSKEY
|
||||
OPENPGPKEY = RdataType.OPENPGPKEY
|
||||
CSYNC = RdataType.CSYNC
|
||||
SVCB = RdataType.SVCB
|
||||
HTTPS = RdataType.HTTPS
|
||||
SPF = RdataType.SPF
|
||||
UNSPEC = RdataType.UNSPEC
|
||||
EUI48 = RdataType.EUI48
|
||||
EUI64 = RdataType.EUI64
|
||||
TKEY = RdataType.TKEY
|
||||
TSIG = RdataType.TSIG
|
||||
IXFR = RdataType.IXFR
|
||||
AXFR = RdataType.AXFR
|
||||
MAILB = RdataType.MAILB
|
||||
MAILA = RdataType.MAILA
|
||||
ANY = RdataType.ANY
|
||||
URI = RdataType.URI
|
||||
CAA = RdataType.CAA
|
||||
AVC = RdataType.AVC
|
||||
AMTRELAY = RdataType.AMTRELAY
|
||||
TA = RdataType.TA
|
||||
DLV = RdataType.DLV
|
||||
|
||||
### END generated RdataType constants
|
46
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AFSDB.py
vendored
Normal file
46
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AFSDB.py
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.mxbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX):
|
||||
|
||||
"""AFSDB record"""
|
||||
|
||||
# Use the property mechanism to make "subtype" an alias for the
|
||||
# "preference" attribute, and "hostname" an alias for the "exchange"
|
||||
# attribute.
|
||||
#
|
||||
# This lets us inherit the UncompressedMX implementation but lets
|
||||
# the caller use appropriate attribute names for the rdata type.
|
||||
#
|
||||
# We probably lose some performance vs. a cut-and-paste
|
||||
# implementation, but this way we don't copy code, and that's
|
||||
# good.
|
||||
|
||||
@property
|
||||
def subtype(self):
|
||||
"the AFSDB subtype"
|
||||
return self.preference
|
||||
|
||||
@property
|
||||
def hostname(self):
|
||||
"the AFSDB hostname"
|
||||
return self.exchange
|
86
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AMTRELAY.py
vendored
Normal file
86
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AMTRELAY.py
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdtypes.util
|
||||
|
||||
|
||||
class Relay(dns.rdtypes.util.Gateway):
|
||||
name = 'AMTRELAY relay'
|
||||
|
||||
@property
|
||||
def relay(self):
|
||||
return self.gateway
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class AMTRELAY(dns.rdata.Rdata):
|
||||
|
||||
"""AMTRELAY record"""
|
||||
|
||||
# see: RFC 8777
|
||||
|
||||
__slots__ = ['precedence', 'discovery_optional', 'relay_type', 'relay']
|
||||
|
||||
def __init__(self, rdclass, rdtype, precedence, discovery_optional,
|
||||
relay_type, relay):
|
||||
super().__init__(rdclass, rdtype)
|
||||
relay = Relay(relay_type, relay)
|
||||
self.precedence = self._as_uint8(precedence)
|
||||
self.discovery_optional = self._as_bool(discovery_optional)
|
||||
self.relay_type = relay.type
|
||||
self.relay = relay.relay
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
relay = Relay(self.relay_type, self.relay).to_text(origin, relativize)
|
||||
return '%d %d %d %s' % (self.precedence, self.discovery_optional,
|
||||
self.relay_type, relay)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
precedence = tok.get_uint8()
|
||||
discovery_optional = tok.get_uint8()
|
||||
if discovery_optional > 1:
|
||||
raise dns.exception.SyntaxError('expecting 0 or 1')
|
||||
discovery_optional = bool(discovery_optional)
|
||||
relay_type = tok.get_uint8()
|
||||
if relay_type > 0x7f:
|
||||
raise dns.exception.SyntaxError('expecting an integer <= 127')
|
||||
relay = Relay.from_text(relay_type, tok, origin, relativize,
|
||||
relativize_to)
|
||||
return cls(rdclass, rdtype, precedence, discovery_optional, relay_type,
|
||||
relay.relay)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
relay_type = self.relay_type | (self.discovery_optional << 7)
|
||||
header = struct.pack("!BB", self.precedence, relay_type)
|
||||
file.write(header)
|
||||
Relay(self.relay_type, self.relay).to_wire(file, compress, origin,
|
||||
canonicalize)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(precedence, relay_type) = parser.get_struct('!BB')
|
||||
discovery_optional = bool(relay_type >> 7)
|
||||
relay_type &= 0x7f
|
||||
relay = Relay.from_wire_parser(relay_type, parser, origin)
|
||||
return cls(rdclass, rdtype, precedence, discovery_optional, relay_type,
|
||||
relay.relay)
|
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AVC.py
vendored
Normal file
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/AVC.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2016 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.txtbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class AVC(dns.rdtypes.txtbase.TXTBase):
|
||||
|
||||
"""AVC record"""
|
||||
|
||||
# See: IANA dns parameters for AVC
|
69
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CAA.py
vendored
Normal file
69
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CAA.py
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CAA(dns.rdata.Rdata):
|
||||
|
||||
"""CAA (Certification Authority Authorization) record"""
|
||||
|
||||
# see: RFC 6844
|
||||
|
||||
__slots__ = ['flags', 'tag', 'value']
|
||||
|
||||
def __init__(self, rdclass, rdtype, flags, tag, value):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.flags = self._as_uint8(flags)
|
||||
self.tag = self._as_bytes(tag, True, 255)
|
||||
if not tag.isalnum():
|
||||
raise ValueError("tag is not alphanumeric")
|
||||
self.value = self._as_bytes(value)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return '%u %s "%s"' % (self.flags,
|
||||
dns.rdata._escapify(self.tag),
|
||||
dns.rdata._escapify(self.value))
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
flags = tok.get_uint8()
|
||||
tag = tok.get_string().encode()
|
||||
value = tok.get_string().encode()
|
||||
return cls(rdclass, rdtype, flags, tag, value)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
file.write(struct.pack('!B', self.flags))
|
||||
l = len(self.tag)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.tag)
|
||||
file.write(self.value)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
flags = parser.get_uint8()
|
||||
tag = parser.get_counted_bytes()
|
||||
value = parser.get_remaining()
|
||||
return cls(rdclass, rdtype, flags, tag, value)
|
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CDNSKEY.py
vendored
Normal file
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CDNSKEY.py
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.dnskeybase
|
||||
import dns.immutable
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from dns.rdtypes.dnskeybase import SEP, REVOKE, ZONE # noqa: F401
|
||||
# pylint: enable=unused-import
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CDNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase):
|
||||
|
||||
"""CDNSKEY record"""
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CDS.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CDS.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.dsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CDS(dns.rdtypes.dsbase.DSBase):
|
||||
|
||||
"""CDS record"""
|
103
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CERT.py
vendored
Normal file
103
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CERT.py
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
import base64
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.dnssec
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
_ctype_by_value = {
|
||||
1: 'PKIX',
|
||||
2: 'SPKI',
|
||||
3: 'PGP',
|
||||
253: 'URI',
|
||||
254: 'OID',
|
||||
}
|
||||
|
||||
_ctype_by_name = {
|
||||
'PKIX': 1,
|
||||
'SPKI': 2,
|
||||
'PGP': 3,
|
||||
'URI': 253,
|
||||
'OID': 254,
|
||||
}
|
||||
|
||||
|
||||
def _ctype_from_text(what):
|
||||
v = _ctype_by_name.get(what)
|
||||
if v is not None:
|
||||
return v
|
||||
return int(what)
|
||||
|
||||
|
||||
def _ctype_to_text(what):
|
||||
v = _ctype_by_value.get(what)
|
||||
if v is not None:
|
||||
return v
|
||||
return str(what)
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CERT(dns.rdata.Rdata):
|
||||
|
||||
"""CERT record"""
|
||||
|
||||
# see RFC 2538
|
||||
|
||||
__slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate']
|
||||
|
||||
def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm,
|
||||
certificate):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.certificate_type = self._as_uint16(certificate_type)
|
||||
self.key_tag = self._as_uint16(key_tag)
|
||||
self.algorithm = self._as_uint8(algorithm)
|
||||
self.certificate = self._as_bytes(certificate)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
certificate_type = _ctype_to_text(self.certificate_type)
|
||||
return "%s %d %s %s" % (certificate_type, self.key_tag,
|
||||
dns.dnssec.algorithm_to_text(self.algorithm),
|
||||
dns.rdata._base64ify(self.certificate, **kw))
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
certificate_type = _ctype_from_text(tok.get_string())
|
||||
key_tag = tok.get_uint16()
|
||||
algorithm = dns.dnssec.algorithm_from_text(tok.get_string())
|
||||
b64 = tok.concatenate_remaining_identifiers().encode()
|
||||
certificate = base64.b64decode(b64)
|
||||
return cls(rdclass, rdtype, certificate_type, key_tag,
|
||||
algorithm, certificate)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
prefix = struct.pack("!HHB", self.certificate_type, self.key_tag,
|
||||
self.algorithm)
|
||||
file.write(prefix)
|
||||
file.write(self.certificate)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(certificate_type, key_tag, algorithm) = parser.get_struct("!HHB")
|
||||
certificate = parser.get_remaining()
|
||||
return cls(rdclass, rdtype, certificate_type, key_tag, algorithm,
|
||||
certificate)
|
29
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CNAME.py
vendored
Normal file
29
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CNAME.py
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.nsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CNAME(dns.rdtypes.nsbase.NSBase):
|
||||
|
||||
"""CNAME record
|
||||
|
||||
Note: although CNAME is officially a singleton type, dnspython allows
|
||||
non-singleton CNAME rdatasets because such sets have been commonly
|
||||
used by BIND and other nameservers for load balancing."""
|
68
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CSYNC.py
vendored
Normal file
68
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/CSYNC.py
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011, 2016 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
import dns.name
|
||||
import dns.rdtypes.util
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class Bitmap(dns.rdtypes.util.Bitmap):
|
||||
type_name = 'CSYNC'
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class CSYNC(dns.rdata.Rdata):
|
||||
|
||||
"""CSYNC record"""
|
||||
|
||||
__slots__ = ['serial', 'flags', 'windows']
|
||||
|
||||
def __init__(self, rdclass, rdtype, serial, flags, windows):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.serial = self._as_uint32(serial)
|
||||
self.flags = self._as_uint16(flags)
|
||||
if not isinstance(windows, Bitmap):
|
||||
windows = Bitmap(windows)
|
||||
self.windows = tuple(windows.windows)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
text = Bitmap(self.windows).to_text()
|
||||
return '%d %d%s' % (self.serial, self.flags, text)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
serial = tok.get_uint32()
|
||||
flags = tok.get_uint16()
|
||||
bitmap = Bitmap.from_text(tok)
|
||||
return cls(rdclass, rdtype, serial, flags, bitmap)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
file.write(struct.pack('!IH', self.serial, self.flags))
|
||||
Bitmap(self.windows).to_wire(file)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(serial, flags) = parser.get_struct("!IH")
|
||||
bitmap = Bitmap.from_wire_parser(parser)
|
||||
return cls(rdclass, rdtype, serial, flags, bitmap)
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DLV.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DLV.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.dsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class DLV(dns.rdtypes.dsbase.DSBase):
|
||||
|
||||
"""DLV record"""
|
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DNAME.py
vendored
Normal file
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DNAME.py
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.nsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class DNAME(dns.rdtypes.nsbase.UncompressedNS):
|
||||
|
||||
"""DNAME record"""
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
self.target.to_wire(file, None, origin, canonicalize)
|
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DNSKEY.py
vendored
Normal file
28
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DNSKEY.py
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.dnskeybase
|
||||
import dns.immutable
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from dns.rdtypes.dnskeybase import SEP, REVOKE, ZONE # noqa: F401
|
||||
# pylint: enable=unused-import
|
||||
|
||||
@dns.immutable.immutable
|
||||
class DNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase):
|
||||
|
||||
"""DNSKEY record"""
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DS.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/DS.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.dsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class DS(dns.rdtypes.dsbase.DSBase):
|
||||
|
||||
"""DS record"""
|
31
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/EUI48.py
vendored
Normal file
31
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/EUI48.py
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
# Author: Petr Spacek <pspacek@redhat.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.euibase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class EUI48(dns.rdtypes.euibase.EUIBase):
|
||||
|
||||
"""EUI48 record"""
|
||||
|
||||
# see: rfc7043.txt
|
||||
|
||||
byte_len = 6 # 0123456789ab (in hex)
|
||||
text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab
|
31
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/EUI64.py
vendored
Normal file
31
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/EUI64.py
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
# Author: Petr Spacek <pspacek@redhat.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.euibase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class EUI64(dns.rdtypes.euibase.EUIBase):
|
||||
|
||||
"""EUI64 record"""
|
||||
|
||||
# see: rfc7043.txt
|
||||
|
||||
byte_len = 8 # 0123456789abcdef (in hex)
|
||||
text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab-cd-ef
|
128
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/GPOS.py
vendored
Normal file
128
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/GPOS.py
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
|
||||
def _validate_float_string(what):
|
||||
if len(what) == 0:
|
||||
raise dns.exception.FormError
|
||||
if what[0] == b'-'[0] or what[0] == b'+'[0]:
|
||||
what = what[1:]
|
||||
if what.isdigit():
|
||||
return
|
||||
try:
|
||||
(left, right) = what.split(b'.')
|
||||
except ValueError:
|
||||
raise dns.exception.FormError
|
||||
if left == b'' and right == b'':
|
||||
raise dns.exception.FormError
|
||||
if not left == b'' and not left.decode().isdigit():
|
||||
raise dns.exception.FormError
|
||||
if not right == b'' and not right.decode().isdigit():
|
||||
raise dns.exception.FormError
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class GPOS(dns.rdata.Rdata):
|
||||
|
||||
"""GPOS record"""
|
||||
|
||||
# see: RFC 1712
|
||||
|
||||
__slots__ = ['latitude', 'longitude', 'altitude']
|
||||
|
||||
def __init__(self, rdclass, rdtype, latitude, longitude, altitude):
|
||||
super().__init__(rdclass, rdtype)
|
||||
if isinstance(latitude, float) or \
|
||||
isinstance(latitude, int):
|
||||
latitude = str(latitude)
|
||||
if isinstance(longitude, float) or \
|
||||
isinstance(longitude, int):
|
||||
longitude = str(longitude)
|
||||
if isinstance(altitude, float) or \
|
||||
isinstance(altitude, int):
|
||||
altitude = str(altitude)
|
||||
latitude = self._as_bytes(latitude, True, 255)
|
||||
longitude = self._as_bytes(longitude, True, 255)
|
||||
altitude = self._as_bytes(altitude, True, 255)
|
||||
_validate_float_string(latitude)
|
||||
_validate_float_string(longitude)
|
||||
_validate_float_string(altitude)
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.altitude = altitude
|
||||
flat = self.float_latitude
|
||||
if flat < -90.0 or flat > 90.0:
|
||||
raise dns.exception.FormError('bad latitude')
|
||||
flong = self.float_longitude
|
||||
if flong < -180.0 or flong > 180.0:
|
||||
raise dns.exception.FormError('bad longitude')
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return '{} {} {}'.format(self.latitude.decode(),
|
||||
self.longitude.decode(),
|
||||
self.altitude.decode())
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
latitude = tok.get_string()
|
||||
longitude = tok.get_string()
|
||||
altitude = tok.get_string()
|
||||
return cls(rdclass, rdtype, latitude, longitude, altitude)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
l = len(self.latitude)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.latitude)
|
||||
l = len(self.longitude)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.longitude)
|
||||
l = len(self.altitude)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.altitude)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
latitude = parser.get_counted_bytes()
|
||||
longitude = parser.get_counted_bytes()
|
||||
altitude = parser.get_counted_bytes()
|
||||
return cls(rdclass, rdtype, latitude, longitude, altitude)
|
||||
|
||||
@property
|
||||
def float_latitude(self):
|
||||
"latitude as a floating point value"
|
||||
return float(self.latitude)
|
||||
|
||||
@property
|
||||
def float_longitude(self):
|
||||
"longitude as a floating point value"
|
||||
return float(self.longitude)
|
||||
|
||||
@property
|
||||
def float_altitude(self):
|
||||
"altitude as a floating point value"
|
||||
return float(self.altitude)
|
65
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/HINFO.py
vendored
Normal file
65
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/HINFO.py
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class HINFO(dns.rdata.Rdata):
|
||||
|
||||
"""HINFO record"""
|
||||
|
||||
# see: RFC 1035
|
||||
|
||||
__slots__ = ['cpu', 'os']
|
||||
|
||||
def __init__(self, rdclass, rdtype, cpu, os):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.cpu = self._as_bytes(cpu, True, 255)
|
||||
self.os = self._as_bytes(os, True, 255)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return '"{}" "{}"'.format(dns.rdata._escapify(self.cpu),
|
||||
dns.rdata._escapify(self.os))
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
cpu = tok.get_string(max_length=255)
|
||||
os = tok.get_string(max_length=255)
|
||||
return cls(rdclass, rdtype, cpu, os)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
l = len(self.cpu)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.cpu)
|
||||
l = len(self.os)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.os)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
cpu = parser.get_counted_bytes()
|
||||
os = parser.get_counted_bytes()
|
||||
return cls(rdclass, rdtype, cpu, os)
|
85
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/HIP.py
vendored
Normal file
85
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/HIP.py
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2010, 2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class HIP(dns.rdata.Rdata):
|
||||
|
||||
"""HIP record"""
|
||||
|
||||
# see: RFC 5205
|
||||
|
||||
__slots__ = ['hit', 'algorithm', 'key', 'servers']
|
||||
|
||||
def __init__(self, rdclass, rdtype, hit, algorithm, key, servers):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.hit = self._as_bytes(hit, True, 255)
|
||||
self.algorithm = self._as_uint8(algorithm)
|
||||
self.key = self._as_bytes(key, True)
|
||||
self.servers = self._as_tuple(servers, self._as_name)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
hit = binascii.hexlify(self.hit).decode()
|
||||
key = base64.b64encode(self.key).replace(b'\n', b'').decode()
|
||||
text = ''
|
||||
servers = []
|
||||
for server in self.servers:
|
||||
servers.append(server.choose_relativity(origin, relativize))
|
||||
if len(servers) > 0:
|
||||
text += (' ' + ' '.join((x.to_unicode() for x in servers)))
|
||||
return '%u %s %s%s' % (self.algorithm, hit, key, text)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
algorithm = tok.get_uint8()
|
||||
hit = binascii.unhexlify(tok.get_string().encode())
|
||||
key = base64.b64decode(tok.get_string().encode())
|
||||
servers = []
|
||||
for token in tok.get_remaining():
|
||||
server = tok.as_name(token, origin, relativize, relativize_to)
|
||||
servers.append(server)
|
||||
return cls(rdclass, rdtype, hit, algorithm, key, servers)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
lh = len(self.hit)
|
||||
lk = len(self.key)
|
||||
file.write(struct.pack("!BBH", lh, self.algorithm, lk))
|
||||
file.write(self.hit)
|
||||
file.write(self.key)
|
||||
for server in self.servers:
|
||||
server.to_wire(file, None, origin, False)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(lh, algorithm, lk) = parser.get_struct('!BBH')
|
||||
hit = parser.get_bytes(lh)
|
||||
key = parser.get_bytes(lk)
|
||||
servers = []
|
||||
while parser.remaining() > 0:
|
||||
server = parser.get_name(origin)
|
||||
servers.append(server)
|
||||
return cls(rdclass, rdtype, hit, algorithm, key, servers)
|
76
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/ISDN.py
vendored
Normal file
76
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/ISDN.py
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class ISDN(dns.rdata.Rdata):
|
||||
|
||||
"""ISDN record"""
|
||||
|
||||
# see: RFC 1183
|
||||
|
||||
__slots__ = ['address', 'subaddress']
|
||||
|
||||
def __init__(self, rdclass, rdtype, address, subaddress):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.address = self._as_bytes(address, True, 255)
|
||||
self.subaddress = self._as_bytes(subaddress, True, 255)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
if self.subaddress:
|
||||
return '"{}" "{}"'.format(dns.rdata._escapify(self.address),
|
||||
dns.rdata._escapify(self.subaddress))
|
||||
else:
|
||||
return '"%s"' % dns.rdata._escapify(self.address)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
address = tok.get_string()
|
||||
tokens = tok.get_remaining(max_tokens=1)
|
||||
if len(tokens) >= 1:
|
||||
subaddress = tokens[0].unescape().value
|
||||
else:
|
||||
subaddress = ''
|
||||
return cls(rdclass, rdtype, address, subaddress)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
l = len(self.address)
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.address)
|
||||
l = len(self.subaddress)
|
||||
if l > 0:
|
||||
assert l < 256
|
||||
file.write(struct.pack('!B', l))
|
||||
file.write(self.subaddress)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
address = parser.get_counted_bytes()
|
||||
if parser.remaining() > 0:
|
||||
subaddress = parser.get_counted_bytes()
|
||||
else:
|
||||
subaddress = b''
|
||||
return cls(rdclass, rdtype, address, subaddress)
|
326
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/LOC.py
vendored
Normal file
326
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/LOC.py
vendored
Normal file
|
@ -0,0 +1,326 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
|
||||
|
||||
_pows = tuple(10**i for i in range(0, 11))
|
||||
|
||||
# default values are in centimeters
|
||||
_default_size = 100.0
|
||||
_default_hprec = 1000000.0
|
||||
_default_vprec = 1000.0
|
||||
|
||||
# for use by from_wire()
|
||||
_MAX_LATITUDE = 0x80000000 + 90 * 3600000
|
||||
_MIN_LATITUDE = 0x80000000 - 90 * 3600000
|
||||
_MAX_LONGITUDE = 0x80000000 + 180 * 3600000
|
||||
_MIN_LONGITUDE = 0x80000000 - 180 * 3600000
|
||||
|
||||
|
||||
def _exponent_of(what, desc):
|
||||
if what == 0:
|
||||
return 0
|
||||
exp = None
|
||||
for (i, pow) in enumerate(_pows):
|
||||
if what < pow:
|
||||
exp = i - 1
|
||||
break
|
||||
if exp is None or exp < 0:
|
||||
raise dns.exception.SyntaxError("%s value out of bounds" % desc)
|
||||
return exp
|
||||
|
||||
|
||||
def _float_to_tuple(what):
|
||||
if what < 0:
|
||||
sign = -1
|
||||
what *= -1
|
||||
else:
|
||||
sign = 1
|
||||
what = round(what * 3600000) # pylint: disable=round-builtin
|
||||
degrees = int(what // 3600000)
|
||||
what -= degrees * 3600000
|
||||
minutes = int(what // 60000)
|
||||
what -= minutes * 60000
|
||||
seconds = int(what // 1000)
|
||||
what -= int(seconds * 1000)
|
||||
what = int(what)
|
||||
return (degrees, minutes, seconds, what, sign)
|
||||
|
||||
|
||||
def _tuple_to_float(what):
|
||||
value = float(what[0])
|
||||
value += float(what[1]) / 60.0
|
||||
value += float(what[2]) / 3600.0
|
||||
value += float(what[3]) / 3600000.0
|
||||
return float(what[4]) * value
|
||||
|
||||
|
||||
def _encode_size(what, desc):
|
||||
what = int(what)
|
||||
exponent = _exponent_of(what, desc) & 0xF
|
||||
base = what // pow(10, exponent) & 0xF
|
||||
return base * 16 + exponent
|
||||
|
||||
|
||||
def _decode_size(what, desc):
|
||||
exponent = what & 0x0F
|
||||
if exponent > 9:
|
||||
raise dns.exception.FormError("bad %s exponent" % desc)
|
||||
base = (what & 0xF0) >> 4
|
||||
if base > 9:
|
||||
raise dns.exception.FormError("bad %s base" % desc)
|
||||
return base * pow(10, exponent)
|
||||
|
||||
|
||||
def _check_coordinate_list(value, low, high):
|
||||
if value[0] < low or value[0] > high:
|
||||
raise ValueError(f'not in range [{low}, {high}]')
|
||||
if value[1] < 0 or value[1] > 59:
|
||||
raise ValueError('bad minutes value')
|
||||
if value[2] < 0 or value[2] > 59:
|
||||
raise ValueError('bad seconds value')
|
||||
if value[3] < 0 or value[3] > 999:
|
||||
raise ValueError('bad milliseconds value')
|
||||
if value[4] != 1 and value[4] != -1:
|
||||
raise ValueError('bad hemisphere value')
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class LOC(dns.rdata.Rdata):
|
||||
|
||||
"""LOC record"""
|
||||
|
||||
# see: RFC 1876
|
||||
|
||||
__slots__ = ['latitude', 'longitude', 'altitude', 'size',
|
||||
'horizontal_precision', 'vertical_precision']
|
||||
|
||||
def __init__(self, rdclass, rdtype, latitude, longitude, altitude,
|
||||
size=_default_size, hprec=_default_hprec,
|
||||
vprec=_default_vprec):
|
||||
"""Initialize a LOC record instance.
|
||||
|
||||
The parameters I{latitude} and I{longitude} may be either a 4-tuple
|
||||
of integers specifying (degrees, minutes, seconds, milliseconds),
|
||||
or they may be floating point values specifying the number of
|
||||
degrees. The other parameters are floats. Size, horizontal precision,
|
||||
and vertical precision are specified in centimeters."""
|
||||
|
||||
super().__init__(rdclass, rdtype)
|
||||
if isinstance(latitude, int):
|
||||
latitude = float(latitude)
|
||||
if isinstance(latitude, float):
|
||||
latitude = _float_to_tuple(latitude)
|
||||
_check_coordinate_list(latitude, -90, 90)
|
||||
self.latitude = tuple(latitude)
|
||||
if isinstance(longitude, int):
|
||||
longitude = float(longitude)
|
||||
if isinstance(longitude, float):
|
||||
longitude = _float_to_tuple(longitude)
|
||||
_check_coordinate_list(longitude, -180, 180)
|
||||
self.longitude = tuple(longitude)
|
||||
self.altitude = float(altitude)
|
||||
self.size = float(size)
|
||||
self.horizontal_precision = float(hprec)
|
||||
self.vertical_precision = float(vprec)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
if self.latitude[4] > 0:
|
||||
lat_hemisphere = 'N'
|
||||
else:
|
||||
lat_hemisphere = 'S'
|
||||
if self.longitude[4] > 0:
|
||||
long_hemisphere = 'E'
|
||||
else:
|
||||
long_hemisphere = 'W'
|
||||
text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % (
|
||||
self.latitude[0], self.latitude[1],
|
||||
self.latitude[2], self.latitude[3], lat_hemisphere,
|
||||
self.longitude[0], self.longitude[1], self.longitude[2],
|
||||
self.longitude[3], long_hemisphere,
|
||||
self.altitude / 100.0
|
||||
)
|
||||
|
||||
# do not print default values
|
||||
if self.size != _default_size or \
|
||||
self.horizontal_precision != _default_hprec or \
|
||||
self.vertical_precision != _default_vprec:
|
||||
text += " {:0.2f}m {:0.2f}m {:0.2f}m".format(
|
||||
self.size / 100.0, self.horizontal_precision / 100.0,
|
||||
self.vertical_precision / 100.0
|
||||
)
|
||||
return text
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
latitude = [0, 0, 0, 0, 1]
|
||||
longitude = [0, 0, 0, 0, 1]
|
||||
size = _default_size
|
||||
hprec = _default_hprec
|
||||
vprec = _default_vprec
|
||||
|
||||
latitude[0] = tok.get_int()
|
||||
t = tok.get_string()
|
||||
if t.isdigit():
|
||||
latitude[1] = int(t)
|
||||
t = tok.get_string()
|
||||
if '.' in t:
|
||||
(seconds, milliseconds) = t.split('.')
|
||||
if not seconds.isdigit():
|
||||
raise dns.exception.SyntaxError(
|
||||
'bad latitude seconds value')
|
||||
latitude[2] = int(seconds)
|
||||
l = len(milliseconds)
|
||||
if l == 0 or l > 3 or not milliseconds.isdigit():
|
||||
raise dns.exception.SyntaxError(
|
||||
'bad latitude milliseconds value')
|
||||
if l == 1:
|
||||
m = 100
|
||||
elif l == 2:
|
||||
m = 10
|
||||
else:
|
||||
m = 1
|
||||
latitude[3] = m * int(milliseconds)
|
||||
t = tok.get_string()
|
||||
elif t.isdigit():
|
||||
latitude[2] = int(t)
|
||||
t = tok.get_string()
|
||||
if t == 'S':
|
||||
latitude[4] = -1
|
||||
elif t != 'N':
|
||||
raise dns.exception.SyntaxError('bad latitude hemisphere value')
|
||||
|
||||
longitude[0] = tok.get_int()
|
||||
t = tok.get_string()
|
||||
if t.isdigit():
|
||||
longitude[1] = int(t)
|
||||
t = tok.get_string()
|
||||
if '.' in t:
|
||||
(seconds, milliseconds) = t.split('.')
|
||||
if not seconds.isdigit():
|
||||
raise dns.exception.SyntaxError(
|
||||
'bad longitude seconds value')
|
||||
longitude[2] = int(seconds)
|
||||
l = len(milliseconds)
|
||||
if l == 0 or l > 3 or not milliseconds.isdigit():
|
||||
raise dns.exception.SyntaxError(
|
||||
'bad longitude milliseconds value')
|
||||
if l == 1:
|
||||
m = 100
|
||||
elif l == 2:
|
||||
m = 10
|
||||
else:
|
||||
m = 1
|
||||
longitude[3] = m * int(milliseconds)
|
||||
t = tok.get_string()
|
||||
elif t.isdigit():
|
||||
longitude[2] = int(t)
|
||||
t = tok.get_string()
|
||||
if t == 'W':
|
||||
longitude[4] = -1
|
||||
elif t != 'E':
|
||||
raise dns.exception.SyntaxError('bad longitude hemisphere value')
|
||||
|
||||
t = tok.get_string()
|
||||
if t[-1] == 'm':
|
||||
t = t[0: -1]
|
||||
altitude = float(t) * 100.0 # m -> cm
|
||||
|
||||
tokens = tok.get_remaining(max_tokens=3)
|
||||
if len(tokens) >= 1:
|
||||
value = tokens[0].unescape().value
|
||||
if value[-1] == 'm':
|
||||
value = value[0: -1]
|
||||
size = float(value) * 100.0 # m -> cm
|
||||
if len(tokens) >= 2:
|
||||
value = tokens[1].unescape().value
|
||||
if value[-1] == 'm':
|
||||
value = value[0: -1]
|
||||
hprec = float(value) * 100.0 # m -> cm
|
||||
if len(tokens) >= 3:
|
||||
value = tokens[2].unescape().value
|
||||
if value[-1] == 'm':
|
||||
value = value[0: -1]
|
||||
vprec = float(value) * 100.0 # m -> cm
|
||||
|
||||
# Try encoding these now so we raise if they are bad
|
||||
_encode_size(size, "size")
|
||||
_encode_size(hprec, "horizontal precision")
|
||||
_encode_size(vprec, "vertical precision")
|
||||
|
||||
return cls(rdclass, rdtype, latitude, longitude, altitude,
|
||||
size, hprec, vprec)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
milliseconds = (self.latitude[0] * 3600000 +
|
||||
self.latitude[1] * 60000 +
|
||||
self.latitude[2] * 1000 +
|
||||
self.latitude[3]) * self.latitude[4]
|
||||
latitude = 0x80000000 + milliseconds
|
||||
milliseconds = (self.longitude[0] * 3600000 +
|
||||
self.longitude[1] * 60000 +
|
||||
self.longitude[2] * 1000 +
|
||||
self.longitude[3]) * self.longitude[4]
|
||||
longitude = 0x80000000 + milliseconds
|
||||
altitude = int(self.altitude) + 10000000
|
||||
size = _encode_size(self.size, "size")
|
||||
hprec = _encode_size(self.horizontal_precision, "horizontal precision")
|
||||
vprec = _encode_size(self.vertical_precision, "vertical precision")
|
||||
wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude,
|
||||
longitude, altitude)
|
||||
file.write(wire)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(version, size, hprec, vprec, latitude, longitude, altitude) = \
|
||||
parser.get_struct("!BBBBIII")
|
||||
if version != 0:
|
||||
raise dns.exception.FormError("LOC version not zero")
|
||||
if latitude < _MIN_LATITUDE or latitude > _MAX_LATITUDE:
|
||||
raise dns.exception.FormError("bad latitude")
|
||||
if latitude > 0x80000000:
|
||||
latitude = (latitude - 0x80000000) / 3600000
|
||||
else:
|
||||
latitude = -1 * (0x80000000 - latitude) / 3600000
|
||||
if longitude < _MIN_LONGITUDE or longitude > _MAX_LONGITUDE:
|
||||
raise dns.exception.FormError("bad longitude")
|
||||
if longitude > 0x80000000:
|
||||
longitude = (longitude - 0x80000000) / 3600000
|
||||
else:
|
||||
longitude = -1 * (0x80000000 - longitude) / 3600000
|
||||
altitude = float(altitude) - 10000000.0
|
||||
size = _decode_size(size, "size")
|
||||
hprec = _decode_size(hprec, "horizontal precision")
|
||||
vprec = _decode_size(vprec, "vertical precision")
|
||||
return cls(rdclass, rdtype, latitude, longitude, altitude,
|
||||
size, hprec, vprec)
|
||||
|
||||
@property
|
||||
def float_latitude(self):
|
||||
"latitude as a floating point value"
|
||||
return _tuple_to_float(self.latitude)
|
||||
|
||||
@property
|
||||
def float_longitude(self):
|
||||
"longitude as a floating point value"
|
||||
return _tuple_to_float(self.longitude)
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/MX.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/MX.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.mxbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class MX(dns.rdtypes.mxbase.MXBase):
|
||||
|
||||
"""MX record"""
|
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NINFO.py
vendored
Normal file
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NINFO.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.txtbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class NINFO(dns.rdtypes.txtbase.TXTBase):
|
||||
|
||||
"""NINFO record"""
|
||||
|
||||
# see: draft-reid-dnsext-zs-01
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NS.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NS.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.nsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class NS(dns.rdtypes.nsbase.NSBase):
|
||||
|
||||
"""NS record"""
|
67
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC.py
vendored
Normal file
67
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC.py
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
import dns.name
|
||||
import dns.rdtypes.util
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class Bitmap(dns.rdtypes.util.Bitmap):
|
||||
type_name = 'NSEC'
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class NSEC(dns.rdata.Rdata):
|
||||
|
||||
"""NSEC record"""
|
||||
|
||||
__slots__ = ['next', 'windows']
|
||||
|
||||
def __init__(self, rdclass, rdtype, next, windows):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.next = self._as_name(next)
|
||||
if not isinstance(windows, Bitmap):
|
||||
windows = Bitmap(windows)
|
||||
self.windows = tuple(windows.windows)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
next = self.next.choose_relativity(origin, relativize)
|
||||
text = Bitmap(self.windows).to_text()
|
||||
return '{}{}'.format(next, text)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
next = tok.get_name(origin, relativize, relativize_to)
|
||||
windows = Bitmap.from_text(tok)
|
||||
return cls(rdclass, rdtype, next, windows)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
# Note that NSEC downcasing, originally mandated by RFC 4034
|
||||
# section 6.2 was removed by RFC 6840 section 5.1.
|
||||
self.next.to_wire(file, None, origin, False)
|
||||
Bitmap(self.windows).to_wire(file)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
next = parser.get_name(origin)
|
||||
bitmap = Bitmap.from_wire_parser(parser)
|
||||
return cls(rdclass, rdtype, next, bitmap)
|
111
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC3.py
vendored
Normal file
111
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC3.py
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
import dns.rdtypes.util
|
||||
|
||||
|
||||
b32_hex_to_normal = bytes.maketrans(b'0123456789ABCDEFGHIJKLMNOPQRSTUV',
|
||||
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
|
||||
b32_normal_to_hex = bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
||||
b'0123456789ABCDEFGHIJKLMNOPQRSTUV')
|
||||
|
||||
# hash algorithm constants
|
||||
SHA1 = 1
|
||||
|
||||
# flag constants
|
||||
OPTOUT = 1
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class Bitmap(dns.rdtypes.util.Bitmap):
|
||||
type_name = 'NSEC3'
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class NSEC3(dns.rdata.Rdata):
|
||||
|
||||
"""NSEC3 record"""
|
||||
|
||||
__slots__ = ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows']
|
||||
|
||||
def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt,
|
||||
next, windows):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.algorithm = self._as_uint8(algorithm)
|
||||
self.flags = self._as_uint8(flags)
|
||||
self.iterations = self._as_uint16(iterations)
|
||||
self.salt = self._as_bytes(salt, True, 255)
|
||||
self.next = self._as_bytes(next, True, 255)
|
||||
if not isinstance(windows, Bitmap):
|
||||
windows = Bitmap(windows)
|
||||
self.windows = tuple(windows.windows)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
next = base64.b32encode(self.next).translate(
|
||||
b32_normal_to_hex).lower().decode()
|
||||
if self.salt == b'':
|
||||
salt = '-'
|
||||
else:
|
||||
salt = binascii.hexlify(self.salt).decode()
|
||||
text = Bitmap(self.windows).to_text()
|
||||
return '%u %u %u %s %s%s' % (self.algorithm, self.flags,
|
||||
self.iterations, salt, next, text)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
algorithm = tok.get_uint8()
|
||||
flags = tok.get_uint8()
|
||||
iterations = tok.get_uint16()
|
||||
salt = tok.get_string()
|
||||
if salt == '-':
|
||||
salt = b''
|
||||
else:
|
||||
salt = binascii.unhexlify(salt.encode('ascii'))
|
||||
next = tok.get_string().encode(
|
||||
'ascii').upper().translate(b32_hex_to_normal)
|
||||
next = base64.b32decode(next)
|
||||
bitmap = Bitmap.from_text(tok)
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
|
||||
bitmap)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
l = len(self.salt)
|
||||
file.write(struct.pack("!BBHB", self.algorithm, self.flags,
|
||||
self.iterations, l))
|
||||
file.write(self.salt)
|
||||
l = len(self.next)
|
||||
file.write(struct.pack("!B", l))
|
||||
file.write(self.next)
|
||||
Bitmap(self.windows).to_wire(file)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(algorithm, flags, iterations) = parser.get_struct('!BBH')
|
||||
salt = parser.get_counted_bytes()
|
||||
next = parser.get_counted_bytes()
|
||||
bitmap = Bitmap.from_wire_parser(parser)
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
|
||||
bitmap)
|
71
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC3PARAM.py
vendored
Normal file
71
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/NSEC3PARAM.py
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
import binascii
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class NSEC3PARAM(dns.rdata.Rdata):
|
||||
|
||||
"""NSEC3PARAM record"""
|
||||
|
||||
__slots__ = ['algorithm', 'flags', 'iterations', 'salt']
|
||||
|
||||
def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.algorithm = self._as_uint8(algorithm)
|
||||
self.flags = self._as_uint8(flags)
|
||||
self.iterations = self._as_uint16(iterations)
|
||||
self.salt = self._as_bytes(salt, True, 255)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
if self.salt == b'':
|
||||
salt = '-'
|
||||
else:
|
||||
salt = binascii.hexlify(self.salt).decode()
|
||||
return '%u %u %u %s' % (self.algorithm, self.flags, self.iterations,
|
||||
salt)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
algorithm = tok.get_uint8()
|
||||
flags = tok.get_uint8()
|
||||
iterations = tok.get_uint16()
|
||||
salt = tok.get_string()
|
||||
if salt == '-':
|
||||
salt = ''
|
||||
else:
|
||||
salt = binascii.unhexlify(salt.encode())
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
l = len(self.salt)
|
||||
file.write(struct.pack("!BBHB", self.algorithm, self.flags,
|
||||
self.iterations, l))
|
||||
file.write(self.salt)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
(algorithm, flags, iterations) = parser.get_struct('!BBH')
|
||||
salt = parser.get_counted_bytes()
|
||||
return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
|
52
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/OPENPGPKEY.py
vendored
Normal file
52
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/OPENPGPKEY.py
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2016 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import base64
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.tokenizer
|
||||
|
||||
@dns.immutable.immutable
|
||||
class OPENPGPKEY(dns.rdata.Rdata):
|
||||
|
||||
"""OPENPGPKEY record"""
|
||||
|
||||
# see: RFC 7929
|
||||
|
||||
def __init__(self, rdclass, rdtype, key):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.key = self._as_bytes(key)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return dns.rdata._base64ify(self.key, chunksize=None, **kw)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
b64 = tok.concatenate_remaining_identifiers().encode()
|
||||
key = base64.b64decode(b64)
|
||||
return cls(rdclass, rdtype, key)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
file.write(self.key)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
key = parser.get_remaining()
|
||||
return cls(rdclass, rdtype, key)
|
76
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/OPT.py
vendored
Normal file
76
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/OPT.py
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2001-2017 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.edns
|
||||
import dns.immutable
|
||||
import dns.exception
|
||||
import dns.rdata
|
||||
|
||||
|
||||
# We don't implement from_text, and that's ok.
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
@dns.immutable.immutable
|
||||
class OPT(dns.rdata.Rdata):
|
||||
|
||||
"""OPT record"""
|
||||
|
||||
__slots__ = ['options']
|
||||
|
||||
def __init__(self, rdclass, rdtype, options):
|
||||
"""Initialize an OPT rdata.
|
||||
|
||||
*rdclass*, an ``int`` is the rdataclass of the Rdata,
|
||||
which is also the payload size.
|
||||
|
||||
*rdtype*, an ``int`` is the rdatatype of the Rdata.
|
||||
|
||||
*options*, a tuple of ``bytes``
|
||||
"""
|
||||
|
||||
super().__init__(rdclass, rdtype)
|
||||
def as_option(option):
|
||||
if not isinstance(option, dns.edns.Option):
|
||||
raise ValueError('option is not a dns.edns.option')
|
||||
return option
|
||||
self.options = self._as_tuple(options, as_option)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
for opt in self.options:
|
||||
owire = opt.to_wire()
|
||||
file.write(struct.pack("!HH", opt.otype, len(owire)))
|
||||
file.write(owire)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return ' '.join(opt.to_text() for opt in self.options)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
options = []
|
||||
while parser.remaining() > 0:
|
||||
(otype, olen) = parser.get_struct('!HH')
|
||||
with parser.restrict_to(olen):
|
||||
opt = dns.edns.option_from_wire_parser(otype, parser)
|
||||
options.append(opt)
|
||||
return cls(rdclass, rdtype, options)
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
"payload size"
|
||||
return self.rdclass
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/PTR.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/PTR.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.nsbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class PTR(dns.rdtypes.nsbase.NSBase):
|
||||
|
||||
"""PTR record"""
|
58
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RP.py
vendored
Normal file
58
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RP.py
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.name
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class RP(dns.rdata.Rdata):
|
||||
|
||||
"""RP record"""
|
||||
|
||||
# see: RFC 1183
|
||||
|
||||
__slots__ = ['mbox', 'txt']
|
||||
|
||||
def __init__(self, rdclass, rdtype, mbox, txt):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.mbox = self._as_name(mbox)
|
||||
self.txt = self._as_name(txt)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
mbox = self.mbox.choose_relativity(origin, relativize)
|
||||
txt = self.txt.choose_relativity(origin, relativize)
|
||||
return "{} {}".format(str(mbox), str(txt))
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
mbox = tok.get_name(origin, relativize, relativize_to)
|
||||
txt = tok.get_name(origin, relativize, relativize_to)
|
||||
return cls(rdclass, rdtype, mbox, txt)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
self.mbox.to_wire(file, None, origin, canonicalize)
|
||||
self.txt.to_wire(file, None, origin, canonicalize)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
mbox = parser.get_name(origin)
|
||||
txt = parser.get_name(origin)
|
||||
return cls(rdclass, rdtype, mbox, txt)
|
124
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RRSIG.py
vendored
Normal file
124
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RRSIG.py
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import base64
|
||||
import calendar
|
||||
import struct
|
||||
import time
|
||||
|
||||
import dns.dnssec
|
||||
import dns.immutable
|
||||
import dns.exception
|
||||
import dns.rdata
|
||||
import dns.rdatatype
|
||||
|
||||
|
||||
class BadSigTime(dns.exception.DNSException):
|
||||
|
||||
"""Time in DNS SIG or RRSIG resource record cannot be parsed."""
|
||||
|
||||
|
||||
def sigtime_to_posixtime(what):
|
||||
if len(what) <= 10 and what.isdigit():
|
||||
return int(what)
|
||||
if len(what) != 14:
|
||||
raise BadSigTime
|
||||
year = int(what[0:4])
|
||||
month = int(what[4:6])
|
||||
day = int(what[6:8])
|
||||
hour = int(what[8:10])
|
||||
minute = int(what[10:12])
|
||||
second = int(what[12:14])
|
||||
return calendar.timegm((year, month, day, hour, minute, second,
|
||||
0, 0, 0))
|
||||
|
||||
|
||||
def posixtime_to_sigtime(what):
|
||||
return time.strftime('%Y%m%d%H%M%S', time.gmtime(what))
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class RRSIG(dns.rdata.Rdata):
|
||||
|
||||
"""RRSIG record"""
|
||||
|
||||
__slots__ = ['type_covered', 'algorithm', 'labels', 'original_ttl',
|
||||
'expiration', 'inception', 'key_tag', 'signer',
|
||||
'signature']
|
||||
|
||||
def __init__(self, rdclass, rdtype, type_covered, algorithm, labels,
|
||||
original_ttl, expiration, inception, key_tag, signer,
|
||||
signature):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.type_covered = self._as_rdatatype(type_covered)
|
||||
self.algorithm = dns.dnssec.Algorithm.make(algorithm)
|
||||
self.labels = self._as_uint8(labels)
|
||||
self.original_ttl = self._as_ttl(original_ttl)
|
||||
self.expiration = self._as_uint32(expiration)
|
||||
self.inception = self._as_uint32(inception)
|
||||
self.key_tag = self._as_uint16(key_tag)
|
||||
self.signer = self._as_name(signer)
|
||||
self.signature = self._as_bytes(signature)
|
||||
|
||||
def covers(self):
|
||||
return self.type_covered
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
return '%s %d %d %d %s %s %d %s %s' % (
|
||||
dns.rdatatype.to_text(self.type_covered),
|
||||
self.algorithm,
|
||||
self.labels,
|
||||
self.original_ttl,
|
||||
posixtime_to_sigtime(self.expiration),
|
||||
posixtime_to_sigtime(self.inception),
|
||||
self.key_tag,
|
||||
self.signer.choose_relativity(origin, relativize),
|
||||
dns.rdata._base64ify(self.signature, **kw)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
type_covered = dns.rdatatype.from_text(tok.get_string())
|
||||
algorithm = dns.dnssec.algorithm_from_text(tok.get_string())
|
||||
labels = tok.get_int()
|
||||
original_ttl = tok.get_ttl()
|
||||
expiration = sigtime_to_posixtime(tok.get_string())
|
||||
inception = sigtime_to_posixtime(tok.get_string())
|
||||
key_tag = tok.get_int()
|
||||
signer = tok.get_name(origin, relativize, relativize_to)
|
||||
b64 = tok.concatenate_remaining_identifiers().encode()
|
||||
signature = base64.b64decode(b64)
|
||||
return cls(rdclass, rdtype, type_covered, algorithm, labels,
|
||||
original_ttl, expiration, inception, key_tag, signer,
|
||||
signature)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
header = struct.pack('!HBBIIIH', self.type_covered,
|
||||
self.algorithm, self.labels,
|
||||
self.original_ttl, self.expiration,
|
||||
self.inception, self.key_tag)
|
||||
file.write(header)
|
||||
self.signer.to_wire(file, None, origin, canonicalize)
|
||||
file.write(self.signature)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
header = parser.get_struct('!HBBIIIH')
|
||||
signer = parser.get_name(origin)
|
||||
signature = parser.get_remaining()
|
||||
return cls(rdclass, rdtype, *header, signer, signature)
|
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RT.py
vendored
Normal file
25
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/RT.py
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.mxbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX):
|
||||
|
||||
"""RT record"""
|
9
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SMIMEA.py
vendored
Normal file
9
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SMIMEA.py
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
import dns.immutable
|
||||
import dns.rdtypes.tlsabase
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class SMIMEA(dns.rdtypes.tlsabase.TLSABase):
|
||||
"""SMIMEA record"""
|
78
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SOA.py
vendored
Normal file
78
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SOA.py
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import struct
|
||||
|
||||
import dns.exception
|
||||
import dns.immutable
|
||||
import dns.rdata
|
||||
import dns.name
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class SOA(dns.rdata.Rdata):
|
||||
|
||||
"""SOA record"""
|
||||
|
||||
# see: RFC 1035
|
||||
|
||||
__slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire',
|
||||
'minimum']
|
||||
|
||||
def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry,
|
||||
expire, minimum):
|
||||
super().__init__(rdclass, rdtype)
|
||||
self.mname = self._as_name(mname)
|
||||
self.rname = self._as_name(rname)
|
||||
self.serial = self._as_uint32(serial)
|
||||
self.refresh = self._as_ttl(refresh)
|
||||
self.retry = self._as_ttl(retry)
|
||||
self.expire = self._as_ttl(expire)
|
||||
self.minimum = self._as_ttl(minimum)
|
||||
|
||||
def to_text(self, origin=None, relativize=True, **kw):
|
||||
mname = self.mname.choose_relativity(origin, relativize)
|
||||
rname = self.rname.choose_relativity(origin, relativize)
|
||||
return '%s %s %d %d %d %d %d' % (
|
||||
mname, rname, self.serial, self.refresh, self.retry,
|
||||
self.expire, self.minimum)
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True,
|
||||
relativize_to=None):
|
||||
mname = tok.get_name(origin, relativize, relativize_to)
|
||||
rname = tok.get_name(origin, relativize, relativize_to)
|
||||
serial = tok.get_uint32()
|
||||
refresh = tok.get_ttl()
|
||||
retry = tok.get_ttl()
|
||||
expire = tok.get_ttl()
|
||||
minimum = tok.get_ttl()
|
||||
return cls(rdclass, rdtype, mname, rname, serial, refresh, retry,
|
||||
expire, minimum)
|
||||
|
||||
def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
|
||||
self.mname.to_wire(file, compress, origin, canonicalize)
|
||||
self.rname.to_wire(file, compress, origin, canonicalize)
|
||||
five_ints = struct.pack('!IIIII', self.serial, self.refresh,
|
||||
self.retry, self.expire, self.minimum)
|
||||
file.write(five_ints)
|
||||
|
||||
@classmethod
|
||||
def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
|
||||
mname = parser.get_name(origin)
|
||||
rname = parser.get_name(origin)
|
||||
return cls(rdclass, rdtype, mname, rname, *parser.get_struct('!IIIII'))
|
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SPF.py
vendored
Normal file
27
NSICollectionPlatformServer/packages/dnspython-2.1.0/build/lib/dns/rdtypes/ANY/SPF.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||||
|
||||
# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose with or without fee is hereby granted,
|
||||
# provided that the above copyright notice and this permission notice
|
||||
# appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import dns.rdtypes.txtbase
|
||||
import dns.immutable
|
||||
|
||||
|
||||
@dns.immutable.immutable
|
||||
class SPF(dns.rdtypes.txtbase.TXTBase):
|
||||
|
||||
"""SPF record"""
|
||||
|
||||
# see: RFC 4408
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user