Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 171 lines (138 sloc) 5.337 kb
69f5544a »
2010-10-23 User space ethernet bridge
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(herp).
32 -behaviour(gen_server).
33
34 -define(SERVER, ?MODULE).
35
36 -include("epcap_net.hrl").
37
f643f9b7 »
2010-10-24 Formatting and function name changes
38 -export([start/0, start/1, stop/0, bridge/2]).
69f5544a »
2010-10-23 User space ethernet bridge
39 -export([start_link/1]).
40 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
41 terminate/2, code_change/3]).
42
43 -record(state, {
44 s, % PF_PACKET socket
45 i, % IF Index
46 gw, % Gateway MAC address
47 ip, % our IP address
48 mac % our MAC address
49 }).
50
51
f643f9b7 »
2010-10-24 Formatting and function name changes
52 %%--------------------------------------------------------------------
53 %%% Exports
54 %%--------------------------------------------------------------------
69f5544a »
2010-10-23 User space ethernet bridge
55 start() ->
56 [Dev] = packet:default_interface(),
57 start(Dev).
58 start(Dev) ->
59 start_link(Dev).
60
f643f9b7 »
2010-10-24 Formatting and function name changes
61 stop() ->
62 gen_server:call(?MODULE, stop).
63
69f5544a »
2010-10-23 User space ethernet bridge
64 start_link(Dev) ->
65 gen_server:start_link({local, ?SERVER}, ?MODULE, [Dev], []).
66
f643f9b7 »
2010-10-24 Formatting and function name changes
67 bridge(MAC, Packet) when is_binary(Packet) ->
68 gen_server:call(?MODULE, {packet, MAC, Packet}).
69
70
71 %%--------------------------------------------------------------------
72 %%% Callbacks
73 %%--------------------------------------------------------------------
69f5544a »
2010-10-23 User space ethernet bridge
74 init([Dev]) ->
75 {ok, PL} = inet:ifget(Dev, [addr, hwaddr]),
76
f643f9b7 »
2010-10-24 Formatting and function name changes
77 {ok, {M1,M2,M3,M4,M5,M6}, _} = packet:gateway(Dev),
69f5544a »
2010-10-23 User space ethernet bridge
78
79 IP = proplists:get_value(addr, PL),
80 MAC = list_to_binary(proplists:get_value(hwaddr, PL)),
81
82 {ok, Socket} = packet:socket(?ETH_P_IP),
83 Ifindex = packet:ifindex(Socket, Dev),
84
85 State = #state{
86 s = Socket,
87 i = Ifindex,
88 ip = IP,
89 mac = MAC,
f643f9b7 »
2010-10-24 Formatting and function name changes
90 gw = <<M1,M2,M3,M4,M5,M6>>
69f5544a »
2010-10-23 User space ethernet bridge
91 },
92
93 spawn_link(fun() -> sniff(Socket, State) end),
94
95 {ok, State}.
96
97 handle_call({packet, DstMAC, Packet}, _From, #state{
98 mac = MAC,
99 s = Socket,
8263bafc »
2010-10-26 Reduce the work parsing packets
100 i = Ifindex} = State) ->
69f5544a »
2010-10-23 User space ethernet bridge
101
102 Ether = epcap_net:ether(#ether{
103 dhost = DstMAC,
104 shost = MAC,
105 type = ?ETH_P_IP
106 }),
107
108 error_logger:info_report([{src, machex(MAC)}, {dst, machex(DstMAC)}]),
109 packet:send(Socket, Ifindex, list_to_binary([Ether, Packet])),
110 {reply, ok, State};
111
112 handle_call(stop, _From, State) ->
f2dc7de4 »
2010-10-25 Kill linked processes on exit
113 {stop, shutdown, ok, State}.
69f5544a »
2010-10-23 User space ethernet bridge
114
115 handle_cast(_Msg, State) ->
116 {noreply, State}.
117
118 % WTF?
119 handle_info(Info, State) ->
120 error_logger:error_report([wtf, Info]),
121 {noreply, State}.
122
123 terminate(_Reason, _State) ->
124 ok.
125
126 code_change(_OldVsn, State, _Extra) ->
127 {ok, State}.
128
129
f643f9b7 »
2010-10-24 Formatting and function name changes
130 %%--------------------------------------------------------------------
131 %%% Read ARP packets from the network and send them to the
132 %%% gen_server
133 %%--------------------------------------------------------------------
69f5544a »
2010-10-23 User space ethernet bridge
134 sniff(Socket, State) ->
135 case procket:recvfrom(Socket, 65535) of
136 nodata ->
137 timer:sleep(10),
138 sniff(Socket, State);
139 {ok, Data} ->
8263bafc »
2010-10-26 Reduce the work parsing packets
140 {#ether{} = Ether, Packet} = epcap_net:ether(Data),
141 filter(Ether, Packet, State),
69f5544a »
2010-10-23 User space ethernet bridge
142 sniff(Socket, State);
143 Error ->
144 error_logger:error_report(Error)
145 end.
146
8263bafc »
2010-10-26 Reduce the work parsing packets
147 filter(#ether{shost = MAC}, _, #state{mac = MAC}) ->
69f5544a »
2010-10-23 User space ethernet bridge
148 ok;
8263bafc »
2010-10-26 Reduce the work parsing packets
149 filter(#ether{type = ?ETH_P_IP}, Packet, State) ->
150 {#ipv4{daddr = DA}, _} = epcap_net:ipv4(Packet),
151 filter1(DA, Packet, State);
152 filter(_, _, _) ->
153 ok.
154
155 filter1(IP, _, #state{ip = IP}) ->
156 ok;
157 filter1(IP, Packet, #state{gw = GW}) ->
158 MAC = case packet:arplookup(IP) of
69f5544a »
2010-10-23 User space ethernet bridge
159 false -> GW;
160 {M1,M2,M3,M4,M5,M6} -> <<M1,M2,M3,M4,M5,M6>>
161 end,
8263bafc »
2010-10-26 Reduce the work parsing packets
162 bridge(MAC, Packet).
69f5544a »
2010-10-23 User space ethernet bridge
163
164
f643f9b7 »
2010-10-24 Formatting and function name changes
165 %%--------------------------------------------------------------------
166 %%% Internal functions
167 %%--------------------------------------------------------------------
69f5544a »
2010-10-23 User space ethernet bridge
168 machex(MAC) when is_binary(MAC) ->
169 lists:flatten(string:join([ io_lib:format("~.16B", [N]) || <<N>> <= MAC ], ":")).
170
Something went wrong with that request. Please try again.