nginx 不能直接记录 request body, 写了个简单的 js 配合 njs 模块, 并且解码 dns 封包获得查询的域名.
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; } } }
在此下载 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 };