Skip to content

HTTPS clone URL

Subversion checkout URL

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