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
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
# vue
|
||||||
*.so
|
./nsi-collection-platform/node_modules/
|
||||||
|
./nsi-collection-platform/dist/
|
||||||
|
./nsi-collection-platform/.idea
|
||||||
|
|
||||||
# Distribution / packaging
|
NSICollectionPlatformServer/.idea
|
||||||
.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/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