Permalink
Browse files

Initial support for active mode

Support for passing the fd to erlang:port_open/2. Add an example of
using active mode.
  • Loading branch information...
msantos committed Sep 26, 2011
1 parent 200307c commit 1dbf4a4ff3e8570f2fb39c3208c6dad1cb5d85da
Showing with 104 additions and 14 deletions.
  1. +12 −4 README.md
  2. +21 −8 src/tuncer.erl
  3. +2 −2 src/vpwn.erl
  4. +69 −0 src/vpwn_active.erl
View
@@ -141,17 +141,25 @@ Tuncer is a stand up guy and just like him, tuncer has your back.
Set the gid owning the interface.
- read(Ref) -> {ok, Buf} | {error, posix()}
- read(Ref, Size) -> {ok, Buf} | {error, posix()}
+ getfd(Ref) -> integer()
Types Ref = pid()
+
+ Get the file descriptor associated with the process. Use getfd/1
+ with read/1,2 and write/2 to interact directly with the tuntap device
+ (bypassing the gen_server).
+
+ read(Fd) -> {ok, Buf} | {error, posix()}
+ read(Fd, Size) -> {ok, Buf} | {error, posix()}
+
+ Types Fd = integer()
Size = integer() Buf = binary()
Read _Size_ bytes from the interface.
- write(Ref, Buf) -> ok | {error, posix()}
+ write(Fd, Buf) -> ok | {error, posix()}
- Types Ref = pid()
+ Types Ref = integer()
Buf = binary()
Write _Buf_ to the interface.
View
@@ -34,7 +34,7 @@
-export([
create/0, create/1, create/2,
- devname/1, flags/1, fd/1,
+ devname/1, flags/1, getfd/1,
destroy/1,
persist/2,
@@ -43,6 +43,8 @@
read/1, read/2,
write/2,
+ send/2,
+
header/1,
up/2, down/1,
@@ -88,7 +90,7 @@ devname(Ref) when is_pid(Ref) ->
flags(Ref) when is_pid(Ref) ->
gen_server:call(Ref, flags).
-fd(Ref) when is_pid(Ref) ->
+getfd(Ref) when is_pid(Ref) ->
gen_server:call(Ref, fd).
destroy(Ref) when is_pid(Ref) ->
@@ -120,16 +122,17 @@ mtu(Ref) when is_pid(Ref) ->
mtu(Ref, MTU) when is_pid(Ref), is_integer(MTU) ->
gen_server:call(Ref, {mtu, MTU}).
-read(Ref) ->
- read(Ref, 16#FFFF).
-read(Ref, Len) when is_pid(Ref), is_integer(Len) ->
- Fd = fd(Ref),
+read(Fd) ->
+ read(Fd, 16#FFFF).
+read(Fd, Len) when is_integer(Fd), is_integer(Len) ->
procket:read(Fd, Len).
-write(Ref, Data) when is_pid(Ref), is_binary(Data) ->
- Fd = fd(Ref),
+write(Fd, Data) when is_integer(Fd), is_binary(Data) ->
procket:write(Fd, Data).
+send(Ref, Data) when is_pid(Ref), is_binary(Data) ->
+ gen_server:call(Ref, {send, Data}).
+
% FIXME: race condition: events can be delivered out of order
controlling_process(Ref, Pid) when is_pid(Ref), is_pid(Pid) ->
flush_events(Ref, Pid),
@@ -186,6 +189,16 @@ handle_call({controlling_process, Pid}, {Owner,_}, #state{pid = Owner} = State)
%%
%% manipulate the tun/tap device
%%
+handle_call({send, Data}, _From, #state{port = Port} = State) ->
+ Reply = try erlang:port_command(Port, Data) of
+ true ->
+ ok
+ catch
+ error:Error ->
+ {error, Error}
+ end,
+ {reply, Reply, State};
+
handle_call({persist, Status}, _From, #state{fd = FD} = State) ->
Reply = tunctl:persist(FD, Status),
{reply, Reply, State};
View
@@ -63,13 +63,13 @@ read(Dev, Pid) ->
timer:sleep(10),
read(Dev, Pid);
{ok, Data} ->
- Pid ! {data, Data},
+ Pid ! {vpwn, Data},
read(Dev, Pid)
end.
write(Dev) ->
receive
- {data, Data} ->
+ {vpwn, Data} ->
ok = tuncer:write(Dev, Data),
write(Dev);
Error ->
View
@@ -0,0 +1,69 @@
+%% Copyright (c) 2011, Michael Santos <michael.santos@gmail.com>
+%% All rights reserved.
+%%
+%% Redistribution and use in source and binary forms, with or without
+%% modification, are permitted provided that the following conditions
+%% are met:
+%%
+%% Redistributions of source code must retain the above copyright
+%% notice, this list of conditions and the following disclaimer.
+%%
+%% Redistributions in binary form must reproduce the above copyright
+%% notice, this list of conditions and the following disclaimer in the
+%% documentation and/or other materials provided with the distribution.
+%%
+%% Neither the name of the author nor the names of its contributors
+%% may be used to endorse or promote products derived from this software
+%% without specific prior written permission.
+%%
+%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+%% "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+%% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+%% FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+%% COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+%% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+%% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+%% ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+%% POSSIBILITY OF SUCH DAMAGE.
+
+%%
+%% VPN over Erlang distribution protocol (active mode)
+%%
+%% Usage:
+%% vpwn:start('node@vpn.example.com', {10,10,10,1}, {10,10,10,2}).
+%%
+-module(vpwn_active).
+-export([start/3]).
+
+
+start(Node, SrcIP, DstIP) ->
+ Pid = peer(Node, SrcIP, DstIP),
+
+ {ok, Dev} = tuncer:create("vpwn", [tap, no_pi, {active, true}]),
+ ok = tuncer:up(Dev, SrcIP),
+
+ proxy(Dev, Pid).
+
+% Parent
+peer(N, SrcIP, DstIP) when is_atom(N) ->
+ pong = net_adm:ping(N),
+ Self = self(),
+ spawn_link(N, vpwn, start, [Self, DstIP, SrcIP]);
+% Child
+peer(N, _, _) when is_pid(N) ->
+ N.
+
+proxy(Dev, Pid) ->
+ receive
+ {tuntap, _Pid, Data} ->
+ Pid ! {vpwn, Data},
+ read(Dev, Pid);
+ {vpwn, Data} ->
+ ok = tuncer:send(Dev, Data),
+ read(Dev, Pid);
+ Error ->
+ Error
+ end.

0 comments on commit 1dbf4a4

Please sign in to comment.