Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

seds: remove Erlang server code

seds has been moved to another repository, keep only the C code here.
  • Loading branch information...
commit 04782b8103531399e8bf30cea86e171f25ac9b32 1 parent 47ff4cd
Michael Santos authored
6 Emakefile
... ... @@ -1,6 +0,0 @@
1   -{["src/*"],
2   - [{i, "include"},
3   - {outdir, "ebin"},
4   - debug_info]
5   -}.
6   -
15 Makefile
... ... @@ -1,15 +0,0 @@
1   -
2   -ERL=erl
3   -
4   -all: dir erl
5   -
6   -dir:
7   - -@mkdir -p ebin deps
8   -
9   -erl:
10   - @$(ERL) -noinput +B \
11   - -eval 'case make:all() of up_to_date -> halt(0); error -> halt(1) end.'
12   -
13   -clean:
14   - @rm -fv ebin/*.beam
15   -
56 include/seds.hrl
... ... @@ -1,56 +0,0 @@
1   -%% Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
2   -%% All rights reserved.
3   -%%
4   -%% Redistribution and use in source and binary forms, with or without
5   -%% modification, are permitted provided that the following conditions
6   -%% are met:
7   -%%
8   -%% Redistributions of source code must retain the above copyright
9   -%% notice, this list of conditions and the following disclaimer.
10   -%%
11   -%% Redistributions in binary form must reproduce the above copyright
12   -%% notice, this list of conditions and the following disclaimer in the
13   -%% documentation and/or other materials provided with the distribution.
14   -%%
15   -%% Neither the name of the author nor the names of its contributors
16   -%% may be used to endorse or promote products derived from this software
17   -%% without specific prior written permission.
18   -%%
19   -%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20   -%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21   -%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22   -%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23   -%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   -%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25   -%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   -%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27   -%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   -%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29   -%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   -%% POSSIBILITY OF SUCH DAMAGE.
31   -
32   --define(DNS_PORT, 53).
33   --define(PROXY_TIMEOUT, 5 * 60 * 1000).
34   -
35   --define(CFG, "seds.cfg").
36   -
37   --define(MAXLABEL, 63). % 1 byte for length of label
38   -
39   --record(seds, {
40   - q, % decoded DNS query
41   - type, % 'up' or 'down'
42   - id = 0, % 2 or 4 byte session ID
43   - forward, % tuple describing destination ip/port
44   - sum = 0, % byte count
45   - domain = [], % domain names
46   - data = [] % base64 encoded data
47   - }).
48   -
49   --record(config, {
50   - acf = false, % allow client forwarding
51   - acl = [], % forward IP blacklist
52   - acl_port = [22], % forward IP blacklist
53   - f, % forwarders map
54   - d = [] % domains
55   - }).
56   -
2  priv/seds.cfg.dist
... ... @@ -1,2 +0,0 @@
1   -{forward, [ {{127,0,0,1}, 22} ]}.
2   -{domains, []}.
101 src/base32.erl
... ... @@ -1,101 +0,0 @@
1   -%% Taken from eadc-hub (http://github.com/JLarky/eadc-hub)
2   -%% http://github.com/JLarky/eadc-hub/blob/master/src/eadc_utils.erl
3   --module(base32).
4   --author('jlarky@gmail.com').
5   -
6   --export([b32/1, encode/1,unb32/1, decode/1 ]).
7   -
8   -
9   -%% @spec b32(integer()) -> [base32char()]
10   -%% @doc returns base32 character corresponding to V like 1 -> 'B', 31 -> '7'.
11   -%% V is integer from 0 to 31
12   -%% @see unb32/1
13   -b32(V) when V < 0 -> % wrong argument
14   - throw({b32,wrong_argument, V});
15   -b32(V) when V < 26 ->
16   - [V+65];
17   -b32(V) when V < 32 ->
18   - [V+24]; % V-26+48+2
19   -b32(V) when is_integer(V) ->
20   - b32_(V, "").
21   -
22   -b32_(0, Buf) ->
23   - Buf;
24   -b32_(V, Buf) ->
25   - [A]=b32(V rem 32),
26   - b32_(V bsr 5, [A|Buf]).
27   -
28   -%% @spec encode(string()) -> base32string()
29   -%% @doc returns base32 encoded string of String
30   -%% @see decode/1
31   -encode(Bin) when is_binary(Bin) ->
32   - lists:reverse(encode_(Bin, _Out=[]));
33   -encode(String) ->
34   - encode(list_to_binary(String)).
35   -
36   -encode_(Bin, Out) ->
37   - case Bin of
38   - <<>> ->
39   - Out;
40   - <<A:1>> ->
41   - [B]=b32(A bsl 4),[B|Out];
42   - <<A:2>> ->
43   - [B]=b32(A bsl 3),[B|Out];
44   - <<A:3>> ->
45   - [B]=b32(A bsl 2),[B|Out];
46   - <<A:4>> ->
47   - [B]=b32(A bsl 1),[B|Out];
48   - Bin ->
49   - <<A:5, T/bitstring>>=Bin,
50   - [B]=b32(A),encode_(T, [B|Out])
51   - end.
52   -
53   -%% @spec unb32(base32char()) -> integer()
54   -%% @doc A=unb32(b32(A))
55   -%% @see b32/1
56   -unb32([V]) when ((V >= $A) and (V =< $Z)) ->
57   - V-$A;
58   -unb32([V]) when ((V >= $2) and (V =< $7)) ->
59   - V-$2+26;
60   -unb32([V]) ->
61   - throw({badarg, [V]});
62   -unb32(String=[_|_]) ->
63   - lists:foldl(fun(Char, Acc) ->
64   - Acc*32+unb32([Char])
65   - end, 0, String).
66   -
67   -%% @spec decode(base32string()) -> string()
68   -%% @doc returns base32 decoded string of String
69   -%% @see encode/1
70   -decode(Bin) when is_binary(Bin) ->
71   - decode(binary_to_list(Bin));
72   -decode(String) ->
73   - Bits=lists:foldl(fun(Elem, Acc) ->
74   - A= unb32([Elem]),
75   - New= <<Acc/bitstring, A:5>>,
76   - New
77   - end, <<>>, String),
78   - decode_(Bits, _Out=[]).
79   -
80   -decode_(<<>>, Out) ->
81   - Out;
82   -decode_(Bits, Out) ->
83   - case Bits of
84   - <<Head:8, Rest/bitstring>> ->
85   - decode_(Rest, Out++[Head]);
86   - <<0:1>> -> Out;
87   - <<0:2>> -> Out;
88   - <<0:3>> -> Out;
89   - <<0:4>> -> Out;
90   - <<0:5>> -> Out;
91   - <<0:6>> -> Out;
92   - <<0:7>> -> Out;
93   - <<H:1>> -> Out++[H bsl 7];
94   - <<H:2>> -> Out++[H bsl 6];
95   - <<H:3>> -> Out++[H bsl 5];
96   - <<H:4>> -> Out++[H bsl 4];
97   - <<H:5>> -> Out++[H bsl 3];
98   - <<H:6>> -> Out++[H bsl 2];
99   - <<H:7>> -> Out++[H bsl 1]
100   - end.
101   -
185 src/seds.erl
... ... @@ -1,185 +0,0 @@
1   -%% Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
2   -%% All rights reserved.
3   -%%
4   -%% Redistribution and use in source and binary forms, with or without
5   -%% modification, are permitted provided that the following conditions
6   -%% are met:
7   -%%
8   -%% Redistributions of source code must retain the above copyright
9   -%% notice, this list of conditions and the following disclaimer.
10   -%%
11   -%% Redistributions in binary form must reproduce the above copyright
12   -%% notice, this list of conditions and the following disclaimer in the
13   -%% documentation and/or other materials provided with the distribution.
14   -%%
15   -%% Neither the name of the author nor the names of its contributors
16   -%% may be used to endorse or promote products derived from this software
17   -%% without specific prior written permission.
18   -%%
19   -%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20   -%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21   -%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22   -%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23   -%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   -%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25   -%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   -%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27   -%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   -%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29   -%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   -%% POSSIBILITY OF SUCH DAMAGE.
31   --module(seds).
32   --behaviour(gen_server).
33   -
34   --include_lib("kernel/src/inet_dns.hrl").
35   --include("seds.hrl").
36   -
37   --define(SERVER, ?MODULE).
38   -
39   --export([start_link/0, start_link/1, send/2]).
40   --export([config/2, privpath/1]).
41   --export([init/1, handle_call/3, handle_cast/2, handle_info/2,
42   - terminate/2, code_change/3]).
43   -
44   --record(state, {
45   - acf = false, % allow client forwarding
46   - acl = [], % forward IP blacklist
47   - acl_port = [], % allowed ports (whitelist)
48   -
49   - f, % forwarders map
50   - s, % socket
51   - d = [], % domains
52   - p = [] % list of proxies
53   - }).
54   -
55   -
56   -send({IP, Port, #dns_rec{} = Rec}, #seds{} = Query) ->
57   - gen_server:call(?SERVER, {send, {IP, Port, Rec, Query}}).
58   -
59   -
60   -start_link() ->
61   - start_link(?DNS_PORT).
62   -start_link(Port) ->
63   - gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
64   -
65   -init([Port]) when Port > 1024 ->
66   - init(Port, []);
67   -init([Port]) ->
68   - {ok, FD} = procket:listen(Port, [
69   - {protocol, udp},
70   - {family, inet},
71   - {type, dgram}
72   - ]),
73   - init(Port, [{fd, FD}]).
74   -
75   -init(Port, Opt) ->
76   - {ok, Socket} = gen_udp:open(Port, [
77   - binary,
78   - {active, once}
79   - ] ++ Opt),
80   - {ok, #state{
81   - acf = config(dynamic, ?CFG, false),
82   - acl = config(acl, ?CFG, []),
83   - acl_port = config(allowed_ports, ?CFG, [22]),
84   - f = config(forward, ?CFG, []),
85   - d = [ string:tokens(N, ".") || N <- config(domains, ?CFG) ],
86   - s = Socket,
87   - p = dict:new()
88   - }}.
89   -
90   -
91   -handle_call({send, {IP, Port, #dns_rec{} = Rec,
92   - #seds{type = Type, sum = Sum, data = Data} = Query}},
93   - _From, State) ->
94   - Session = seds_protocol:session(Query, map(State)),
95   - {Proxy, Proxies} = proxy(Session, State),
96   - ok = seds_proxy:send(Proxy, IP, Port, Rec, {Type, Sum, Data}),
97   - {reply, ok, State#state{p = Proxies}};
98   -
99   -handle_call(Request, _From, State) ->
100   - error_logger:error_report([{wtf, Request}]),
101   - {reply, ok, State}.
102   -
103   -handle_cast(_Msg, State) ->
104   - {noreply, State}.
105   -
106   -% DNS request from client
107   -handle_info({udp, Socket, IP, Port, Data}, #state{
108   - s = Socket
109   - } = State) ->
110   - ok = inet:setopts(Socket, [{active, once}]),
111   - spawn(seds_protocol, decode, [{IP, Port, Data}, map(State)]),
112   - {noreply, State};
113   -
114   -% Session terminated
115   -handle_info({'DOWN', _Ref, process, Pid, _Reason}, #state{
116   - p = Proxies
117   - } = State) ->
118   - {noreply, State#state{
119   - p = dict:filter(
120   - fun (_,V) when V == Pid -> false;
121   - (_,_) -> true
122   - end,
123   - Proxies)
124   - }};
125   -
126   -% WTF?
127   -handle_info(Info, State) ->
128   - error_logger:error_report([{wtf, Info}]),
129   - {noreply, State}.
130   -
131   -terminate(_Reason, _State) ->
132   - ok.
133   -code_change(_OldVsn, State, _Extra) ->
134   - {ok, State}.
135   -
136   -
137   -%%%
138   -%%% Internal Functions
139   -%%%
140   -proxy({{IP, Port}, Id} = Session, #state{
141   - s = Socket,
142   - p = Proxies
143   - }) ->
144   - case dict:find(Session, Proxies) of
145   - error ->
146   - error_logger:info_report([
147   - {session_start, {IP, Port}},
148   - {id, Id}
149   - ]),
150   - {ok, Pid} = seds_proxy:start_link(Socket, {IP, Port}),
151   - {Pid, dict:store(Session, Pid, Proxies)};
152   - {ok, Pid} ->
153   - {Pid, Proxies}
154   - end.
155   -
156   -config(Key, Cfg) ->
157   - config(Key, Cfg, undefined).
158   -config(Key, Cfg, Default) ->
159   - {ok, Map} = file:consult(privpath(Cfg)),
160   - proplists:get_value(Key, Map, Default).
161   -
162   -privpath(Cfg) ->
163   - filename:join([
164   - filename:dirname(code:which(?MODULE)),
165   - "..",
166   - "priv",
167   - Cfg
168   - ]).
169   -
170   -map(#state{
171   - acf = ACF,
172   - acl = ACL,
173   - acl_port = ACP,
174   - f = Fwd,
175   - d = Domains
176   - }) ->
177   - #config{
178   - acf = ACF,
179   - acl = ACL,
180   - acl_port = ACP,
181   - f = Fwd,
182   - d = Domains
183   - }.
184   -
185   -
245 src/seds_protocol.erl
... ... @@ -1,245 +0,0 @@
1   -%% Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
2   -%% All rights reserved.
3   -%%
4   -%% Redistribution and use in source and binary forms, with or without
5   -%% modification, are permitted provided that the following conditions
6   -%% are met:
7   -%%
8   -%% Redistributions of source code must retain the above copyright
9   -%% notice, this list of conditions and the following disclaimer.
10   -%%
11   -%% Redistributions in binary form must reproduce the above copyright
12   -%% notice, this list of conditions and the following disclaimer in the
13   -%% documentation and/or other materials provided with the distribution.
14   -%%
15   -%% Neither the name of the author nor the names of its contributors
16   -%% may be used to endorse or promote products derived from this software
17   -%% without specific prior written permission.
18   -%%
19   -%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20   -%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21   -%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22   -%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23   -%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   -%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25   -%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   -%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27   -%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   -%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29   -%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   -%% POSSIBILITY OF SUCH DAMAGE.
31   --module(seds_protocol).
32   -
33   --include_lib("kernel/src/inet_dns.hrl").
34   --include("seds.hrl").
35   -
36   --export([decode/2, session/2]).
37   -
38   -
39   -%%%
40   -%%% Handle decoding of the data embedded in the different
41   -%%% record types.
42   -%%%
43   -
44   -%%--------------------------------------------------------------------
45   -%%% Sessions: which IP:Port to send the data
46   -%%--------------------------------------------------------------------
47   -
48   -% Static list of forwarded hosts:port, identified from offset 0
49   -session(#seds{
50   - forward = {session, Forward},
51   - id = Id
52   - },
53   - #config{f = Map}) ->
54   - F = case Forward + 1 of
55   - N when N > length(Map) -> 1;
56   - N when N < 1 -> 1;
57   - N -> N
58   - end,
59   - {lists:nth(F, Map), Id};
60   -
61   -% Dynamic forwaring requested by client
62   -session(#seds{
63   - forward = {forward, Forward},
64   - id = Id
65   - }, #config{}) ->
66   - {Forward, Id}.
67   -
68   -
69   -%%--------------------------------------------------------------------
70   -%%% Decode the data embedded in the DNS record.
71   -%%%
72   -%%% The decode function is spawned as an unlinked process. If the
73   -%%% parsing succeeds, the data is returned to the gen_server. If
74   -%%% the parsing fails, the data is bad and is thrown away.
75   -%%%
76   -%%--------------------------------------------------------------------
77   -
78   -% mfz.wiztb.onsgmcq.40966-0.id-372571.u.192.168.100.101-2222.x.example.com
79   -% B64._Nonce-Sum.id-SessionId.u.IP1.IP2.IP3.IP4-Port.x.Domain
80   -decode({domain, {a, [Base64Nonce, Sum, "id", SessionId, "u",
81   - IP1, IP2, IP3, IP4, Port, "x"|Domain]}},
82   - #config{d = Domains, acf = true, acl = ACL, acl_port = ACP}) ->
83   -
84   - IP = makeaddr({IP1,IP2,IP3,IP4}),
85   - Port1 = list_to_integer(Port),
86   -
87   - true = check_dn(Domain, Domains),
88   - true = check_acl(IP, ACL),
89   - true = check_port(Port1, ACP),
90   -
91   - B64 = string:tokens(Base64Nonce, "."),
92   - Forward = forward({IP, Port1}),
93   -
94   - #seds{
95   - type = up,
96   - forward = Forward,
97   - id = SessionId,
98   - data = lists:flatten(lists:sublist(B64, length(B64)-1)),
99   - sum = list_to_integer(Sum),
100   - domain = Domain
101   - };
102   -decode({domain, {a, [Base64Nonce, Sum, "id", SessionId, "u",
103   - IP1, IP2, IP3, IP4, "x"|Domain]}},
104   - #config{d = Domains, acf = true, acl = ACL}) ->
105   -
106   - IP = makeaddr({IP1,IP2,IP3,IP4}),
107   -
108   - true = check_dn(Domain, Domains),
109   - true = check_acl(IP, ACL),
110   -
111   - B64 = string:tokens(Base64Nonce, "."),
112   - Forward = forward({IP, 22}),
113   -
114   - #seds{
115   - type = up,
116   - forward = Forward,
117   - id = SessionId,
118   - data = lists:flatten(lists:sublist(B64, length(B64)-1)),
119   - sum = list_to_integer(Sum),
120   - domain = Domain
121   - };
122   -
123   -% mfz.wiztb.onsgmcq.40966-0.id-372571.up.p.example.com
124   -% B64._Nonce-Sum.id-SessionId.up.Domain
125   -decode({domain, {a, [Base64Nonce, Sum, "id", SessionId, "up"|Domain]}},
126   - #config{d = Domains}) ->
127   - true = check_dn(Domain, Domains),
128   -
129   - B64 = string:tokens(Base64Nonce, "."),
130   - {Forward, Id} = forward(list_to_integer(SessionId)),
131   -
132   - #seds{
133   - type = up,
134   - forward = Forward,
135   - id = Id,
136   - data = lists:flatten(lists:sublist(B64, length(B64)-1)),
137   - sum = list_to_integer(Sum),
138   - domain = Domain
139   - };
140   -
141   -% 0-29941.id-10498.d.192.168.100.101.s.p.example.com
142   -% Sum-Nonce.id-SessionId.d.IP1.IP2.IP3.IP4.Domain
143   -%
144   -% 0-29941.id-10498.d.192.168.100.101-2222.x.p.example.com
145   -% Sum-Nonce.id-SessionId.d.IP1.IP2.IP3.IP4-Port.x.Domain
146   -decode({domain, {_Type, [Sum, _Nonce, "id", SessionId, "d",
147   - IP1, IP2, IP3, IP4, Port, "x"|Domain]}},
148   - #config{d = Domains, acf = true, acl = ACL, acl_port = ACP}) ->
149   -
150   - IP = makeaddr({IP1,IP2,IP3,IP4}),
151   - Port1 = list_to_integer(Port),
152   -
153   - true = check_dn(Domain, Domains),
154   - true = check_acl(IP, ACL),
155   - true = check_port(Port1, ACP),
156   -
157   - Forward = forward({IP, Port1}),
158   -
159   - #seds{
160   - type = down,
161   - forward = Forward,
162   - id = SessionId,
163   - sum = list_to_sum(Sum),
164   - domain = Domain
165   - };
166   -decode({domain, {_Type, [Sum, _Nonce, "id", SessionId, "d",
167   - IP1, IP2, IP3, IP4, "x"|Domain]}},
168   - #config{d = Domains, acf = true, acl = ACL}) ->
169   -
170   - IP = makeaddr({IP1,IP2,IP3,IP4}),
171   -
172   - true = check_dn(Domain, Domains),
173   - true = check_acl(IP, ACL),
174   -
175   - Forward = forward({IP, 22}),
176   -
177   - #seds{
178   - type = down,
179   - forward = Forward,
180   - id = SessionId,
181   - sum = list_to_sum(Sum),
182   - domain = Domain
183   - };
184   -
185   -% 0-29941.id-10498.down.s.p.example.com
186   -% Sum-Nonce.id-SessionId.down.Domain
187   -decode({domain, {_Type, [Sum, _Nonce, "id", SessionId, "down"|Domain]}},
188   - #config{d = Domains}) ->
189   - true = check_dn(Domain, Domains),
190   -
191   - {Forward, Id} = forward(list_to_integer(SessionId)),
192   -
193   - #seds{
194   - type = down,
195   - forward = Forward,
196   - id = Id,
197   - sum = list_to_sum(Sum),
198   - domain = Domain
199   - };
200   -
201   -decode({dns_rec, #dns_rec{
202   - header = #dns_header{
203   - qr = false,
204   - opcode = 'query'
205   - },
206   - qdlist = [#dns_query{
207   - domain = Query,
208   - type = Type,
209   - class = in
210   - }|_]
211   - }
212   - }, State) ->
213   - {Prefix, Session} = lists:split(string:chr(Query, $-), Query),
214   - decode({domain, {Type, [Prefix|string:tokens(Session, ".-")]}}, State);
215   -
216   -decode({IP, Port, Data}, State) ->
217   - {ok, Query} = inet_dns:decode(Data),
218   - seds:send({IP, Port, Query}, decode({dns_rec, Query}, State)).
219   -
220   -
221   -%%--------------------------------------------------------------------
222   -%%% Internal functions
223   -%%--------------------------------------------------------------------
224   -makeaddr({IP1,IP2,IP3,IP4}) when is_list(IP1), is_list(IP2), is_list(IP3), is_list(IP4) ->
225   - {list_to_integer(IP1), list_to_integer(IP2), list_to_integer(IP3), list_to_integer(IP4)}.
226   -
227   -% Respond only to the configured list of domains
228   -check_dn(Domain, Domains) ->
229   - [ N || N <- Domains, lists:suffix(N, Domain) ] /= [].
230   -
231   -check_acl({IP1,IP2,IP3,IP4}, ACL) ->
232   - [ N || N <- ACL, lists:prefix(N, [IP1,IP2,IP3,IP4]) ] == [].
233   -
234   -check_port(Port, Allowed) ->
235   - lists:member(Port, Allowed).
236   -
237   -% Remove the trailing dash and convert to an integer
238   -list_to_sum(N) when is_list(N) ->
239   - list_to_integer(string:strip(N, right, $-)).
240   -
241   -forward({_IP, _Port} = Forward) ->
242   - {forward, Forward};
243   -forward(Id) when is_integer(Id) ->
244   - <<_Opt:8, Forward:8, SessionId:16>> = <<Id:32>>,
245   - {{session, Forward}, SessionId}.
299 src/seds_proxy.erl
... ... @@ -1,299 +0,0 @@
1   -%% Copyright (c) 2010, Michael Santos <michael.santos@gmail.com>
2   -%% All rights reserved.
3   -%%
4   -%% Redistribution and use in source and binary forms, with or without
5   -%% modification, are permitted provided that the following conditions
6   -%% are met:
7   -%%
8   -%% Redistributions of source code must retain the above copyright
9   -%% notice, this list of conditions and the following disclaimer.
10   -%%
11   -%% Redistributions in binary form must reproduce the above copyright
12   -%% notice, this list of conditions and the following disclaimer in the
13   -%% documentation and/or other materials provided with the distribution.
14   -%%
15   -%% Neither the name of the author nor the names of its contributors
16   -%% may be used to endorse or promote products derived from this software
17   -%% without specific prior written permission.
18   -%%
19   -%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20   -%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21   -%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22   -%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23   -%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   -%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25   -%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   -%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27   -%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   -%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29   -%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   -%% POSSIBILITY OF SUCH DAMAGE.
31   --module(seds_proxy).
32   --behaviour(gen_fsm).
33   -
34   --include_lib("kernel/src/inet_dns.hrl").
35   --include("seds.hrl").
36   -
37   --record(state, {
38   - ip,
39   - port,
40   - dnsfd, % dns server socket
41   - s, % proxied socket
42   -
43   - sum_up = 0, % number of bytes sent to server
44   - sum_down = 0, % number of bytes received from server
45   - buf = [], % last packet sent (for resend)
46   - data = [<<>>] % list of binaries: data returned by proxied server
47   - }).
48   -
49   -
50   --define(MAXDATA, 110).
51   -
52   -% Interface
53   --export([send/5]).
54   --export([start_link/2]).
55   --export([label/1]).
56   -% States
57   --export([connect/2,proxy/2]).
58   -% Behaviours
59   --export([init/1, handle_event/3, handle_sync_event/4,
60   - handle_info/3, terminate/3, code_change/4]).
61   -
62   -
63   -%%--------------------------------------------------------------------
64   -%%% Interface
65   -%%--------------------------------------------------------------------
66   -send(Pid, IP, Port, #dns_rec{} = Query, {up, Sum, Data}) when is_pid(Pid) ->
67   - gen_fsm:send_event(Pid, {up, IP, Port, Query, Sum, Data});
68   -send(Pid, IP, Port, #dns_rec{} = Query, {down, Sum, _}) when is_pid(Pid) ->
69   - gen_fsm:send_event(Pid, {down, IP, Port, Query, Sum}).
70   -
71   -%%--------------------------------------------------------------------
72   -%%% Behaviours
73   -%%--------------------------------------------------------------------
74   -start_link(Socket, {ServerIP, ServerPort}) ->
75   - {ok, Pid} = gen_fsm:start(?MODULE, [
76   - Socket,
77   - {ServerIP, ServerPort}
78   - ], []),
79   - erlang:monitor(process, Pid),
80   - {ok, Pid}.
81   -
82   -init([DNSSocket, {ServerIP, ServerPort}]) ->
83   - process_flag(trap_exit, true),
84   - {ok, connect, #state{
85   - dnsfd = DNSSocket,
86   - ip = ServerIP,
87   - port = ServerPort
88   - }, 0}.
89   -
90   -
91   -handle_event(_Event, StateName, State) ->
92   - {next_state, StateName, State}.
93   -
94   -handle_sync_event(_Event, _From, StateName, State) ->
95   - {next_state, StateName, State}.
96   -
97   -
98   -%%
99   -%% State: proxy
100   -%%
101   -
102   -% From server
103   -handle_info({tcp, Socket, Data}, proxy, #state{s = Socket} = State) ->
104   - {next_state, proxy, State#state{
105   - data = [Data|State#state.data]
106   - }, ?PROXY_TIMEOUT};
107   -
108   -% Connection closed
109   -handle_info({tcp_closed, Socket}, proxy, #state{s = Socket} = State) ->
110   - {stop, shutdown, State}.
111   -
112   -terminate(Reason, StateName, #state{
113   - ip = IP,
114   - port = Port,
115   - sum_up = Up,
116   - sum_down = Down
117   - }) ->
118   - error_logger:info_report([
119   - {session_end, {IP, Port}},
120   - {bytes_sent, Up},
121   - {bytes_rcvd, Down},
122   - {state, StateName},
123   - {reason, Reason}
124   - ]),
125   - ok.
126   -
127   -code_change(_OldVsn, StateName, State, _Extra) ->
128   - {ok, StateName, State}.
129   -
130   -
131   -%%--------------------------------------------------------------------
132   -%%% States
133   -%%--------------------------------------------------------------------
134   -
135   -%%
136   -%% connect
137   -%%
138   -connect(timeout, #state{ip = IP, port = Port} = State) ->
139   - {ok, Socket} = gen_tcp:connect(IP, Port, [
140   - binary,
141   - {packet, 0},
142   - {active, once}
143   - ], 5000),
144   - {next_state, proxy, State#state{s = Socket}}.
145   -
146   -
147   -%%
148   -%% proxy
149   -%%
150   -
151   -% client sent data to be forwarded to server
152   -proxy({up, IP, Port, Rec, ClientSum, Data},
153   - #state{
154   - sum_up = Sum,
155   - dnsfd = DNSSocket,
156   - s = Socket
157   - } = State) ->
158   -
159   - Payload = base32:decode(string:to_upper(Data)),
160   - Sum1 = Sum + length(Payload),
161   -
162   - case response(up, ClientSum, Sum, Rec) of
163   - error ->
164   - {stop, {up, out_of_sync}, State};
165   - duplicate ->
166   - error_logger:info_report([{dropping, {IP, Port}}]),
167   - {next_state, proxy, State, ?PROXY_TIMEOUT};
168   - Packet ->
169   -% error_logger:info_report([
170   -% {direction, up},
171   -% {dns_query, Packet}
172   -% ]),
173   - ok = gen_tcp:send(Socket, Payload),
174   - ok = gen_udp:send(DNSSocket, IP, Port, Packet),
175   - {next_state, proxy, State#state{sum_up = Sum1},
176   - ?PROXY_TIMEOUT}
177   - end;
178   -
179   -% client requested pending data from server
180   -proxy({down, IP, Port,
181   - #dns_rec{
182   - qdlist = [#dns_query{
183   - type = Type
184   - }|_]} = Rec, ClientSum},
185   - #state{
186   - sum_down = Sum,
187   - dnsfd = DNSSocket,
188   - s = Socket,
189   - data = Data,
190   - buf = Buf
191   - } = State) ->
192   -
193   - {Payload, Size, Rest} = data(Type, Data),
194   -
195   - case response({down, Payload}, ClientSum, Sum, Rec) of
196   - error ->
197   - {stop, {down, out_of_sync}, State};
198   - duplicate ->
199   - error_logger:info_report([{resending, {IP, Port, Sum}}]),
200   - ok = resend(DNSSocket, IP, Port, Type, Buf, Rec),
201   - {next_state, proxy, State#state{sum_down = Sum},
202   - ?PROXY_TIMEOUT};
203   - Packet ->
204   -% error_logger:info_report([
205   -% {direction, down},
206   -% {dns_query, Rec}
207   -% ]),
208   - ok = inet:setopts(Socket, [{active, once}]),
209   - ok = gen_udp:send(DNSSocket, IP, Port, Packet),
210   - {next_state, proxy, State#state{
211   - sum_down = Sum + Size,
212   - data = [Rest],
213   - buf = Data}, ?PROXY_TIMEOUT}
214   - end;
215   -
216   -proxy(timeout, State) ->
217   - {stop, timeout, State}.
218   -
219   -%%--------------------------------------------------------------------
220   -%%% Internal Functions
221   -%%--------------------------------------------------------------------
222   -seq(N) when is_integer(N) ->
223   - <<I1,I2,I3,I4>> = <<N:32>>,
224   - {I1,I2,I3,I4}.
225   -
226   -
227   -%% Encode the data returned by the server as a DNS record
228   -data(_, [<<>>]) ->
229   - {[],0,<<>>};
230   -data(Type, Data) when is_list(Data) ->
231   - data(Type, list_to_binary(lists:reverse(Data)));
232   -
233   -% TXT records
234   -data(txt, <<D1:?MAXDATA/bytes, D2:?MAXDATA/bytes, Rest/binary>>) ->
235   - {[base64:encode_to_string(D1), base64:encode_to_string(D2)], 2*?MAXDATA, Rest};
236   -data(txt, <<D1:?MAXDATA/bytes, Rest/binary>>) ->
237   - {[base64:encode_to_string(D1)], ?MAXDATA, Rest};
238   -data(txt, Data) ->
239   - {[base64:encode_to_string(Data)], byte_size(Data), <<>>};
240   -
241   -% NULL records
242   -data(null, <<D1:(?MAXDATA*2)/bytes, Rest/binary>>) ->
243   - {base64:encode(D1), ?MAXDATA*2, Rest};
244   -data(null, Data) ->
245   - {base64:encode(Data), byte_size(Data), <<>>};
246   -
247   -% CNAME records
248   -data(cname, <<D1:?MAXDATA/bytes, Rest/binary>>) ->
249   - {label(base32:encode(D1)), ?MAXDATA, Rest};
250   -data(cname, Data) ->
251   - {label(base32:encode(Data)), byte_size(Data), <<>>}.
252   -
253   -
254   -%% Each component (or label) of a CNAME can have a
255   -%% max length of 63 bytes. A "." divides the labels.
256   -label(String) when byte_size(String) < ?MAXLABEL ->
257   - String;
258   -label(String) ->
259   - re:replace(String, ".{63}", "&.", [global, {return, list}]).
260   -
261   -
262   -%% Packet sum checks
263   -response(up, Sum, Sum, Rec) ->
264   - encode(seq(Sum), Rec);
265   -response({down, Payload}, Sum, Sum, Rec) ->
266   - encode(Payload, Rec);
267   -response(_, Sum1, Sum2, _) when Sum1 < Sum2 ->
268   - duplicate;
269   -response(_, Sum1, Sum2, _) when Sum1 > Sum2 ->
270   - error.
271   -
272   -
273   -%% Encode the DNS response to the client
274   -encode(Data, #dns_rec{
275   - header = Header,
276   - qdlist = [#dns_query{
277   - domain = Domain,
278   - type = Type
279   - }|_]} = Rec) ->
280   - inet_dns:encode(Rec#dns_rec{
281   - header = Header#dns_header{
282   - qr = true,
283   - ra = true
284   - },
285   - anlist = [#dns_rr{
286   - domain = Domain,
287   - type = Type,
288   - data = Data
289   - }]}).
290   -
291   -
292   -% Resend a lost packet
293   -resend(_Socket, _IP, _Port, _Type, [], _Rec) ->
294   - ok;
295   -resend(Socket, IP, Port, Type, Data, Rec) ->
296   - {Payload, _, _} = data(Type, Data),
297   - gen_udp:send(Socket, IP, Port, encode(Payload, Rec)).
298   -
299   -
3  start.sh
... ... @@ -1,3 +0,0 @@
1   -#!/bin/sh
2   -
3   -exec erl -pa $PWD/ebin $PWD/deps/*/ebin $PWD/deps/*/deps/*/ebin -s seds start_link

0 comments on commit 04782b8

Please sign in to comment.
Something went wrong with that request. Please try again.