add基础代码
This commit is contained in:
parent
79650dd319
commit
1e2aa32bde
17
apps/dns_proxy/src/dns_cache.erl
Normal file
17
apps/dns_proxy/src/dns_cache.erl
Normal file
@ -0,0 +1,17 @@
|
||||
-module(dns_cache).
|
||||
-export([init/0, lookup/1, insert/2]).
|
||||
|
||||
-define(TABLE, dns_cache).
|
||||
|
||||
init() ->
|
||||
ets:new(?TABLE, [named_table, set, public, {read_concurrency, true}]).
|
||||
|
||||
lookup(Key) ->
|
||||
case ets:lookup(?TABLE, Key) of
|
||||
[{_Key, Value}] -> {hit, Value};
|
||||
[] -> miss
|
||||
end.
|
||||
|
||||
insert(Key, DNSMsg) ->
|
||||
ets:insert(?TABLE, {Key, DNSMsg}),
|
||||
ok.
|
||||
48
apps/dns_proxy/src/dns_handler.erl
Normal file
48
apps/dns_proxy/src/dns_handler.erl
Normal file
@ -0,0 +1,48 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author anlicheng
|
||||
%%% @copyright (C) 2025, <COMPANY>
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 03. 12月 2025 17:27
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(dns_handler).
|
||||
-author("anlicheng").
|
||||
|
||||
-include_lib("dns_erlang/include/dns.hrl").
|
||||
-include_lib("dns_erlang/include/dns_records.hrl").
|
||||
-include_lib("dns_erlang/include/dns_terms.hrl").
|
||||
|
||||
-export([handle_request/4]).
|
||||
|
||||
handle_request(Sock, Ip, Port, Packet) ->
|
||||
case dns:decode_message(Packet) of
|
||||
{ok, Msg} ->
|
||||
%Qname = (Msg#dns_message.questions)#dns_question.qname,
|
||||
Qname = <<"www.baidu.com">>,
|
||||
case dns_cache:lookup(Qname) of
|
||||
{hit, R} ->
|
||||
Resp = build_response(Msg, R),
|
||||
gen_udp:send(Sock, Ip, Port, dns:encode_message(Resp));
|
||||
miss ->
|
||||
forward_to_upstream(Sock, Ip, Port, Packet)
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
forward_to_upstream(Sock, Ip, Port, Packet) ->
|
||||
{SendSock, {UpIP, UpPort}} = dns_socket_pool:get_socket(),
|
||||
ok = gen_udp:send(SendSock, UpIP, UpPort, Packet),
|
||||
|
||||
inet:setopts(SendSock, [{active, once}]),
|
||||
receive
|
||||
{udp, SendSock, _UIp, _UPort, Resp} ->
|
||||
gen_udp:send(Sock, Ip, Port, Resp)
|
||||
after 2000 ->
|
||||
ok
|
||||
end.
|
||||
|
||||
build_response(Req, RR) ->
|
||||
Msg = Req,
|
||||
Msg#dns_message{answers=[RR], qr=true, aa=true}.
|
||||
71
apps/dns_proxy/src/dns_handler_sup.erl
Normal file
71
apps/dns_proxy/src/dns_handler_sup.erl
Normal file
@ -0,0 +1,71 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author anlicheng
|
||||
%%% @copyright (C) 2025, <COMPANY>
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 03. 12月 2025 17:29
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(dns_handler_sup).
|
||||
-author("anlicheng").
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
-export([start_handler/4]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%%%===================================================================
|
||||
%%% API functions
|
||||
%%%===================================================================
|
||||
|
||||
%% @doc Starts the supervisor
|
||||
-spec(start_link() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Supervisor callbacks
|
||||
%%%===================================================================
|
||||
|
||||
%% @private
|
||||
%% @doc Whenever a supervisor is started using supervisor:start_link/[2,3],
|
||||
%% this function is called by the new process to find out about
|
||||
%% restart strategy, maximum restart frequency and child
|
||||
%% specifications.
|
||||
-spec(init(Args :: term()) ->
|
||||
{ok, {SupFlags :: {RestartStrategy :: supervisor:strategy(),
|
||||
MaxR :: non_neg_integer(), MaxT :: non_neg_integer()},
|
||||
[ChildSpec :: supervisor:child_spec()]}}
|
||||
| ignore | {error, Reason :: term()}).
|
||||
init([]) ->
|
||||
SupFlags = #{strategy => simple_one_for_one, intensity => 0, period => 1},
|
||||
Spec = #{
|
||||
id => dns_handler,
|
||||
start => {'dns_handler', dns_handler, []},
|
||||
restart => temporary,
|
||||
shutdown => 2000,
|
||||
type => worker,
|
||||
modules => ['dns_handler']
|
||||
},
|
||||
|
||||
{ok, {SupFlags, [Spec]}}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
||||
start_handler(Sock, Ip, Port, Packet) ->
|
||||
case supervisor:start_child(?MODULE, [Sock, Ip, Port, Packet]) of
|
||||
{ok, Pid} ->
|
||||
{ok, Pid};
|
||||
{error, {already_started, Pid}} ->
|
||||
{ok, Pid};
|
||||
StartError ->
|
||||
StartError
|
||||
end.
|
||||
@ -4,7 +4,11 @@
|
||||
{registered, []},
|
||||
{mod, {dns_proxy_app, []}},
|
||||
{applications,
|
||||
[kernel,
|
||||
[
|
||||
sync,
|
||||
lager,
|
||||
dns_erlang,
|
||||
kernel,
|
||||
stdlib
|
||||
]},
|
||||
{env,[]},
|
||||
|
||||
@ -26,10 +26,17 @@ start_link() ->
|
||||
%% type => worker(), % optional
|
||||
%% modules => modules()} % optional
|
||||
init([]) ->
|
||||
SupFlags = #{strategy => one_for_all,
|
||||
intensity => 0,
|
||||
period => 1},
|
||||
ChildSpecs = [],
|
||||
SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600},
|
||||
ChildSpecs = [
|
||||
#{
|
||||
id => dns_handler_sup,
|
||||
start => {dns_handler_sup, start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 2000,
|
||||
type => supervisor,
|
||||
modules => ['dns_handler_sup']
|
||||
}
|
||||
],
|
||||
{ok, {SupFlags, ChildSpecs}}.
|
||||
|
||||
%% internal functions
|
||||
|
||||
30
apps/dns_proxy/src/dns_server.erl
Normal file
30
apps/dns_proxy/src/dns_server.erl
Normal file
@ -0,0 +1,30 @@
|
||||
-module(dns_server).
|
||||
-export([start/0, stop/0]).
|
||||
|
||||
-define(LISTEN_PORT, 53).
|
||||
|
||||
start() ->
|
||||
dns_cache:init(),
|
||||
dns_zone_loader:load("priv/local.zone"),
|
||||
|
||||
%% 配置上游 DNS
|
||||
Upstreams = [
|
||||
{{8,8,8,8}, 53},
|
||||
{{1,1,1,1}, 53}
|
||||
],
|
||||
dns_socket_pool:start_link(Upstreams),
|
||||
|
||||
{ok, Sock} = gen_udp:open(?LISTEN_PORT, [binary, {active, true}]),
|
||||
io:format("DNS Forwarder started on UDP port ~p~n", [?LISTEN_PORT]),
|
||||
loop(Sock).
|
||||
|
||||
stop() ->
|
||||
gen_udp:close(?LISTEN_PORT),
|
||||
ok.
|
||||
|
||||
loop(Sock) ->
|
||||
receive
|
||||
{udp, Sock, Ip, Port, Packet} ->
|
||||
dns_handler_sup:start_handler(Sock, Ip, Port, Packet),
|
||||
loop(Sock)
|
||||
end.
|
||||
26
apps/dns_proxy/src/dns_socket_pool.erl
Normal file
26
apps/dns_proxy/src/dns_socket_pool.erl
Normal file
@ -0,0 +1,26 @@
|
||||
-module(dns_socket_pool).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-export([start_link/1, get_socket/0]).
|
||||
-export([init/1, handle_call/3]).
|
||||
|
||||
-record(state, {sockets=[]}).
|
||||
|
||||
start_link(Ups) ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, Ups, []).
|
||||
|
||||
get_socket() ->
|
||||
gen_server:call(?MODULE, get).
|
||||
|
||||
init(Upstreams) ->
|
||||
%% 为多个上游 DNS 建 socket
|
||||
Sockets = lists:map(fun({IP, Port}) ->
|
||||
{ok, Sock} = gen_udp:open(0, [binary, {active, false}]),
|
||||
{Sock, {IP, Port}}
|
||||
end, Upstreams),
|
||||
{ok, #state{sockets=Sockets}}.
|
||||
|
||||
handle_call(get, _From, State=#state{sockets=Socks}) ->
|
||||
%% 简单 round-robin
|
||||
[H|T] = Socks,
|
||||
{reply, H, State#state{sockets=T ++ [H]}}.
|
||||
13
apps/dns_proxy/src/dns_zone_loader.erl
Normal file
13
apps/dns_proxy/src/dns_zone_loader.erl
Normal file
@ -0,0 +1,13 @@
|
||||
-module(dns_zone_loader).
|
||||
-export([load/1]).
|
||||
|
||||
-include_lib("dns_erlang/include/dns.hrl").
|
||||
|
||||
load(Path) ->
|
||||
{ok, Bin} = file:read_file(Path),
|
||||
{ok, Records} = dns_zone:decode(Bin), % dns_erlang 提供
|
||||
lists:foreach(fun(R) ->
|
||||
Name = R#dns_rr.name,
|
||||
dns_cache:insert(Name, R)
|
||||
end, Records),
|
||||
ok.
|
||||
@ -1,3 +1,46 @@
|
||||
[
|
||||
{dns_proxy, []}
|
||||
{dns_proxy, [
|
||||
|
||||
%% 公共的dns域名解析服务
|
||||
{public_dns_servers, [
|
||||
{{8,8,8,8}, 53},
|
||||
{{1,1,1,1}, 53}
|
||||
]}
|
||||
|
||||
]},
|
||||
|
||||
%% 系统日志配置,系统日志为lager, 支持日志按日期自动分割
|
||||
{lager, [
|
||||
{colored, true},
|
||||
%% Whether to write a crash log, and where. Undefined means no crash logger.
|
||||
{crash_log, "trade_hub.crash.log"},
|
||||
%% Maximum size in bytes of events in the crash log - defaults to 65536
|
||||
{crash_log_msg_size, 65536},
|
||||
%% Maximum size of the crash log in bytes, before its rotated, set
|
||||
%% to 0 to disable rotation - default is 0
|
||||
{crash_log_size, 10485760},
|
||||
%% What time to rotate the crash log - default is no time
|
||||
%% rotation. See the README for a description of this format.
|
||||
{crash_log_date, "$D0"},
|
||||
%% Number of rotated crash logs to keep, 0 means keep only the
|
||||
%% current one - default is 0
|
||||
{crash_log_count, 5},
|
||||
%% Whether to redirect error_logger messages into lager - defaults to true
|
||||
{error_logger_redirect, true},
|
||||
|
||||
%% How big the gen_event mailbox can get before it is switched into sync mode
|
||||
{async_threshold, 20},
|
||||
%% Switch back to async mode, when gen_event mailbox size decrease from `async_threshold'
|
||||
%% to async_threshold - async_threshold_window
|
||||
{async_threshold_window, 5},
|
||||
|
||||
{handlers, [
|
||||
%% debug | info | warning | error, 日志级别
|
||||
{lager_console_backend, debug},
|
||||
{lager_file_backend, [{file, "debug.log"}, {level, debug}, {size, 314572800}]},
|
||||
{lager_file_backend, [{file, "notice.log"}, {level, notice}, {size, 314572800}]},
|
||||
{lager_file_backend, [{file, "error.log"}, {level, error}, {size, 314572800}]},
|
||||
{lager_file_backend, [{file, "info.log"}, {level, info}, {size, 314572800}]}
|
||||
]}
|
||||
]}
|
||||
].
|
||||
|
||||
10
rebar.config
10
rebar.config
@ -1,5 +1,10 @@
|
||||
{erl_opts, [debug_info]}.
|
||||
{deps, []}.
|
||||
{deps, [
|
||||
{dns_erlang, ".*", {git, "https://github.com/dnsimple/dns_erlang.git", {tag, "v4.4.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"}}}
|
||||
]}.
|
||||
|
||||
{relx, [{release, {dns_proxy, "0.1.0"},
|
||||
[dns_proxy,
|
||||
@ -30,3 +35,6 @@
|
||||
%% {mode, minimal}
|
||||
]
|
||||
}]}]}.
|
||||
|
||||
{erl_opts, [{parse_transform,lager_transform}]}.
|
||||
{rebar_packages_cdn, "https://hexpm.upyun.com"}.
|
||||
Loading…
x
Reference in New Issue
Block a user