用户工具

站点工具


xnix:nginx_doh_logging

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

在此下载 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 };
xnix/nginx_doh_logging.txt · 最后更改: 2024/05/10 02:05 由 Hshh