Skip to main content

有条件地重写和过滤 A 记录请求的 DNS 代理服务器

项目描述

dns 重写代理圈子CI 测试覆盖率

有条件地重写和过滤 A 记录请求的 DNS 代理服务器。用 Python 编写,所有代码都在一个模块中,并且有一个依赖项 aiodnsresolver

CNAME 由代理跟踪并解析为 IP 地址,并且永远不会返回给客户端。

安装

pip install dnsrewriteproxy

用法

默认情况下,代理将侦听端口 53,并将请求代理到/etc/resolv.conf. 但是,默认情况下,所有请求都会在没有明确规则的情况下被阻止,因此对于代理请求,您必须至少配置一个重写规则。

from dnsrewriteproxy import DnsProxy

# Proxy all incoming A record requests without any rewriting
start = DnsProxy(rules=((r'(^.*$)', r'\1'),))

# Run proxy, accepting UDP requests on port 53
await start()

rules参数必须是元组的可迭代[例如列表或元组],其中每个元组是正则表达式模式/替换对,在后台传递给re.subn。在来自域的下游的每个传入 DNS 请求上

  • 这个列表被迭代;
  • 第一条匹配传入域名的规则用于改写域,向上游DNS服务器查询A记录,下游返回这些记录或错误码;
  • 如果没有规则匹配,则下游返回 REFUSED 响应。

REFUSED 的响应是为了让客户端能够帮助区分代理上的配置问题、代理不工作或不可联系,以及域实际上不存在。

www.source.com因此,要重写to的所有查询www.target.com,并拒绝代理任何其他查询,您可以使用以下配置。

start = DnsProxy(rules=(
    (r'^www\.source\.com$', r'www.target.com'),
))

或者,进行相同的重写,但要允许所有其他请求,您可以使用以下内容。

start = DnsProxy(rules=(
    (r'^www\.source\.com$', r'www.target.com'),
    (r'(^.*$)', r'\1'),
))

要代理到 中指定的服务器以外的服务器/etc/resolv.conf,您可以通过自定义Resolver传递get_resolver

from aiodnsresolver import Resolver
from dnsrewriteproxy import DnsProxy

def get_resolver():
    async def get_nameservers(_, __):
        for _ in range(0, 5):
            yield (0.5, ('8.8.8.8', 53))
    return Resolver(get_nameserver=get_nameservers)

start = DnsProxy(
    rules=((r'(^.*$)', r'\1'),),
    get_resolver=get_resolver,
)

服务器生命周期

在上面的例子await start()中,服务器刚刚开始监听就完成了。协程start返回底层任务以控制服务器生命周期。一个任务可以看作是一个“异步线程”;这被暴露以允许服务器坐在一个更大的 asyncio Python 程序中,该程序可能具有特定的启动/关闭过程。

永远奔跑

通过等待此任务,您可以永远运行服务器[或直到它遇到一些不可恢复的错误]。

from dnsrewriteproxy import DnsProxy

start = DnsProxy(rules=((r'(^.*$)', r'\1'),))
server_task = await start()

# Waiting here until the server is stopped
await server_task

停止服务器

要停止服务器,您可以cancel返回任务。

from dnsrewriteproxy import DnsProxy

start = DnsProxy(rules=((r'(^.*$)', r'\1'),))
proxy_task = await start()

# ... Receive requests

# Initiate stopping: new requests will not be processed...
proxy_task.cancel()

try:
    # ... and we wait until previously received requests have been processed
    await proxy_task
except asyncio.CancelledError:
    pass

优雅关机示例

下面是一个在 SIGINT 或 SIGTERM 上进行正常关闭的服务器的完整示例。

import asyncio
import signal

from dnsrewriteproxy import (
    DnsProxy,
)

async def async_main():
    start = DnsProxy(rules=((r'(^.*$)', r'\1'),))
    proxy_task = await start()

    loop = asyncio.get_running_loop()
    loop.add_signal_handler(signal.SIGINT, proxy_task.cancel)
    loop.add_signal_handler(signal.SIGTERM, proxy_task.cancel)

    try:
        await proxy_task
    except asyncio.CancelledError:
        pass

asyncio.run(async_main())
print('End of program')

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

dnsrewriteproxy-0.0.16.tar.gz (5.6 kB 查看哈希

已上传 source

内置分布

dnsrewriteproxy-0.0.16-py3-none-any.whl (6.5 kB 查看哈希

已上传 py3