====== Nginx + njs 记录 DoH 的查询域名 ======
nginx 不能直接记录 request body, 写了个简单的 js 配合 njs 模块, 并且解码 dns 封包获得查询的域名.
===== nginx.conf =====
http {
# ... 省略设置
# 定义日志格式
log_format doh_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$dns_name"';
server {
# ... 省略设置
# 导入 dohlog.js, 该文件内容在下文
js_import /path/dohlog.js;
# 预定义变量保存域名信息
js_var $dns_name;
# 用 njs 替换原来的 /dns-query 用于记录
location /dns-query {
js_content dohlog.log;
}
# 这是原始的 /dns-query 查询, 按实际配置
location /dns-query2 {
internal;
rewrite / /dns-query break;
grpc_pass grpc://127.0.0.1:8053;
grpc_socket_keepalive on;
# 日志路径, 并且使用 doh_log 格式
access_log /path/doh.log doh_log;
}
}
}
===== dohlog.js =====
[[https://raw.githubusercontent.com/TuxInvader/nginx-dns/master/njs.d/dns/libdns.js|在此]]下载 libdns.js 并且与 dohlog.js 放在同一个目录.
import dns from "libdns.js";
// 与 nginx.conf 中一致
var target_uri = '/dns-query2';
function log(r) {
let data;
switch (r.method) {
case "POST":
data = r.requestBuffer;
break;
case "GET":
if (r.args.dns) data = Buffer.from(r.args.dns, "base64url");
break;
}
if (data && data.length > 0) {
let packet = dns.parse_packet(data);
dns.parse_question(packet);
if (typeof(r.variables.dns_name)!="undefined") r.variables.dns_name = packet.question.name;
}
let uri = r.variables.args ? target_uri + "?" + r.variables.args : target_uri
r.internalRedirect(uri);
}
export default { log };
{{tag>nginx njs doh log "post content"}}