Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 197 lines (162 sloc) 6.004 kB
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
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(procket).
560517c @msantos Communicate with Unix sockets
authored
32 -include("procket.hrl").
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
33
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
34 -export([
560517c @msantos Communicate with Unix sockets
authored
35 init/0,open/1,open/2,
36 socket/3, listen/2,connect/2,
37 accept/1,accept/2,
38 fdopen/1,fdrecv/1,close/1,close/2,
65a61dc @msantos Add an NIF interface to ioctl()
authored
39 recvfrom/2,sendto/4,bind/2,
3649b5c @msantos Add an NIF setsockopt for promiscous mode
authored
40 ioctl/3,setsockopt/4
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
41 ]).
5bbc1bb @msantos Dynamically create path to procket executable too.
authored
42 -export([make_args/2,progname/0]).
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
43
44 -on_load(on_load/0).
45
5d8600f @msantos Dynamically create path to NIF relative to module.
authored
46
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
47 init() ->
48 on_load().
49
50 on_load() ->
5bbc1bb @msantos Dynamically create path to procket executable too.
authored
51 erlang:load_nif(progname(), []).
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
52
53
d7487f7 @msantos Close any file descriptor
authored
54 close(_) ->
55 erlang:error(not_implemented).
56
560517c @msantos Communicate with Unix sockets
authored
57 fdrecv(_) ->
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
58 erlang:error(not_implemented).
59
00214e3 @msantos Make the NIF stateless!
authored
60 close(_,_) ->
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
61 erlang:error(not_implemented).
62
560517c @msantos Communicate with Unix sockets
authored
63 accept(Socket) ->
64 accept(Socket, <<>>).
65 accept(_,_) ->
66 erlang:error(not_implemented).
67
74a854e @msantos Add sendto/4 and bind/2
authored
68 bind(_,_) ->
69 erlang:error(not_implemented).
70
560517c @msantos Communicate with Unix sockets
authored
71 connect(_,_) ->
72 erlang:error(not_implemented).
73
74 listen(_,_) ->
75 erlang:error(not_implemented).
76
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
77 recvfrom(_,_) ->
78 erlang:error(not_implemented).
79
560517c @msantos Communicate with Unix sockets
authored
80 socket(_,_,_) ->
81 erlang:error(not_implemented).
82
65a61dc @msantos Add an NIF interface to ioctl()
authored
83 ioctl(_,_,_) ->
84 erlang:error(not_implemented).
85
74a854e @msantos Add sendto/4 and bind/2
authored
86 sendto(_,_,_,_) ->
194feb8 @msantos Add NIF versions of recvfrom/sendto
authored
87 erlang:error(not_implemented).
88
3649b5c @msantos Add an NIF setsockopt for promiscous mode
authored
89 setsockopt(_,_,_,_) ->
90 erlang:error(not_implemented).
91
560517c @msantos Communicate with Unix sockets
authored
92
93 open(Port) ->
94 open(Port, []).
95 open(Port, Options) when is_integer(Port), is_list(Options) ->
cfafb55 @msantos Clean up local socket temp directory
authored
96 Opt = case proplists:get_value(pipe, Options) of
97 undefined ->
98 Tmp = mktmp:dirname(),
99 ok = mktmp:make_dir(Tmp),
100 Path = Tmp ++ "/sock",
101 [{pipe, Path}, {tmpdir, Tmp}] ++ Options;
102 _ ->
103 [{tmpdir, false}] ++ Options
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
104 end,
560517c @msantos Communicate with Unix sockets
authored
105 open1(Port, Opt).
cfafb55 @msantos Clean up local socket temp directory
authored
106
560517c @msantos Communicate with Unix sockets
authored
107 open1(Port, Options) ->
cfafb55 @msantos Clean up local socket temp directory
authored
108 Pipe = proplists:get_value(pipe, Options),
560517c @msantos Communicate with Unix sockets
authored
109 {ok, Sockfd} = fdopen(Pipe),
cfafb55 @msantos Clean up local socket temp directory
authored
110 Cmd = make_args(Port, Options),
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
111 case os:cmd(Cmd) of
112 [] ->
560517c @msantos Communicate with Unix sockets
authored
113 FD = fdget(Sockfd),
cfafb55 @msantos Clean up local socket temp directory
authored
114 cleanup(Sockfd, Pipe, Options),
00214e3 @msantos Make the NIF stateless!
authored
115 FD;
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
116 Error ->
cfafb55 @msantos Clean up local socket temp directory
authored
117 cleanup(Sockfd, Pipe, Options),
00214e3 @msantos Make the NIF stateless!
authored
118 {error, {procket_cmd, Error}}
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
119 end.
120
cfafb55 @msantos Clean up local socket temp directory
authored
121 cleanup(Sockfd, Pipe, Options) ->
122 close(Sockfd, Pipe),
123 case proplists:get_value(tmpdir, Options) of
124 false ->
125 ok;
126 Path ->
127 mktmp:close(Path)
128 end.
129
560517c @msantos Communicate with Unix sockets
authored
130 fdopen(Path) when is_list(Path) ->
131 fdopen(list_to_binary(Path));
132 fdopen(Path) when is_binary(Path), byte_size(Path) < ?UNIX_PATH_MAX ->
133 {ok, Socket} = socket(?PF_LOCAL, ?SOCK_STREAM, 0),
134 Sun = <<?PF_LOCAL:16/native, Path/binary, 0:((?UNIX_PATH_MAX-byte_size(Path))*8)>>,
135 ok = bind(Socket, Sun),
136 ok = listen(Socket, ?BACKLOG),
137 {ok, Socket}.
138
139 fdget(Socket) ->
140 {ok, S} = accept(Socket),
141 fdrecv(S).
142
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
143 make_args(Port, Options) ->
144 Bind = " " ++ case proplists:lookup(ip, Options) of
145 none ->
146 integer_to_list(Port);
147 IP ->
148 get_switch(IP) ++ ":" ++ integer_to_list(Port)
149 end,
5bbc1bb @msantos Dynamically create path to procket executable too.
authored
150 proplists:get_value(progname, Options, "sudo " ++ progname()) ++ " " ++
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
151 string:join([ get_switch(proplists:lookup(Arg, Options)) || Arg <- [
152 pipe,
96f8a1e @msantos Allow arbitrary socket family, type and protocol
authored
153 protocol,
154 family,
eba4ec3 Added option to bind a socket to a specific interface
klaar authored
155 type,
156 interface
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
157 ], proplists:lookup(Arg, Options) /= none ],
158 " ") ++ Bind.
159
160 get_switch({pipe, Arg}) -> "-p " ++ Arg;
96f8a1e @msantos Allow arbitrary socket family, type and protocol
authored
161
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
162 get_switch({protocol, raw}) -> "-P 0";
163 get_switch({protocol, icmp}) -> "-P 1";
164 get_switch({protocol, tcp}) -> "-P 6";
165 get_switch({protocol, udp}) -> "-P 17";
73d8247 @msantos Type conversion is wardsback
authored
166 get_switch({protocol, Proto}) when is_integer(Proto) -> "-P " ++ integer_to_list(Proto);
96f8a1e @msantos Allow arbitrary socket family, type and protocol
authored
167
168 get_switch({type, stream}) -> "-T 1";
169 get_switch({type, dgram}) -> "-T 2";
170 get_switch({type, raw}) -> "-T 3";
73d8247 @msantos Type conversion is wardsback
authored
171 get_switch({type, Type}) when is_integer(Type) -> "-T " ++ integer_to_list(Type);
96f8a1e @msantos Allow arbitrary socket family, type and protocol
authored
172
173 get_switch({family, unspec}) -> "-F 0";
174 get_switch({family, inet}) -> "-F 2";
175 get_switch({family, packet}) -> "-F 17";
73d8247 @msantos Type conversion is wardsback
authored
176 get_switch({family, Family}) when is_integer(Family) -> "-F " ++ integer_to_list(Family);
96f8a1e @msantos Allow arbitrary socket family, type and protocol
authored
177
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
178 get_switch({ip, Arg}) when is_tuple(Arg) -> inet_parse:ntoa(Arg);
eba4ec3 Added option to bind a socket to a specific interface
klaar authored
179 get_switch({ip, Arg}) when is_list(Arg) -> Arg;
180
315b8cf Add interface name sanitation
klaar authored
181 get_switch({interface, Name}) when is_list(Name) ->
182 % An interface name is expected to consist of a reasonable
183 % subset of all charactes, use a whitelist and extend it if needed
184 SName = [C || C <- Name, ((C >= $a) and (C =< $z)) or ((C >= $A) and (C =< $Z))
185 or ((C >= $0) and (C =< $9)) or (C == $.)],
186 "-I " ++ SName.
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
187
5bbc1bb @msantos Dynamically create path to procket executable too.
authored
188 progname() ->
189 filename:join([
190 filename:dirname(code:which(?MODULE)),
191 "..",
192 "priv",
193 ?MODULE
194 ]).
195
441fde8 @msantos Interface for requesting privileged sockets in Erlang.
authored
196
Something went wrong with that request. Please try again.