39个稳定版本
1.15.0 | 2024年7月22日 |
---|---|
1.14.3 | 2023年9月1日 |
1.14.1 | 2022年7月7日 |
1.14.0 | 2021年11月2日 |
0.0.1 |
|
#85 in Web编程
每月下载 194次
255KB
5.5K SLoC
Constellation
可插拔的权威DNS服务器。可以通过HTTP REST API添加和删除条目。
Constellation是一个小巧的权威服务器,允许您以通用的方式通过HTTP REST API管理DNS条目。它可以插入到现有的基础设施中,以管理您服务的用户DNS记录,例如配置无法在传统DNS服务器中轻松通配符的出站邮件记录(DKIM、DMARC、SPF记录)。
DNS条目存储在Redis中。因此,DNS数据库可以轻松修改和转储以备备份。
在Rust版本1.79.0 (129f3b996 2024-06-10)上测试过。
🇫🇷 在法国安格斯制作。
谁在使用它?
Crisp |
👋 您使用Constellation并希望在列表中列出? 联系我.
功能
- 可插拔的权威DNS服务器,如果您需要为用户生成例如电子邮件子域(带有DKIM、DMARC和SPF记录),它将非常方便。
- HTTP REST API 以在线检查、读取、插入、修改和删除DNS记录。
- 持久层 在Redis中。这意味着您可以在网络上运行多个Constellation,对同一数据库进行操作。您甚至可以分片Redis,如果需要DNS数据存储的容错能力。
- Geo-DNS 基于地理位置提供记录。例如,为所有北美用户提供美国服务器的IP地址,其余的回退到欧洲。基于MaxMind GeoLite2免费数据库,必要时自动更新。
- CNAME扁平化 以节省为用户提供解析往返。这可以按记录设置启用。
支持的记录类型
Constellation支持所有最广泛使用的DNS记录类型
类型 | 支持? | CNAME扁平化? |
---|---|---|
A |
✅ | ✅ |
AAAA |
✅ | ✅ |
CNAME |
✅ | ❌ |
MX |
✅ | ✅ |
TXT |
✅ | ✅ |
CAA |
✅ | ✅ |
PTR |
✅ | ❌ |
👉 如果您希望我添加此处未列出的记录类型支持,请提交一个issue。
如何使用它?
安装
Constellation是用Rust构建的。要安装它,可以下载Constellation发行版页面上的版本,使用cargo install
,或者从master
拉取源代码。
👉 每个发布二进制文件都附带一个.asc
签名文件,可以使用@valeriansaliou GPG公钥进行验证:🔑valeriansaliou.gpg.pub.asc。
从软件包安装
Constellation为基于Debian的系统(Debian、Ubuntu等)提供了预构建的软件包。
重要:目前Constellation仅提供针对Debian 10、11 & 12的64位软件包(代号:buster
、bullseye
& bookworm
)。您仍然可以在其他Debian版本以及Ubuntu上使用它们。
首先,添加Constellation APT仓库(例如,对于Debian bookworm
)
echo "deb [signed-by=/usr/share/keyrings/valeriansaliou_constellation.gpg] https://packagecloud.io/valeriansaliou/constellation/debian/ bookworm main" > /etc/apt/sources.list.d/valeriansaliou_constellation.list
curl -fsSL https://packagecloud.io/valeriansaliou/constellation/gpgkey | gpg --dearmor -o /usr/share/keyrings/valeriansaliou_constellation.gpg
apt-get update
然后,安装Constellation软件包
apt-get install constellation
然后,编辑预填充的Constellation配置文件
nano /etc/constellation.cfg
最后,重新启动Constellation
service constellation restart
从源代码安装
如果您从Git拉取了源代码,可以使用cargo
构建它
cargo build --release
您可以在./target/release
目录中找到构建的二进制文件。
在编译Constellation之前,安装libssl-dev
(即OpenSSL头文件)。SSL依赖对于Geo-DNS数据库更新器和DNS健康检查系统(HTTPS探测器)是必需的。
从Cargo安装
您可以使用cargo install
直接安装Constellation
cargo install constellation-server
确保您的$PATH
已正确配置以源Crate二进制文件,然后使用constellation
命令运行Constellation。
从Docker Hub安装
您可能希望通过Docker运行Constellation。您可以在Docker Hub上找到预构建的Constellation镜像,地址为valeriansaliou/constellation。
预构建的Docker版本可能不是可用的Constellation最新版本。
首先,拉取valeriansaliou/constellation
镜像
docker pull valeriansaliou/constellation:v1.15.0
然后,创建一个配置文件并运行它(将/path/to/your/constellation/config.cfg
替换为您配置文件的路径)
docker run -p 53:53/udp -p 8080:8080 -v /path/to/your/constellation/config.cfg:/etc/constellation.cfg -v /path/to/your/constellation/res/:/var/lib/constellation/ valeriansaliou/constellation:v1.15.0
在配置文件中,请确保
dns.inets
设置为[0.0.0.0:53]
(这允许Constellation DNS从容器外部访问)http.inet
设置为0.0.0.0:8080
(这允许Constellation REST API从容器外部访问)geo.database_path
设置为/var/lib/constellation/geo/
(GeoIP数据库将存储在此处)
星座服务将通过DNS解析器从udp://localhost:53
可访问;其内部REST API可通过https://127.0.0.1:8080
访问。
此外,不要忘记在./res/geo/
文件夹中初始化GeoIP数据库(参考下文的如何初始化GeoIP)。
配置
使用示例配置文件config.cfg,并根据您的环境进行调整。
以下列出了可用的配置选项及其允许值
[server]
log_level
(类型:字符串,允许值:debug
、info
、warn
、error
,默认:error
)—— 日志记录的详细程度,在生产环境中设置为error
。identifier
(类型:字符串,允许值:文本值,默认:constellation/0
)—— 此星座服务器在副本池中的标识符(用于标识和通知目的)。
[dns]
inets
(类型:字符串数组,允许值:IPs + 端口,默认:[0.0.0.0:53, [::]:53]
)—— DNS服务器应监听的宿主机和UDP/TCP端口。tcp_timeout
(类型:整数,允许值:秒,默认:2
)—— DNS通过TCP连接的超时时间。nameservers
(类型:字符串数组,允许值:域名,默认:无默认值)—— 所服务域名的域名服务器。soa_master
(类型:字符串,允许值:域名,默认:无默认值)—— 所服务区域的SOA主域名(主NS服务器的名称)。soa_responsible
(类型:字符串,允许值:作为域名使用的电子邮件地址,默认:无默认值)—— 所服务区域的SOA负责人的电子邮件。soa_refresh
(类型:整数,允许值:秒,默认:10000
)—— SOA记录刷新值。soa_retry
(类型:整数,允许值:秒,默认:2400
)—— SOA记录重试值。soa_expire
(类型:整数,允许值:秒,默认:604800
)—— SOA记录过期值。soa_ttl
(类型:整数,允许值:秒,默认:3600
)—— SOA记录TTL值。record_ttl
(类型:整数,允许值:秒,默认:3600
)—— DNS记录TTL值。
[[dns.zone.'{name}']]
指定您的区域名称,例如:
[[dns.zone.'relay.crisp.chat']]
对于区域基础:relay.crisp.chat
。
resolvers
(类型:字符串数组,允许:主机名,IPv4,IPv6,默认:无默认值)— 在扁平化CNAME记录时应使用的DNS解析器
check_enable
(类型:布尔值,允许:true
,false
,默认:false
)— 是否执行周期性健康检查check_interval
(类型:整数,允许:秒,默认:60
)— 健康检查的间隔时间(建议从1分钟到5分钟)
slack_hook_url
(类型:字符串,允许:URL,默认:无默认值)— 通知的Slack钩子URL(例如:https://hooks.slack.com/[..]
)
zone
(类型:字符串,允许:任何区域根域名,默认:无默认值)— 要检查的区域根域名(例如:relay.crisp.chat
)name
(类型:字符串,允许:区域上的任何子域名,默认:无默认值)— 要检查的区域的子域名(例如:client.@
,对于扩展域名client.relay.crisp.chat
)method
(类型:字符串,允许:HEAD
,GET
,默认:GET
)— HTTP健康探测请求所使用的HTTP方法host
(类型:字符串,允许:HTTP虚拟主机,默认:空)— 检查时请求的HTTP虚拟主机(如果没有设置,则从zone
和name
生成)path
(类型:字符串,允许:HTTP路径,默认:/
)— 检查时请求的HTTP路径port
(类型:整数,允许:TCP端口,默认:443
)— 用于HTTP检查的TCP端口(如果使用HTTP,端口号可能为80
)secure
(类型:布尔值,允许:true
,false
,默认:true
)— 是否通过安全的HTTPS或纯HTTP执行健康检查timeout
(类型:整数,允许:秒,默认:10
)— 单个HTTP检查尝试的超时时间(秒)max_attempts
(类型:整数,允许:数字,默认:3
)— 在健康检查失败的情况下,尝试给定健康检查的最大连续次数(即,既不匹配预期状态也不匹配预期主体的健康检查)expected_status
(类型:整数数组,允许:HTTP状态码,默认:200
)— 预期状态码列表expected_body
(类型:字符串数组,允许:文本值,默认:空)— 预期正文内容列表(子字符串可以包含在响应体中;仅当method
设置为GET
时适用)
[geo]
database_path
(类型:字符串,允许:文件夹路径,默认:./res/geo/
) — 存放 GeoIP 数据库的文件夹路径database_file
(类型:字符串,允许:文件名,默认:GeoLite2-Country.mmdb
) — 数据库文件夹中 GeoIP2 MMDB 数据库的文件名(可以是免费的 GeoLite2 或付费的 GeoIP2;如果想要从远程下载服务器自动更新此文件,请启用geo.update_enable
)update_enable
(类型:布尔值,允许:true
,false
,默认:false
) — 是否启用 GeoIP 数据库更新器update_interval
(类型:整数,允许:秒数,默认:864000
) — GeoIP 数据库刷新的间隔时间(推荐一周或更长时间)update_url
(类型:字符串,允许:HTTP URL,默认:为空) — 压缩的 GeoIP MMDB 文件的 URL(支持:tar.gz
),在刷新时下载(如果启用了geo.update_enable
,则需要此值)
[http]
inet
(类型:字符串,允许:IPv4 / IPv6 + 端口,默认:[::1]:8080
) — HTTP API 服务器应监听的宿主机和 TCP 端口workers
(类型:整数,允许:任何数字,默认:2
) — HTTP API 服务器运行的工人数record_token
(类型:字符串,允许:秘密令牌,默认:无默认值) — 管理API访问的记录秘密令牌(即秘密密码)
[redis]
database
(类型:整数,允许:0
到255
,默认:0
) — 目标 Redis 数据库pool_size
(类型:整数,允许:0
到(2^32)-1
,默认:8
) — Redis 连接池大小max_lifetime_seconds
(类型:整数,允许:秒数,默认:20
) — Redis 连接的最大生命周期(您希望它低于 5 分钟,因为这将影响断开连接时重新连接 Redis 的延迟)idle_timeout_seconds
(类型:整数,允许:秒数,默认:600
) — Redis 空闲/死连接的超时时间connection_timeout_seconds
(类型:整数,允许:秒数,默认:2
) — Redis 死连接的秒数超时,拒绝 DNS 和 HTTP API 查询delinquency_seconds
(类型:整数,允许:秒数,默认:10
) — 标记失败的 Redis 连接为欠款的秒数,这意味着在故障期间不会反复尝试。它应该是连接超时的一个因子,建议的因子是 3。cache_refresh_seconds
(类型:整数,允许:秒,默认:60
)— 在本地缓存的记录从Redis刷新后的秒数(应保持较低值)cache_expire_seconds
(类型:整数,允许:秒,默认:600
)— 本地缓存的记录在Redis中过期后应刷新的秒数(应保持较低值)
host
(类型:字符串,允许:主机名,IPv4,IPv6,默认:localhost
)— 目标主Redis主机port
(类型:整数,允许:TCP端口,默认:6379
)— 目标主Redis TCP端口password
(类型:字符串,允许:密码值,默认:无) — 主Redis密码(如果没有密码,不要设置此键)
host
(类型:字符串,允许:主机名,IPv4,IPv6,默认:localhost
)— 只读救援Redis主机port
(类型:整数,允许:TCP端口,默认:6379
)— 只读救援Redis TCP端口password
(类型:字符串,允许:密码值,默认:无) — 只读救援Redis密码(如果没有密码,不要设置此键)
初始化GeoIP
由于Constellation在其仓库中没有分发GeoIP数据库,您在第一次运行Constellation之前需要从MaxMind获取它(否则Constellation将拒绝启动)。
执行提供的脚本
./scripts/init_geoip.sh --许可证密钥=YOUR_GEOLITE2_LICENSE_KEY
YOUR_GEOLITE2_LICENSE_KEY应替换为有效的GeoLite2许可证密钥。请遵循MaxMind提供的说明以获取许可证密钥。
请注意,一旦Constellation从您手动初始化的GeoIP数据库启动,它将通过在后台自动检查和应用更新来保持数据库的最新状态。数据库初始化是一次性操作。请确保您的许可证密钥也设置在配置中的GeoIP更新URL。
运行Constellation
Constellation可以这样运行
./constellation -c/path/to/config.cfg
测试Constellation
运行后,可以在本地网络中对Constellation进行DNS查询(使用默认配置)
dig subdomain.中继.crisp.聊天@::1
请注意,可以使用dig
实用工具通过@
修饰符指向特定服务器,这里使用IPv6 localhost: ::1
。
🛰 HTTP REST API
Constellation HTTP REST API监听配置文件config.cfg
中的http.inet
接口。您可以使用它来满足您的管理和监控需求。
如果您想轻松地尝试API,一个最新的Paw文件包含所有API路由和示例请求。在此处下载适用于您的Mac的Paw应用程序(Paw是开发者用来测试他们API的工具)。
1. DNS记录管理
要检查、读取、插入、修改和删除DNS记录,您可以使用zone
API资源。
API概述
端点URL
HTTPhttp://constellation.local:8080/zone/<zone_name>/record/<record_name>/<record_type>/
其中
zone_name
:区域名称(即基础域名),例如:relay.crisp.chat
record_name
:要读取或修改的记录名称(即子域名或基础域名),例如:client.@
对于client.relay.crisp.chat
FQDN,或@
对于relay.crisp.chat
FQDNrecord_type
:要读取或修改record_name
的 DNS 记录类型;可以是:a
、aaaa
、cname
、mx
、txt
、caa
或ptr
(如果您需要其他记录类型支持,请提交问题)
请求头
- 添加一个带有
Authorization
的请求头,使用Basic
认证,密码为您的配置http.record_token
。
Geo-DNS 区域
如果您想使用 Geo-DNS 功能向最近的服务器提供记录,您将需要通过 API 设置 regions
,其中
-
美洲
nnam
:北美北部snam
:北美南部nsam
:南美北部ssam
:南美南部
-
欧洲
weu
:西欧ceu
:中欧eeu
:东欧ru
:俄罗斯
-
中东
me
:中东
-
非洲
naf
:北非maf
:中非saf
:南非
-
亚洲
in
:印度seas
:东南亚neas
:东北亚
-
大洋洲
oc
:大洋洲
Geo-DNS 黑洞
如果您想使用 Geo-DNS 功能针对被阻止的国家返回空的 DNS 响应,您将需要通过 API 设置 blackhole
,为一个黑名单 ISO-3166 Alpha-2 国家代码 列表(例如,FR
代表法国)。
健康检查的救援记录
如果您正在对区域域使用健康检查,您可能需要指定救援记录,在所有常规记录(标准和 Geo-DNS)都被视为无效的情况下,这些记录将被提供给 DNS 客户端。您可以在 API 中设置 rescue
属性以确保在默认服务器失败的情况下,只有故障转移服务器被提供并连接。
如果您没有设置任何 rescue
记录;在所有常规记录都被报告为无效的情况下,DNS 客户端将收到一个空的响应。因此,您仍然应该提供备用记录。
CNAME 层叠
CNAME记录可以方便地在单个DNS条目中集中记录值,并在多个DNS CNAME条目中重复使用。然而,它也有一些限制,例如,按照DNS RFC规定,它不能与同一子域上的其他记录共享。在域根目录下设置CNAME也是非法的。此外,CNAME需要DNS解析器执行第二次解析步骤来解析平面值(例如,A
、AAAA
、TXT
等记录),这并不高效,因为它增加了用户通过CNAME解析域名时的额外延迟。
如果遇到DNS RFC中CNAME记录类型的边缘情况,CNAME扁平化可以帮助您。它允许Constellation解析实际平面值,并立即提供服务,而不是返回实际的CNAME。可以通过在API中将flatten
属性设置为true
来为记录启用CNAME扁平化。默认情况下,不执行CNAME扁平化。
一个专门的Constellation线程管理之前扁平化的CNAME值,并随着它们在远程DNS服务器上的更改而更新它们。此外,如果缓存的扁平化CNAME长时间未使用,则将其从缓存中删除。请注意,为了尽快响应用户,如果启用扁平化的CNAME值尚未在缓存中,则Constellation将以CNAME的形式回答,并将延迟扁平化命令委托给扁平化管理线程,以避免减慢对请求用户的初始响应。一旦扁平化管理线程完成其工作,进一步的DNS查询到CNAME将使用扁平化的值回答(例如,它将返回平面A
记录值,而不是CNAME
值)。
请注意,flatten
选项仅适用于具有CNAME值的记录。如果在例如A
记录类型上启用了扁平化,则flatten
属性将没有任何效果。
API路由
检查DNS记录是否存在
HTTP HEADhttp://constellation.local:8080/zone/<zone_name>/record/<record_name>/<record_type>/
示例请求
HEAD /zone/relay.crisp.chat/record/@/a HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
示例响应
HTTP/1.1 200 OK
获取DNS记录
HTTP GEThttp://constellation.local:8080/zone/<zone_name>/record/<record_name>/<record_type>/
示例请求
GET /zone/relay.crisp.chat/record/@/a HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
示例响应
HTTP/1.1 200 OK
Content-Type: application/json
{"type":"a","name":"@","ttl":600,"blackhole": null,"regions": null,"values":["159.89.97.13","46.101.18.133"]}
写入DNS记录(或覆盖现有记录)
HTTP PUThttp://constellation.local:8080/zone/<zone_name>/record/<record_name>/<record_type>/
示例请求(标准)
PUT /zone/relay.crisp.chat/record/@/a HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
Content-Type: application/json; charset=utf-8
{"values":["159.89.97.13","46.101.18.133"],"ttl":600}
示例请求(地理DNS)
PUT /zone/relay.crisp.chat/record/@/cname HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
Content-Type: application/json; charset=utf-8
{"regions":{"nnam":["client.nnam.geo.relay.crisp.net"],"snam":["client.snam.geo.relay.crisp.net"],"nsam":["client.nsam.geo.relay.crisp.net"],"ssam":["client.ssam.geo.relay.crisp.net"],"weu":["client.weu.geo.relay.crisp.net"],"ceu":["client.ceu.geo.relay.crisp.net"],"eeu":["client.eeu.geo.relay.crisp.net"],"ru":["client.ru.geo.relay.crisp.net"],"me":["client.me.geo.relay.crisp.net"],"naf":["client.naf.geo.relay.crisp.net"],"maf":["client.maf.geo.relay.crisp.net"],"saf":["client.saf.geo.relay.crisp.net"],"in":["client.in.geo.relay.crisp.net"],"seas":["client.seas.geo.relay.crisp.net"],"neas":["client.neas.geo.relay.crisp.net"],"oc":["client.oc.geo.relay.crisp.net"]},"values":["client.default.geo.relay.crisp.net"],"ttl":600}
示例请求(健康检查)
PUT /zone/relay.crisp.chat/record/@/a HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
Content-Type: application/json; charset=utf-8
{"values":["159.89.97.13","46.101.18.133"],"rescue":["139.59.174.13"],"ttl":60}
示例响应
HTTP/1.1 200 OK
示例请求(CNAME扁平化)
PUT /zone/relay.crisp.chat/record/@/cname HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
Content-Type: application/json; charset=utf-8
{"values":["alias.crisp.net"],"flatten":true,"ttl":60}
示例响应
HTTP/1.1 200 OK
删除DNS记录
HTTP DELETEhttp://constellation.local:8080/zone/<zone_name>/record/<record_name>/<record_type>/
示例请求
DELETE /zone/relay.crisp.chat/record/@/a HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
示例响应
HTTP/1.1 200 OK
2. 服务器使用情况指标检索
要获取服务器使用情况指标(例如,哪些国家的DNS请求),您可以使用metrics
API资源。
API概述
端点URL
HTTPhttp://constellation.local:8080/zone/<zone_name>/metrics/<metrics_timespan>/<metrics_category>/<metrics_type>
其中
zone_name
:区域名称(即基础域名),例如:relay.crisp.chat
metrics_timespan
:返回指标的时长(可以是:1m
、5m
或15m
),代表:过去'n分钟'的指标metrics_category
:指标类别(可以是:query
或answer
)metrics_type
:类别中的指标类型(如果类别是query
,则为types
或origins
,如果类别是answer
,则为codes
)
请求头
- 添加一个带有
Authorization
的请求头,使用Basic
认证,密码为您的配置http.record_token
。
API路由
获取指标
HTTP GEThttp://constellation.local:8080/zone/<zone_name>/metrics/<metrics_timespan>/<metrics_category>/<metrics_type>/
示例请求
GET /zone/relay.crisp.chat/metrics/5m/query/origins HTTP/1.1
Authorization: Basic OlJFUExBQ0VfVEhJU19XSVRIX0FfU0VDUkVUX0tFWQ==
示例响应
HTTP/1.1 200 OK
Content-Type: application/json
{"fr":1203,"us":899,"lv":23,"gb":10,"other":2}
🔥 报告漏洞
如果您在Constellation中发现漏洞,您非常欢迎通过发送加密电子邮件到[email protected]直接向@valeriansaliou报告。请不要在公共GitHub问题中报告漏洞,因为恶意人员可能会利用这些漏洞针对运行未打补丁的Constellation实例的生产服务器。
⚠️ 您必须使用 @valeriansaliou GPG 公钥加密您的电子邮件:🔑valeriansaliou.gpg.pub.asc。
依赖项
~33–47MB
~1M SLoC