resolve

CoreDNS 插件:为 HTTPS (DoH) 服务器提供 /resolve JSON 解析接口,支持 EDNS0 Client Subnet。

编译安装

前置条件

  • Go 1.21+
  • CoreDNS 源码
1
2
3
# 克隆 CoreDNS 源码
git clone https://github.com/coredns/coredns.git coredns
cd coredns

1. 克隆插件

1
git clone https://github.com/qist/resolve.git plugin/resolve

2. 应用上游补丁

1
2
cd  coredns
git apply --3way plugin/resolve/server_https.patch

补丁修改以下文件:

  • core/dnsserver/server_https.go — 新增 /resolve 处理、EDNS0 Client Subnet 注入
  • core/dnsserver/config.go — 新增 ResolveEDNS0 配置字段

3. 注册插件到 plugin.cfg

1
2
3
# 在 https3 行后添加 edns0 和 resolve 指令
#sed -i '/^https3:https3$/a edns0:resolve\nresolve:resolve' plugin.cfg
补丁里面添加了 不需要 手动添加

验证:

1
2
3
4
grep -n "edns0\|resolve" plugin.cfg
# 应输出:
# 32:edns0:resolve
# 33:resolve:resolve

4. 生成代码并编译

1
2
3
4
5
6
7
8
# 生成 zplugin.go 和 zdirectives.go
go generate

# 编译
go build -o coredns .

# 验证二进制包含 resolve 插件
strings ./coredns | grep "resolve" | head -3

5. 安装

1
2
3
4
# 替换原有二进制
cp coredns /usr/local/bin/coredns
# 或
cp coredns /opt/coredns/coredns

配置

Corefile

1
2
# 自动添加到 Corefile 的 https server block
sed -i '/tls .*/a\ edns0 on\n resolve' /path/to/Corefile

完整配置:

1
2
3
4
5
6
7
8
9
10
https://.:443 {
tls /path/to/fullchain.crt /path/to/private.key
edns0 on
resolve
forward . 8.8.8.8 1.1.1.1 223.5.5.5 {
max_concurrent 1000
}
log
errors
}

指令说明

指令 说明
resolve 启用 /resolve JSON 接口
edns0 on 自动注入 EDNS0 Client Subnet(默认)
edns0 off 关闭自动注入,仅 cip 参数生效

接口

GET /resolve

1
GET /resolve?name=<domain>&type=<rrtype>&cip=<client_ip>
参数 必填 说明 示例
name 查询域名 example.com
type 记录类型,默认 A AAAAMXCNAMENSTXTSRV
cip 客户端 IP,用于 EDNS0 Client Subnet 8.8.8.8

响应格式

成功(200):

1
2
3
4
5
6
7
8
9
10
{
"Name": "www.qq.com.",
"Type": "A",
"Status": 0,
"TTL": 30,
"Answer": [
{"name": "www.qq.com.", "type": "CNAME", "ttl": 30, "data": "www.qq.com.eo.dnse2.com."},
{"name": "www.qq.com.eo.dnse2.com.", "type": "A", "ttl": 30, "data": "43.159.109.55"}
]
}

错误(400/405/500):

1
{"Error": "missing required 'name' parameter"}

字段说明

字段 类型 说明
Name string 查询域名(FQDN)
Type string 查询记录类型
Status int DNS 响应码(0=成功,3=NXDOMAIN)
TTL uint32 最小 TTL,无记录时为 0
Answer array 解析记录列表
Answer[].name string 记录名称
Answer[].type string 记录类型
Answer[].ttl uint32 记录 TTL
Answer[].data string 记录数据

EDNS0 Client Subnet

行为

默认开启(不写 edns0 指令等同于 edns0 on)。

edns0 cip /resolve /dns-query
on(默认) 自动提取客户端 IP 自动提取客户端 IP
on(默认) 以 cip 为准 自动提取客户端 IP
off 不注入 不注入
off 以 cip 为准 不注入

客户端 IP 优先级

  1. cip 查询参数(仅 /resolve
  2. X-Forwarded-For 头(取第一个 IP)
  3. X-Real-IP
  4. 连接 RemoteAddr

子网掩码

协议 掩码
IPv4 /24
IPv6 /48

反向代理

Nginx 传递真实客户端 IP:

1
2
3
4
5
location /resolve {
proxy_pass https://coredns:443;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
# 基本查询
curl -sk "https://localhost:443/resolve?name=example.com"

# 指定记录类型
curl -sk "https://localhost:443/resolve?name=example.com&type=AAAA"

# 指定客户端 IP(EDNS0 Client Subnet)
curl -sk "https://localhost:443/resolve?name=example.com&cip=8.8.8.8"

# 格式化输出
curl -sk "https://localhost:443/resolve?name=example.com" | python3 -m json.tool
curl -sk "https://localhost:443/resolve?name=example.com" | jq .

卸载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 从 plugin.cfg 移除
sed -i '/^edns0:resolve$/d; /^resolve:resolve$/d' plugin.cfg

# 2. 从 Corefile 移除
sed -i '/edns0/d; /resolve/d' Corefile

# 3. 回退上游补丁
git apply -R plugin/resolve/server_https.patch

# 4. 删除插件目录
rm -rf plugin/resolve

# 5. 重新编译
go generate && go build

文件说明

1
2
3
4
5
plugin/resolve/
├── README.md # 本文档
├── setup.go # 注册 resolve + edns0 指令,包装 validator
├── resolve.go # 透传 handler(实现 plugin.Handler 接口)
└── server_https.patch # 上游补丁

server_https.patch 改动

文件 行数 改动
core/dnsserver/config.go +3 新增 ResolveEDNS0 bool 字段
core/dnsserver/register.go +1 默认 ResolveEDNS0: true
core/dnsserver/server_https.go +236 serveResolve()、addECSFromHTTP()、clientIPFromRequest()、resolveEDNS0()
plugin.cfg +2 edns0:resolveresolve:resolve

hostlist

概述

hostlist 是一个 CoreDNS 插件,使用 AdGuard HostlistsRegistry 格式的规则进行 DNS 域名过滤。支持黑名单/白名单两种模式,远程规则自动同步,本地缓存。

插件在 tsig 之后执行,优先级高于测速、缓存等插件。

特性

  • 支持 AdGuard 全部 DNS 过滤规则格式
  • 黑名单模式(封锁匹配域名)和白名单模式(仅放行匹配域名)
  • 远程 URL 和本地文件两种规则来源
  • 定时自动同步远程规则,支持本地缓存
  • 反向标签 trie 数据结构,50 万+ 域名毫秒级匹配
  • 用户自定义黑白名单,不受远程更新影响

Corefile 语法

1
2
3
4
5
6
7
8
9
10
11
12
hostlist {
url <remote-url> # 远程规则 URL(可重复)
file <local-path> # 本地规则文件(可重复)
whitelist_url <remote-url> # 远程白名单 URL(可重复)
whitelist_file <local-path> # 本地白名单文件(可重复)
allowlist <rule> # 用户白名单规则(可重复)
blocklist <rule> # 用户黑名单规则(可重复)
mode blacklist|whitelist # 模式,默认 blacklist
block_type 0.0.0.0|nxdomain|empty # 拦截响应类型,默认 0.0.0.0
refresh <duration> # 远程同步间隔,默认 4d
cache_dir <path> # 缓存目录,默认 ./hostlist/
}

示例配置

基础配置

1
2
3
4
5
6
7
8
9
. {
hostlist {
url https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
url https://adguardteam.github.io/HostlistsRegistry/assets/filter_21.txt
file /etc/coredns/custom_blocklist.txt
refresh 12h
}
forward . 8.8.8.8:53
}

完整配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
. {
hostlist {
# 黑名单来源
url https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
url https://adguardteam.github.io/HostlistsRegistry/assets/filter_29.txt
file /etc/coredns/custom_blocklist.txt

# 白名单来源(整份文件所有规则作为白名单)
whitelist_url https://example.com/my_allowlist.txt
whitelist_file /etc/coredns/allowlist.txt

# 用户自定义规则(不受远程更新影响)
allowlist @@||www.youtube.com^
allowlist @@||m.youtube.com^
blocklist ||ads.example.com^
blocklist ||tracker.myapp.com^

# 设置
mode blacklist
block_type nxdomain
refresh 12h
cache_dir /var/lib/coredns/hostlist
}
forward . 8.8.8.8:53
log
}

白名单模式

1
2
3
4
5
6
7
. {
hostlist {
url https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
mode whitelist
}
forward . 8.8.8.8:53
}

白名单模式下,仅放行规则列表中的域名,其他全部拦截。

规则格式

封锁规则

格式 示例 说明
||domain^ ||ads.example.com^ 封锁域名及所有子域名
127.0.0.1 domain 127.0.0.1 analytics.163.com 仅封锁精确域名,不含子域名
/REGEX/ /^ads\d*\./ 正则匹配封锁
||*wild*domain^ ||*serror*.wo.com.cn^ 通配符,自动转正则
.domain^ .bbelements.com^ 封锁域名及子域名
domain wykop.pl 封锁域名

白名单规则

格式 示例 说明
@@||domain^ @@||youtube.com^ 放行域名及所有子域名
@@|domain^ @@|affiliate.notion.so^ 放行(单锚点)
@@||domain^| @@||sedge.nfl.com^| 放行(末尾多余 |
@@/REGEX/ @@/^safe\./ 正则匹配放行

修饰符

修饰符 行为
$important 正常处理(剥离修饰符)
$badfilter 跳过(禁用其他规则,不适用)
$dnsrewrite 跳过(DNS 重写,不适用)

注释

1
2
! 这是注释
# 这也是注释

行为说明

黑名单模式(默认)

  • 匹配 url/file 中的封锁规则 → 拦截
  • 匹配 @@/whitelist_url/whitelist_file 中的白名单规则 → 放行
  • 匹配 allowlist 中的用户白名单 → 放行
  • 匹配 blocklist 中的用户黑名单 → 拦截
  • 白名单优先级高于黑名单
  • 其他域名 → 放行

白名单模式

  • 匹配 url/file 中的规则 → 放行
  • 其他域名 → 拦截

拦截响应

  • block_type 0.0.0.0(默认):返回 NOERROR + A 记录 0.0.0.0
  • block_type nxdomain:返回 NXDOMAIN + SOA
  • block_type empty:返回 NOERROR,无应答记录

域名匹配

  • ||domain^ 格式:祖先匹配,封锁 domain 及所有子域名
  • hosts 格式(127.0.0.1 domain):精确匹配,仅封锁 domain 本身
  • 白名单 @@||domain^:祖先匹配,放行 domain 及所有子域名

远程同步

  • 启动时立即加载所有规则
  • refresh 间隔定时重新下载远程规则
  • 下载失败时使用本地缓存文件
  • 所有错误(网络超时、文件不存在等)均跳过,不影响进程

缓存目录

远程下载的规则会保存到 cache_dir 目录(默认 ./hostlist/),文件名为 URL 的 SHA256 哈希。重启时优先读取本地缓存,后台再同步远程更新。

Prometheus 指标

指标 类型 说明
coredns_hostlist_blocked_requests_total Counter 被拦截的请求数(标签:server, zone)
coredns_hostlist_domains_loaded Gauge 当前加载的封锁域名数

编译

1. 克隆 CoreDNS 源码

1
2
git clone https://github.com/coredns/coredns.git
cd coredns

2. 添加 hostlist 插件

1
git clone https://github.com/qist/hostlist.git plugin/hostlist

3. 注册插件

1
grep -q '^hostlist:hostlist' plugin.cfg || sed -i '/^tsig:tsig$/a hostlist:hostlist' plugin.cfg

这会在 tsig:tsig 之后插入 hostlist:hostlist,如果已存在则跳过。

4. 生成代码并编译

1
2
go generate
go build -o coredns .

5. 验证

1
2
./coredns -version
./coredns -plugins | grep hostlist

使用 Go module 方式添加

如果需要以 module 方式引入(适用于 CoreDNS 自定义构建):

1
2
3
4
# 在 CoreDNS 项目根目录
go mod edit -require github.com/qist/hostlist@latest
go mod edit -replace github.com/qist/hostlist=./plugin/hostlist
go mod tidy

然后在 plugin.cfg 中使用完整包路径:

1
hostlist:github.com/qist/hostlist

CoreDNS 测速插件 speedcheck

Name

coredns 上游可用性探测插件返回最快IP

speedcheck - 对上游返回的多个 IP 做探测并返回最快的一个 IP。

Description

speedcheck 拦截包含 A/AAAA 记录的 DNS 应答,对每个候选 IP 执行连通性探测(ICMP ping / TCP 连接 / HTTP 请求),从中选出最快的一个返回给客户端。

探测流程:

  1. 向上游转发请求,获取原始应答
  2. 从应答中提取 A/AAAA 记录的 IP 列表
  3. 并发探测所有 IP(受并发上限控制,默认最多 32 个)
  4. 根据 speed-ip-mode 的家族偏好选择最优 IP
  5. 将应答收敛为单个最优 IP 返回

当所有探测均失败时,优先回落到 IPv4 地址;若无 IPv4 则随机返回一个 IP。

Syntax

1
2
3
4
5
6
7
8
9
10
11
speedcheck {
speed-check-mode ping,tcp:80,tcp:443
speed-timeout-mode 3s
speed-check-parallel off
speed-cache-ttl 30s
speed-ip-mode ipv4,ipv6
speed-ip-parallel off
speed-host-override *.example.com|tcp:443,http:443|ipv4,ipv6
check_http_send "HEAD / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n"
check_http_expect_alive http_2xx http_3xx http_4xx
}

speed-check-mode

探测模式,支持 none / ping / tcp:<port> / http:<port>,可用逗号组合多种模式。

  • 包含 ping 时:先做 ICMP ping;ping 成功则该 IP 视为成功(仍会继续尝试 tcp/http,但 tcp/http 全失败时仍按 ping 成功处理);ping 失败则继续尝试 tcp/http,任意一个成功即短路
  • 仅配置 ping:只做 ICMP ping 探测
  • 不包含 ping:按配置顺序尝试 tcp/http,任意一个成功即短路
  • 配置为 none:禁用探测(仅在 speed-host-override 中有意义)

speed-timeout-mode

单次探测超时时间,默认 2s

speed-check-parallel

是否并发执行同一 IP 的 tcp/http 探测(on / off),默认 off

开启后所有 tcp/http 探测同时发起,任意一个成功即短路返回,适合目标端口响应差异较大的场景。

speed-cache-ttl

缓存探测结果的时间(按 域名+查询类型 缓存),默认 0(关闭)。过期条目在访问时自动清理。

speed-ip-mode

IP 家族优先级,默认 ipv6,ipv4(优先 IPv6)。

含义
ipv6,ipv4 优先 IPv6,IPv6 全部失败时回落到 IPv4
ipv4,ipv6 优先 IPv4,IPv4 全部失败时回落到 IPv6
ipv4 仅使用 IPv4
ipv6 仅使用 IPv6

speed-ip-parallel

是否并发竞速 v4/v6(on / off),默认 off

开启后忽略 speed-ip-mode 的家族优先级,将所有 A/AAAA 的 IP 合并后并发探测,返回最先成功的 IP。当查询类型为 AAAA 且 IPv4 获胜时,返回空 AAAA(促使客户端回落使用 A 记录)。

speed-host-override

按域名覆盖探测模式与 IP 家族选择,可配置多条。支持精确匹配和泛域名匹配。

语法

推荐语法(管道分隔,避免逗号歧义):

1
speed-host-override <host>|<check-mode>|<ip-mode>

兼容语法(逗号或空格分隔,不推荐用于多探测项):

1
2
speed-host-override <host>,<check-mode>,<ip-mode>
speed-host-override <host> <check-mode> <ip-mode>

泛域名

使用 * 前缀匹配所有子域名,逐级向上查找:

配置 foo.example.com a.b.example.com example.com
*.example.com 匹配 匹配 不匹配
*.b.example.com 不匹配 匹配 不匹配

精确匹配优先于泛域名匹配。

ip-mode 详解

行为
ipv4 / v4 仅保留 A 记录;AAAA 查询返回空(促使客户端回落)
ipv6 / v6 仅保留 AAAA 记录;A 查询返回空
ipv4,ipv6 优先 IPv4,IPv4 失败时允许回落到 IPv6
ipv6,ipv4 优先 IPv6,IPv6 失败时允许回落到 IPv4

check-mode 为 none 时

不做任何探测,也不收敛多 IP 为单 IP,仅按 ip-mode 做 A/AAAA 的保留或清空。适用于强制客户端走指定协议家族的场景。

命中 override 后的行为

  • 使用该域名专属的 check-modeip-mode
  • 禁用 speed-ip-parallel 的 v4/v6 竞速

check_http_send

自定义 HTTP/1.x 探测报文。{host} / {HOST} 会被替换为当前 DNS 查询域名。默认值:

1
GET / HTTP/1.0\r\n\r\n

check_http_expect_alive

HTTP 探测可接受的状态码分类,可多选:

  • http_2xx / http_3xx / http_4xx / http_5xx
  • http_all:接受所有状态码

默认接受所有状态码。

Examples

基础配置

1
2
3
4
5
6
7
8
9
. {
speedcheck {
speed-check-mode ping,tcp:80,tcp:443
speed-timeout-mode 3s
speed-cache-ttl 30s
speed-ip-mode ipv6,ipv4
}
forward . 8.8.8.8
}

HTTP 探测

http:443 会并发尝试 HTTPS/1.x 与 HTTP/3,取更快的一个:

1
2
3
4
5
6
7
8
. {
speedcheck {
speed-check-mode ping,http:80,http:443
speed-timeout-mode 2s
check_http_expect_alive http_2xx http_3xx
}
forward . 8.8.8.8
}

泛域名覆盖

对所有 Google 域名强制 IPv4,对 CDN 域名使用 HTTP 探测:

1
2
3
4
5
6
7
8
9
. {
speedcheck {
speed-check-mode ping,tcp:443
speed-timeout-mode 2s
speed-host-override *.google.com|tcp:443|ipv4
speed-host-override *.cdn.example.com|http:443|ipv6,ipv4
}
forward . 8.8.8.8
}

强制协议家族

对特定域名不做探测,仅强制使用 IPv4:

1
2
3
4
5
6
7
. {
speedcheck {
speed-check-mode ping,tcp:443
speed-host-override legacy.example.org|none|ipv4
}
forward . 8.8.8.8
}

并发竞速模式

开启 v4/v6 竞速,返回最快响应的 IP:

1
2
3
4
5
6
7
8
9
. {
speedcheck {
speed-check-mode tcp:443
speed-timeout-mode 2s
speed-ip-parallel on
speed-check-parallel on
}
forward . 8.8.8.8
}

Notes

  • ICMP ping 需要 CAP_NET_RAW 权限或 root 权限;缺少权限时 ping 探测会静默失败,不影响其他探测模式
  • http:443 探测会并发尝试 HTTPS/1.x 和 HTTP/3(QUIC),取先成功的结果
  • 探测连接不复用,每次探测都是新建连接,以准确测量连接建立延迟
  • 缓存按 域名+查询类型 存储,过期条目在访问时自动清理
  • 探测并发上限为 32 个 IP;超出时排队等待,防止协程爆炸

Build

  1. 拉取 CoreDNS 源码:
1
2
git clone https://github.com/coredns/coredns.git
cd coredns
  1. plugin.cfg 增加一行(建议放到 cache:cache 前面):
1
2
# 使用 sed 自动添加到 cache:cache 前面
sed -i '/^cache:cache$/i\speedcheck:speedcheck' plugin.cfg
  1. 拉取 speedcheck 模块源码:
1
2
cd coredns
git clone https://github.com/qist/speedcheck.git plugin/speedcheck
  1. 重新生成插件注册代码并编译:
1
2
go generate coredns.go
make

交叉编译(Linux arm64):

1
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o coredns-linux-arm64

WSL DNS PATH 配置

本文档用于说明 WSL(Windows Subsystem for Linux)中 /etc/wsl.conf 文件内各配置项的作用及影响。

配置如下:

1
2
3
4
5
[network]
generateResolvConf = false

[interop]
appendWindowsPath = false

一、[network] 网络相关配置

generateResolvConf = false

作用:
禁止 WSL 在启动时自动生成 /etc/resolv.conf 文件。

默认行为(true):

  • WSL 启动时会根据 Windows 当前网络状态自动生成 /etc/resolv.conf
  • 通常使用 Windows 的 DNS(例如 VPN 或公司内网 DNS)

设置为 false 后:

  • 不再自动覆盖 /etc/resolv.conf
  • DNS 完全由用户手动维护
  • 适用于代理、IPTV、Docker、服务器等场景

示例:

1
2
nameserver 1.1.1.1
nameserver 8.8.8.8

二、[interop] Windows 与 Linux 互操作

appendWindowsPath = false

作用:
禁止将 Windows 的 PATH 环境变量追加到 WSL 的 PATH 中。

默认行为(true):

  • Windows 的可执行程序会出现在 WSL 的 PATH 中
  • 可能导致命令冲突(如 curl、git)

设置为 false 后:

  • 仅使用 Linux 自身的 PATH
  • 环境更干净、稳定
  • 适合开发与服务器运行环境

三、配置生效

修改 /etc/wsl.conf 后执行:

1
wsl --shutdown

重新进入 WSL 后配置生效。

本文档介绍如何在 Linux 系统上编译支持 HTTP/3 的 cURL,依赖 quictls OpenSSL、nghttp3 和 ngtcp2。


0. 编译环境准备

在开始之前,需要安装一些基础编译工具和依赖库(以 Ubuntu/Debian 为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sudo apt update
sudo apt install -y \
build-essential \
autoconf \
automake \
libtool \
pkg-config \
cmake \
git \
curl \
wget \
make \
gcc \
g++ \
libssl-dev \
zlib1g-dev

说明:

  • build-essential:包含 gcc、g++、make 等基础编译工具

  • autoconf、automake、libtool:用于生成配置文件和构建工具

  • pkg-config:用于检测依赖库路径

  • libssl-dev:OpenSSL 开发库

  • zlib1g-dev:压缩库,部分库可能依赖

  • git:拉取源码

CentOS/RHEL:

1
2
sudo yum groupinstall "Development Tools" -y
sudo yum install -y autoconf automake libtool pkgconfig cmake git wget openssl-devel zlib-devel

1. 编译 quictls OpenSSL

1
2
3
4
5
6
7
8
9
10
git clone --depth=1 --recursive -b openssl-3.3.0-quic1 https://github.com/quictls/openssl.git
cd openssl
./Configure linux-x86_64 no-shared enable-tls1_3 --prefix=/usr/local/openssl-quic
make -j$(nproc)
make install

export PATH=/usr/local/openssl-quic/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/openssl-quic/lib64:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/usr/local/openssl-quic/lib64/pkgconfig:$PKG_CONFIG_PATH
cd ..

2. 编译 nghttp3

1
2
3
4
5
6
7
8
9
10
# 克隆 nghttp3 仓库
git clone --depth=1 --recursive https://github.com/ngtcp2/nghttp3.git
cd nghttp3

# 自动生成配置文件并编译
autoreconf -i
./configure
make -j$(nproc)
make install
cd ..

3. 编译 ngtcp2

1
2
3
4
5
6
7
8
9
10
# 克隆 ngtcp2 仓库
git clone --depth=1 --recursive https://github.com/ngtcp2/ngtcp2.git
cd ngtcp2

# 自动生成配置文件并编译,仅编译库文件
autoreconf -i
./configure --enable-lib-only
make -j$(nproc)
make install
cd ..

4. 编译 cURL(官方 master 分支)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 克隆 cURL 仓库
git clone --depth=1 --recursive https://github.com/curl/curl.git
cd curl

# 生成构建配置
./buildconf

# 配置并编译 cURL,启用 OpenSSL、nghttp3、ngtcp2 和 HTTP/3
PKG_CONFIG_PATH=/usr/local/openssl-quic/lib64/pkgconfig \
./configure --with-ssl=/usr/local/openssl-quic --with-nghttp3 --with-ngtcp2 --enable-alt-svc --enable-shared
make -j$(nproc)
make install
cd ..

5. 测试 HTTP/3 支持

1
2
3
使用以下命令测试是否成功支持 HTTP/3:
curl -v --http3 https://example.com
如果输出中包含 Using HTTP/3 或类似信息,则表示编译成功,cURL 已支持 HTTP/3 协议。

6. 环境变量持久化(可选)

可以将以下内容添加到 ~/.bashrc, ~/.zshrc 或ld.so.conf.d 目录 中,方便每次登录自动生效:

1
2
3
4
5
6
7
8
export PATH=/usr/local/openssl-quic/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/openssl-quic/lib64:$LD_LIBRARY_PATH
export PKG_CONFIG_PATH=/usr/local/openssl-quic/lib64/pkgconfig:$PKG_CONFIG_PATH
vim /etc/ld.so.conf.d/openssl.conf
/usr/local/lib
/usr/local/lib64
/usr/local/openssl-quic/lib64
ldconfig #生效