# async_dns
[![PyPI](https://img.shields.io/pypi/v/async_dns.svg)]()
This is the documentation for v2.x. Click [here](https://github.com/gera2ld/async_dns/tree/v1.1.10) for 1.x documentation.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Features](#features)
- [Prerequisite](#prerequisite)
- [Installation](#installation)
- [CLI](#cli)
- [Resolver](#resolver)
- [Server](#server)
- [API](#api)
- [Client](#client)
- [Routing](#routing)
- [DoH support](#doh-support)
- [DNS Spoofing](#dns-spoofing)
- [Test](#test)
- [Logging](#logging)
- [References](#references)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Features
- Built with `asyncio` in pure Python, no third party dependency is required
- Support DNS over UDP / TCP
- Support DNS over HTTPS
- Support DNS over TLS
## Prerequisite
- Python >=3.6
## Installation
``` sh
$ pip3 install async_dns
# or
$ pip3 install git+https://github.com/gera2ld/async_dns.git
```
## CLI
### Resolver
```
usage: python3 -m async_dns.resolver [-h] [-n NAMESERVERS [NAMESERVERS ...]] [-t TYPES [TYPES ...]]
hostnames [hostnames ...]
Async DNS resolver
positional arguments:
hostnames the hostnames to query
optional arguments:
-h, --help show this help message and exit
-n NAMESERVERS [NAMESERVERS ...], --nameservers NAMESERVERS [NAMESERVERS ...]
name servers
-t TYPES [TYPES ...], --types TYPES [TYPES ...]
query types, default as `any`
```
Examples:
``` sh
# Resolve an IP
$ python3 -m async_dns.resolver www.google.com
$ python3 -m async_dns.resolver -t mx -- gmail.com
# Query via TCP
$ python3 -m async_dns.resolver -n tcp://127.0.0.1 -- www.google.com
# Query via TLS
$ python3 -m async_dns.resolver -n tcps://dns.alidns.com -- www.google.com
# Query from non-standard ports
$ python3 -m async_dns.resolver -n udp://127.0.0.1:1053 -- www.google.com
# Query from HTTPS
$ python3 -m async_dns.resolver -n https://dns.alidns.com/dns-query -- www.google.com
```
**Note:** `--` is required before `hostname`s if the previous option can have multiple arguments.
### Server
```
usage: python3 -m async_dns.server [-h] [-b BIND] [--hosts HOSTS] [-x [PROXY [PROXY ...]]]
DNS server by Gerald.
optional arguments:
-h, --help show this help message and exit
-b BIND, --bind BIND the address for the server to bind
--hosts HOSTS the path of a hosts file, `none` to disable hosts, `local` to read from
local hosts file
-x [PROXY [PROXY ...]], --proxy [PROXY [PROXY ...]]
the proxy DNS servers, `none` to serve as a recursive server, `default` to
proxy to default nameservers
```
**Note:** TLS and HTTPS are not supported in `async_dns` server. Consider [async-doh](https://github.com/gera2ld/async-doh) for DoH server support.
Examples:
``` sh
# Start a DNS proxy server on :53
$ python3 -m async_dns.server -b :53 --hosts /etc/hosts
# Start a DNS server over TCP proxy
$ python3 -m async_dns.server -x tcp://114.114.114.114
# Start a DNS recursive server
$ python3 -m async_dns.server -x none
```
## API
``` python
import asyncio
from async_dns.core import types
from async_dns.resolver import ProxyResolver
resolver = ProxyResolver()
res, cached = asyncio.run(resolver.query('www.baidu.com', types.A))
print(res)
```
### Client
The client sends a request to a remote server and returns the message directly. Unlike resolvers, client does not have a cache and does not modify the response.
```python
import asyncio
from async_dns.core import types, Address
from async_dns.resolver import DNSClient
async def query():
client = DNSClient()
res = await client.query('www.google.com', types.A,
Address.parse('8.8.8.8'))
print(res)
print(res.aa)
asyncio.run(query())
```
### Routing
ProxyResolver supports routing based on domains:
```python
resolver = ProxyResolver(proxies=[
('*.lan', ['192.168.1.1']), # query 'udp://192.168.1.1:53' for '*.lan' domains
(lambda d: d.endswith('.local'), ['tcp://127.0.0.1']), # query tcp://127.0.0.1:53 for domains ending with '.local'
'8.8.8.8', # equivalent to (None, ['8.8.8.8']), matches all others
])
```
## DoH support
This library contains a simple implementation of DoH (aka DNS over HTTPS) client with partial HTTP protocol implemented.
If you need a more powerful DoH client based on [aiohttp](https://docs.aiohttp.org/en/stable/), or a DoH server, consider [async-doh](https://github.com/gera2ld/async-doh).
## DNS Spoofing
You can easily add records to the cache with a hosts file or the cache API.
- Start a server with a custom hosts file:
```bash
$ python3 -m async_dns.server -b :53 --hosts /path/to/custom/hosts
```
- Add some additional records to a resolver:
```python
from async_dns.core import parse_hosts_file, types
for name, qtype, data in parse_hosts_file(hosts):
resolver.cache.add(name, qtype, data)
resolver.cache.add('www.example.com', types.A, ['127.0.0.1'])
```
## Test
```bash
$ python3 -m unittest
# Or with tox
$ tox -e py
```
## Logging
Logging does not work out of the box in v2. It requires at least minimal `logging` configuration.
```py
logging.basicConfig(level=logging.INFO)
```
You can also add a formatter for the logger:
```py
import logging
from async_dns.core import logger
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
fmt = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
handler.setFormatter(fmt)
logger.addHandler(handler)
```
## References
- <https://tools.ietf.org/html/rfc1034>
- <https://tools.ietf.org/html/rfc1035>
- <https://tools.ietf.org/html/rfc1464> TXT
- <https://tools.ietf.org/html/rfc2915> NAPTR
Raw data
{
"_id": null,
"home_page": "https://github.com/gera2ld/async_dns",
"name": "async-dns",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6,<4.0",
"maintainer_email": "",
"keywords": "async,dns,asyncio",
"author": "Gerald",
"author_email": "gera2ld@live.com",
"download_url": "https://files.pythonhosted.org/packages/8e/4b/e37f42f7633b3287421545c9dae85cface08d664a638e444953f2b334f6c/async_dns-2.0.0.tar.gz",
"platform": "",
"description": "# async_dns\n\n[![PyPI](https://img.shields.io/pypi/v/async_dns.svg)]()\n\nThis is the documentation for v2.x. Click [here](https://github.com/gera2ld/async_dns/tree/v1.1.10) for 1.x documentation.\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [Features](#features)\n- [Prerequisite](#prerequisite)\n- [Installation](#installation)\n- [CLI](#cli)\n - [Resolver](#resolver)\n - [Server](#server)\n- [API](#api)\n - [Client](#client)\n - [Routing](#routing)\n- [DoH support](#doh-support)\n- [DNS Spoofing](#dns-spoofing)\n- [Test](#test)\n- [Logging](#logging)\n- [References](#references)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n## Features\n\n- Built with `asyncio` in pure Python, no third party dependency is required\n- Support DNS over UDP / TCP\n- Support DNS over HTTPS\n- Support DNS over TLS\n\n## Prerequisite\n\n- Python >=3.6\n\n## Installation\n\n``` sh\n$ pip3 install async_dns\n# or\n$ pip3 install git+https://github.com/gera2ld/async_dns.git\n```\n\n## CLI\n\n### Resolver\n\n```\nusage: python3 -m async_dns.resolver [-h] [-n NAMESERVERS [NAMESERVERS ...]] [-t TYPES [TYPES ...]]\n hostnames [hostnames ...]\n\nAsync DNS resolver\n\npositional arguments:\n hostnames the hostnames to query\n\noptional arguments:\n -h, --help show this help message and exit\n -n NAMESERVERS [NAMESERVERS ...], --nameservers NAMESERVERS [NAMESERVERS ...]\n name servers\n -t TYPES [TYPES ...], --types TYPES [TYPES ...]\n query types, default as `any`\n```\n\nExamples:\n\n``` sh\n# Resolve an IP\n$ python3 -m async_dns.resolver www.google.com\n$ python3 -m async_dns.resolver -t mx -- gmail.com\n\n# Query via TCP\n$ python3 -m async_dns.resolver -n tcp://127.0.0.1 -- www.google.com\n\n# Query via TLS\n$ python3 -m async_dns.resolver -n tcps://dns.alidns.com -- www.google.com\n\n# Query from non-standard ports\n$ python3 -m async_dns.resolver -n udp://127.0.0.1:1053 -- www.google.com\n\n# Query from HTTPS\n$ python3 -m async_dns.resolver -n https://dns.alidns.com/dns-query -- www.google.com\n```\n\n**Note:** `--` is required before `hostname`s if the previous option can have multiple arguments.\n\n### Server\n\n```\nusage: python3 -m async_dns.server [-h] [-b BIND] [--hosts HOSTS] [-x [PROXY [PROXY ...]]]\n\nDNS server by Gerald.\n\noptional arguments:\n -h, --help show this help message and exit\n -b BIND, --bind BIND the address for the server to bind\n --hosts HOSTS the path of a hosts file, `none` to disable hosts, `local` to read from\n local hosts file\n -x [PROXY [PROXY ...]], --proxy [PROXY [PROXY ...]]\n the proxy DNS servers, `none` to serve as a recursive server, `default` to\n proxy to default nameservers\n```\n\n**Note:** TLS and HTTPS are not supported in `async_dns` server. Consider [async-doh](https://github.com/gera2ld/async-doh) for DoH server support.\n\nExamples:\n\n``` sh\n# Start a DNS proxy server on :53\n$ python3 -m async_dns.server -b :53 --hosts /etc/hosts\n\n# Start a DNS server over TCP proxy\n$ python3 -m async_dns.server -x tcp://114.114.114.114\n\n# Start a DNS recursive server\n$ python3 -m async_dns.server -x none\n```\n\n## API\n\n``` python\nimport asyncio\nfrom async_dns.core import types\nfrom async_dns.resolver import ProxyResolver\n\nresolver = ProxyResolver()\nres, cached = asyncio.run(resolver.query('www.baidu.com', types.A))\nprint(res)\n```\n\n### Client\n\nThe client sends a request to a remote server and returns the message directly. Unlike resolvers, client does not have a cache and does not modify the response.\n\n```python\nimport asyncio\nfrom async_dns.core import types, Address\nfrom async_dns.resolver import DNSClient\n\nasync def query():\n client = DNSClient()\n res = await client.query('www.google.com', types.A,\n Address.parse('8.8.8.8'))\n print(res)\n print(res.aa)\n\nasyncio.run(query())\n```\n\n### Routing\n\nProxyResolver supports routing based on domains:\n\n```python\nresolver = ProxyResolver(proxies=[\n ('*.lan', ['192.168.1.1']), # query 'udp://192.168.1.1:53' for '*.lan' domains\n (lambda d: d.endswith('.local'), ['tcp://127.0.0.1']), # query tcp://127.0.0.1:53 for domains ending with '.local'\n '8.8.8.8', # equivalent to (None, ['8.8.8.8']), matches all others\n])\n```\n\n## DoH support\n\nThis library contains a simple implementation of DoH (aka DNS over HTTPS) client with partial HTTP protocol implemented.\n\nIf you need a more powerful DoH client based on [aiohttp](https://docs.aiohttp.org/en/stable/), or a DoH server, consider [async-doh](https://github.com/gera2ld/async-doh).\n\n## DNS Spoofing\n\nYou can easily add records to the cache with a hosts file or the cache API.\n\n- Start a server with a custom hosts file:\n\n ```bash\n $ python3 -m async_dns.server -b :53 --hosts /path/to/custom/hosts\n ```\n\n- Add some additional records to a resolver:\n\n ```python\n from async_dns.core import parse_hosts_file, types\n\n for name, qtype, data in parse_hosts_file(hosts):\n resolver.cache.add(name, qtype, data)\n\n resolver.cache.add('www.example.com', types.A, ['127.0.0.1'])\n ```\n\n## Test\n\n```bash\n$ python3 -m unittest\n\n# Or with tox\n$ tox -e py\n```\n\n## Logging\n\nLogging does not work out of the box in v2. It requires at least minimal `logging` configuration.\n\n```py\nlogging.basicConfig(level=logging.INFO)\n```\n\nYou can also add a formatter for the logger:\n\n```py\nimport logging\nfrom async_dns.core import logger\n\nlogger.setLevel(logging.INFO)\nhandler = logging.StreamHandler()\nfmt = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')\nhandler.setFormatter(fmt)\nlogger.addHandler(handler)\n```\n\n## References\n\n- <https://tools.ietf.org/html/rfc1034>\n- <https://tools.ietf.org/html/rfc1035>\n- <https://tools.ietf.org/html/rfc1464> TXT\n- <https://tools.ietf.org/html/rfc2915> NAPTR\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Asynchronous DNS client and server",
"version": "2.0.0",
"project_urls": {
"Homepage": "https://github.com/gera2ld/async_dns",
"Repository": "https://github.com/gera2ld/async_dns"
},
"split_keywords": [
"async",
"dns",
"asyncio"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1b53c105f915ed250f42b6099e5556a075324ef307ed1d3993de85335b513585",
"md5": "8d3a404205405a79463eb0f4e4058250",
"sha256": "a257e47cc64022f95d570a1cd7f5fe90c2d8546b24fbe1049c3980a9a5832b96"
},
"downloads": -1,
"filename": "async_dns-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8d3a404205405a79463eb0f4e4058250",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6,<4.0",
"size": 34289,
"upload_time": "2021-07-22T12:15:19",
"upload_time_iso_8601": "2021-07-22T12:15:19.982207Z",
"url": "https://files.pythonhosted.org/packages/1b/53/c105f915ed250f42b6099e5556a075324ef307ed1d3993de85335b513585/async_dns-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8e4be37f42f7633b3287421545c9dae85cface08d664a638e444953f2b334f6c",
"md5": "8ac690523c741d6402304d47b8c874d9",
"sha256": "8536be11c3789b154472a86db9df5c2149d5466949c78071019bf5edccbb639e"
},
"downloads": -1,
"filename": "async_dns-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "8ac690523c741d6402304d47b8c874d9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6,<4.0",
"size": 27477,
"upload_time": "2021-07-22T12:15:22",
"upload_time_iso_8601": "2021-07-22T12:15:22.955465Z",
"url": "https://files.pythonhosted.org/packages/8e/4b/e37f42f7633b3287421545c9dae85cface08d664a638e444953f2b334f6c/async_dns-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2021-07-22 12:15:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "gera2ld",
"github_project": "async_dns",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "async-dns"
}