From a32f00a1d8b95d4b70e0544f1a32172f11b0d546 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Fri, 12 Dec 2025 15:40:33 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=80=E5=8C=96dns=E7=9A=84=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dns_proxy/src/dns_handler.erl | 122 ++++++++++++++------------- apps/dns_proxy/src/dns_proxy.app.src | 1 + rebar.config | 1 + 3 files changed, 66 insertions(+), 58 deletions(-) diff --git a/apps/dns_proxy/src/dns_handler.erl b/apps/dns_proxy/src/dns_handler.erl index 8c24d30..cb5e5ce 100644 --- a/apps/dns_proxy/src/dns_handler.erl +++ b/apps/dns_proxy/src/dns_handler.erl @@ -73,64 +73,13 @@ handle_call(_Request, _From, State = #state{}) -> {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). handle_cast(handle, State = #state{socket = Sock, src_ip = SrcIp, src_port = SrcPort, packet = Packet}) -> - case dns:decode_message(Packet) of - QueryMsg = #dns_message{qc = 1, questions = [Question = #dns_query{name = QName, type = QType, class = QClass}|_]} -> - %% 查找是否是内置的域名 - case search_inbuilt_domain(QName) of - {ok, Ip} -> - Answer = #dns_rr { - name = QName, - type = QType, - class = QClass, - ttl = 300, - data = #dns_rrdata_a { - ip = Ip - } - }, - RespMsg = QueryMsg#dns_message{ - qr = true, - ra = true, - anc = 1, - auc = 0, - adc = 0, - answers = [Answer], - authority = [], - additional = [] - }, - gen_udp:send(Sock, SrcIp, SrcPort, dns:encode_message(RespMsg)), - - {stop, normal, State}; - error -> - case dns_cache:lookup(Question) of - {hit, Cache} -> - lager:debug("[dns_handler] question: ~p, hit cache answers: ~p", [Question, Cache#dns_cache.answers]), - RespMsg = build_response(QueryMsg, Cache), - gen_udp:send(Sock, SrcIp, SrcPort, dns:encode_message(RespMsg)), - {stop, normal, State}; - miss -> - lager:debug("[dns_handler] cache is miss"), - Ref = make_ref(), - forward_to_upstream(Ref, Packet, QueryMsg), - receive - {dns_resolver_reply, Ref, Resp} -> - case dns:decode_message(Resp) of - RespMsg = #dns_message{answers = Answers} -> - lager:debug("[dns_handler] get a response answers: ~p", [Answers]), - dns_cache:insert(Question, RespMsg), - gen_udp:send(Sock, SrcIp, SrcPort, Resp); - Other -> - lager:debug("[dns_handler] parse reply get error: ~p", [Other]) - end, - {stop, normal, State} - after 5000 -> - {stop, normal, State} - end - end - end; - Other -> - lager:warning("[dns_handler] decode dns query get error: ~p", [Other]), - {stop, normal, State} - end. + case resolver(Packet) of + {ok, Resp} -> + gen_udp:send(Sock, SrcIp, SrcPort, Resp); + {error, Reason} -> + lager:debug("[dns_handler] resolver get error: ~p", [Reason]) + end, + {stop, normal, State}. %% @private %% @doc Handling all non call/cast messages @@ -163,6 +112,63 @@ code_change(_OldVsn, State = #state{}, _Extra) -> %%% Internal functions %%%=================================================================== +-spec resolver(Packet :: binary()) -> {ok, Resp :: binary()} | {error, Reason :: any()}. +resolver(Packet) when is_binary(Packet) -> + resolver0(Packet, dns:decode_message(Packet)). +resolver0(Packet, QueryMsg = #dns_message{qc = 1, questions = [Question = #dns_query{name = QName, type = QType, class = QClass}|_]}) -> + %% 查找是否是内置的域名 + case search_inbuilt_domain(QName) of + {ok, Ip} -> + Answer = #dns_rr { + name = QName, + type = QType, + class = QClass, + ttl = 300, + data = #dns_rrdata_a { + ip = Ip + } + }, + RespMsg = QueryMsg#dns_message{ + qr = true, + ra = true, + anc = 1, + auc = 0, + adc = 0, + answers = [Answer], + authority = [], + additional = [] + }, + {ok, dns:encode_message(RespMsg)}; + error -> + case dns_cache:lookup(Question) of + {hit, Cache} -> + lager:debug("[dns_handler] question: ~p, hit cache answers: ~p", [Question, Cache#dns_cache.answers]), + RespMsg = build_response(QueryMsg, Cache), + {ok, dns:encode_message(RespMsg)}; + miss -> + lager:debug("[dns_handler] cache is miss"), + Ref = make_ref(), + forward_to_upstream(Ref, Packet, QueryMsg), + receive + {dns_resolver_reply, Ref, Resp} -> + case dns:decode_message(Resp) of + RespMsg = #dns_message{answers = Answers} -> + lager:debug("[dns_handler] get a response answers: ~p", [Answers]), + dns_cache:insert(Question, RespMsg), + {ok, Resp}; + Error -> + lager:debug("[dns_handler] parse reply get error: ~p", [Error]), + Error + end + after 5000 -> + {error, timeout} + end + end + end; +resolver0(_, Error) -> + lager:warning("[dns_handler] decode dns query get error: ~p", [Error]), + Error. + -spec forward_to_upstream(Ref :: reference(), Request :: binary(), QueryMsg :: #dns_message{}) -> no_return(). forward_to_upstream(Ref, Request, QueryMsg) -> ReceiverPid = self(), diff --git a/apps/dns_proxy/src/dns_proxy.app.src b/apps/dns_proxy/src/dns_proxy.app.src index b529991..f679fa3 100644 --- a/apps/dns_proxy/src/dns_proxy.app.src +++ b/apps/dns_proxy/src/dns_proxy.app.src @@ -8,6 +8,7 @@ sync, lager, dns_erlang, + pkt, poolboy, kernel, stdlib diff --git a/rebar.config b/rebar.config index 78a8e2c..54e5a1f 100644 --- a/rebar.config +++ b/rebar.config @@ -2,6 +2,7 @@ {deps, [ {dns_erlang, ".*", {git, "https://github.com/dnsimple/dns_erlang.git", {tag, "v4.4.0"}}}, {poolboy, ".*", {git, "https://github.com/devinus/poolboy.git", {tag, "1.5.1"}}}, + {pkt, ".*", {git, "https://github.com/msantos/pkt.git", {tag, "0.6.0"}}}, {sync, ".*", {git, "https://github.com/rustyio/sync.git", {branch, "master"}}}, {parse_trans, ".*", {git, "https://github.com/uwiger/parse_trans", {tag, "3.0.0"}}}, {lager, ".*", {git,"https://github.com/erlang-lager/lager.git", {tag, "3.9.2"}}}