Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 163 lines (135 sloc) 5.245 kb
27c51ed Michael Santos Fix build as dep
authored
1 %% Copyright (c) 2010-2012, Michael Santos <michael.santos@gmail.com>
69f5544 Michael Santos User space ethernet bridge
authored
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
27c51ed Michael Santos Fix build as dep
authored
36 -include_lib("pkt/include/pkt.hrl").
69f5544 Michael Santos User space ethernet bridge
authored
37
ed0ff89 Michael Santos Use port_open/2
authored
38 -export([start/0, start/1, stop/0]).
69f5544 Michael Santos User space ethernet bridge
authored
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, {
ed0ff89 Michael Santos Use port_open/2
authored
44 port,
69f5544 Michael Santos User space ethernet bridge
authored
45 s, % PF_PACKET socket
46 i, % IF Index
47 gw, % Gateway MAC address
48 ip, % our IP address
49 mac % our MAC address
50 }).
51
52
f643f9b Michael Santos Formatting and function name changes
authored
53 %%--------------------------------------------------------------------
54 %%% Exports
55 %%--------------------------------------------------------------------
69f5544 Michael Santos User space ethernet bridge
authored
56 start() ->
57 [Dev] = packet:default_interface(),
58 start(Dev).
59 start(Dev) ->
60 start_link(Dev).
61
f643f9b Michael Santos Formatting and function name changes
authored
62 stop() ->
63 gen_server:call(?MODULE, stop).
64
69f5544 Michael Santos User space ethernet bridge
authored
65 start_link(Dev) ->
66 gen_server:start_link({local, ?SERVER}, ?MODULE, [Dev], []).
67
f643f9b Michael Santos Formatting and function name changes
authored
68
69 %%--------------------------------------------------------------------
70 %%% Callbacks
71 %%--------------------------------------------------------------------
69f5544 Michael Santos User space ethernet bridge
authored
72 init([Dev]) ->
73 {ok, PL} = inet:ifget(Dev, [addr, hwaddr]),
74
f643f9b Michael Santos Formatting and function name changes
authored
75 {ok, {M1,M2,M3,M4,M5,M6}, _} = packet:gateway(Dev),
69f5544 Michael Santos User space ethernet bridge
authored
76
77 IP = proplists:get_value(addr, PL),
78 MAC = list_to_binary(proplists:get_value(hwaddr, PL)),
79
80 {ok, Socket} = packet:socket(?ETH_P_IP),
81 Ifindex = packet:ifindex(Socket, Dev),
82
ed0ff89 Michael Santos Use port_open/2
authored
83 Port = open_port({fd, Socket, Socket}, [stream, binary]),
84
85 {ok, #state{
86 port = Port,
69f5544 Michael Santos User space ethernet bridge
authored
87 s = Socket,
88 i = Ifindex,
89 ip = IP,
90 mac = MAC,
f643f9b Michael Santos Formatting and function name changes
authored
91 gw = <<M1,M2,M3,M4,M5,M6>>
ed0ff89 Michael Santos Use port_open/2
authored
92 }}.
69f5544 Michael Santos User space ethernet bridge
authored
93
94 handle_call(stop, _From, State) ->
f2dc7de Michael Santos Kill linked processes on exit
authored
95 {stop, shutdown, ok, State}.
69f5544 Michael Santos User space ethernet bridge
authored
96
97 handle_cast(_Msg, State) ->
98 {noreply, State}.
99
ed0ff89 Michael Santos Use port_open/2
authored
100 %%--------------------------------------------------------------------
101 %%% Port communication
102 %%--------------------------------------------------------------------
103 handle_info({Port, {data, Data}}, #state{port = Port} = State) ->
104 {#ether{} = Ether, Packet} = pkt:ether(Data),
105 case filter(Ether, Packet, State) of
106 ok -> ok;
107 {MAC, Packet} -> bridge(MAC, Packet, State)
108 end,
109 {noreply, State};
110
69f5544 Michael Santos User space ethernet bridge
authored
111 % WTF?
112 handle_info(Info, State) ->
113 error_logger:error_report([wtf, Info]),
114 {noreply, State}.
115
116 terminate(_Reason, _State) ->
117 ok.
118
119 code_change(_OldVsn, State, _Extra) ->
120 {ok, State}.
121
122
f643f9b Michael Santos Formatting and function name changes
authored
123 %%--------------------------------------------------------------------
124 %%% Read ARP packets from the network and send them to the
125 %%% gen_server
126 %%--------------------------------------------------------------------
8263baf Michael Santos Reduce the work parsing packets
authored
127 filter(#ether{shost = MAC}, _, #state{mac = MAC}) ->
69f5544 Michael Santos User space ethernet bridge
authored
128 ok;
8263baf Michael Santos Reduce the work parsing packets
authored
129 filter(#ether{type = ?ETH_P_IP}, Packet, State) ->
d8ab9a8 Michael Santos Switch to pkt from epcap_net
authored
130 {#ipv4{daddr = DA}, _} = pkt:ipv4(Packet),
27c51ed Michael Santos Fix build as dep
authored
131 filter_1(DA, Packet, State);
8263baf Michael Santos Reduce the work parsing packets
authored
132 filter(_, _, _) ->
133 ok.
134
27c51ed Michael Santos Fix build as dep
authored
135 filter_1(IP, _, #state{ip = IP}) ->
8263baf Michael Santos Reduce the work parsing packets
authored
136 ok;
27c51ed Michael Santos Fix build as dep
authored
137 filter_1(IP, Packet, #state{gw = GW}) ->
8263baf Michael Santos Reduce the work parsing packets
authored
138 MAC = case packet:arplookup(IP) of
69f5544 Michael Santos User space ethernet bridge
authored
139 false -> GW;
140 {M1,M2,M3,M4,M5,M6} -> <<M1,M2,M3,M4,M5,M6>>
141 end,
ed0ff89 Michael Santos Use port_open/2
authored
142 {MAC, Packet}.
143
144 bridge(DstMAC, Packet, #state{
145 mac = MAC,
146 s = Socket,
147 i = Ifindex}) ->
148 Ether = pkt:ether(#ether{
149 dhost = DstMAC,
150 shost = MAC,
151 type = ?ETH_P_IP
152 }),
153 error_logger:info_report([{src, machex(MAC)}, {dst, machex(DstMAC)}]),
154 packet:send(Socket, Ifindex, <<Ether/binary, Packet/binary>>),
155 ok.
69f5544 Michael Santos User space ethernet bridge
authored
156
157
f643f9b Michael Santos Formatting and function name changes
authored
158 %%--------------------------------------------------------------------
159 %%% Internal functions
160 %%--------------------------------------------------------------------
69f5544 Michael Santos User space ethernet bridge
authored
161 machex(MAC) when is_binary(MAC) ->
162 lists:flatten(string:join([ io_lib:format("~.16B", [N]) || <<N>> <= MAC ], ":")).
Something went wrong with that request. Please try again.