Skip to content
Newer
Older
100644 208 lines (144 sloc) 6.05 KB
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
1 epcap\_compile is an Erlang library for compiling PCAP filters to BPF
589f606 @msantos Remove trailing whitespace
authored
2 programs (see pcap-filter(7)).
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
3
4 epcap\_compile uses the NIF interface to wrap pcap\_compile(3PCAP)
5 from libpcap.
6
7
8 ## WARNING
9
10 Since the library passes the filter string to pcap\_compile(3PCAP)
11 directly, any bugs in pcap\_compile() may cause the Erlang VM to crash. Do
12 not use filters from untrusted sources.
13
1a5cca4 @msantos Add a BSD example
authored
14 Also note very large filters may block the scheduler. For example:
15
16 epcap_compile:compile(string:copies("ip and ", 50000) ++ "ip").
17
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
18
19 ## REQUIREMENTS
20
21 * libpcap
22
23 On Ubuntu: sudo apt-get install libpcap-dev
24
1a5cca4 @msantos Add a BSD example
authored
25 These libraries are not required but can be used with epcap\_compile:
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
26
27 * pkt: https://github.com/msantos/pkt.git
28
29 Use pkt to map the datalinktype to a number:
30
31 pkt:dlt(en10mb)
32
33 * procket: https://github.com/msantos/procket.git
34
31da3bd @msantos Add an example of filtering an inet socket
authored
35 Set a BPF filter on any kind of socket (Linux) or on a BPF device
36 (BSD).
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
37
38
39 ## COMPILING
40
41 make
42
43
44 ## EXPORTS
45
46 compile(Filter) -> {ok, Fcode} | {error, Error}
47 compile(Filter, Options) -> {ok, Fcode} | {error, Error}
589f606 @msantos Remove trailing whitespace
authored
48
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
49 Types Filter = string() | binary()
50 Fcode = [ Insn ]
51 Insn = binary()
52 Error = enomem | string()
53 Options = [ Option ]
54 Option = {optimize, boolean()}
55 | {netmask, IPaddr}
56 | {dlt, integer()}
57 | {snaplen, integer()}
58
59 Filter is a string in pcap-filter(7) format.
60
61 If the PCAP filter is successfully compiled to a BPF program,
62 a list of BPF instructions is returned.
63
64 If an error occurs, a string describing the error is returned
65 to the caller.
66
1a5cca4 @msantos Add a BSD example
authored
67 compile/1 defaults to:
68
69 * optimization enabled
70
71 * an unspecified netmask (filters specifying the broadcast
72 will return an error)
73
74 * datalinktype set to ethernet (DLT_EN10MB)
75
f168c08 @msantos Clean up examples, README
authored
76 * a packet length of 65535 bytes
1a5cca4 @msantos Add a BSD example
authored
77
f168c08 @msantos Clean up examples, README
authored
78 See pcap_compile(3PCAP) for information about each of these options.
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
79
80
81 ## EXAMPLES
82
83 ### Compile a PCAP Filter
84
85 $ erl -pa ebin
86 1> epcap_compile:compile("ip and ( src host 192.168.10.1 or dst host 192.168.10.1 )").
87 {ok,[<<40,0,0,0,12,0,0,0>>,
88 <<21,0,0,5,0,8,0,0>>,
89 <<32,0,0,0,26,0,0,0>>,
90 <<21,0,2,0,1,10,168,192>>,
91 <<32,0,0,0,30,0,0,0>>,
92 <<21,0,0,1,1,10,168,192>>,
93 <<6,0,0,0,255,255,0,0>>,
94 <<6,0,0,0,0,0,0,0>>]}
95
96 The same BPF program can be generated from Erlang by using the bpf module in procket:
97
98 ip({A,B,C,D}) ->
99 IP = (A bsl 24) bor (B bsl 16) bor (C bsl 8) bor D,
589f606 @msantos Remove trailing whitespace
authored
100
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
101 [
102 % Ethernet
103 ?BPF_STMT(?BPF_LD+?BPF_H+?BPF_ABS, 12), % offset = Ethernet Type
104 ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, ?ETHERTYPE_IP, 0, 5), % type = IP
589f606 @msantos Remove trailing whitespace
authored
105
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
106 % IP
107 ?BPF_STMT(?BPF_LD+?BPF_W+?BPF_ABS, 26), % offset = Source IP address
108 ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, IP, 2, 0), % source = {A,B,C,D}
109 ?BPF_STMT(?BPF_LD+?BPF_W+?BPF_ABS, 30), % offset = Destination IP address
110 ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, IP, 0, 1), % destination = {A,B,C,D}
589f606 @msantos Remove trailing whitespace
authored
111
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
112 % Amount of packet to return
113 ?BPF_STMT(?BPF_RET+?BPF_K, 16#FFFFFFFF), % Return up to 2^32-1 bytes
114 ?BPF_STMT(?BPF_RET+?BPF_K, 0) % Return 0 bytes: drop packet
115 ].
116
117
31da3bd @msantos Add an example of filtering an inet socket
authored
118 ### Apply a BPF Filter to a PF\_PACKET Socket (Linux)
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
119
120 -module(lsf).
121 -export([f/0, f/1]).
589f606 @msantos Remove trailing whitespace
authored
122
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
123 f() ->
124 {ok, Fcode} = epcap_compile:compile("tcp and ( port 80 or port 443 )"),
125 f(Fcode).
589f606 @msantos Remove trailing whitespace
authored
126
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
127 f(Fcode) when is_list(Fcode) ->
128 {ok, S} = packet:socket(),
129 {ok, _} = packet:filter(S, Fcode),
589f606 @msantos Remove trailing whitespace
authored
130
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
131 loop(S).
589f606 @msantos Remove trailing whitespace
authored
132
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
133 loop(S) ->
134 case procket:recv(S, 1500) of
135 {ok, Data} ->
136 error_logger:info_report(Data),
137 loop(S);
138 {error, eagain} ->
139 timer:sleep(10),
140 loop(S)
141 end.
142
31da3bd @msantos Add an example of filtering an inet socket
authored
143 ### Apply a BPF Filter to a TCP Socket (Linux)
144
145 -module(lsf_inet).
146 -export([f/0]).
147
148 f() ->
149 {ok, Fcode} = epcap_compile:compile("tcp and port 443"),
150 unfiltered(Fcode),
151 filtered(Fcode).
152
153 unfiltered(Fcode) when is_list(Fcode) ->
154 {ok, S} = gen_tcp:connect("www.google.com", 80,
155 [binary, {packet, 0}, {active, false}]),
156
157 ok = gen_tcp:send(S, "GET / HTTP/1.0\r\n\r\n"),
158 {ok, R} = gen_tcp:recv(S, 0, 5000),
159 error_logger:info_report([{unfiltered, R}]),
160 ok = gen_tcp:close(S).
161
162 filtered(Fcode) when is_list(Fcode) ->
163 {ok, S} = gen_tcp:connect("www.google.com", 80,
164 [binary, {packet, 0}, {active, false}]),
165
166 {ok, FD} = inet:getfd(S),
167 {ok, _} = packet:filter(FD, Fcode),
168
169 ok = gen_tcp:send(S, "GET / HTTP/1.0\r\n\r\n"),
170 {error, timeout} = gen_tcp:recv(S, 0, 5000),
171 error_logger:info_report([{filtered, "connection timeout"}]),
172
173 ok = gen_tcp:close(S).
174
1a5cca4 @msantos Add a BSD example
authored
175 ### Applying a BPF Filter on BSD
47d1a6a @msantos Compile PCAP filters to BPF programs
authored
176
177
1a5cca4 @msantos Add a BSD example
authored
178 -module(bpf_ex).
f168c08 @msantos Clean up examples, README
authored
179 -export([f/1, f/2]).
1a5cca4 @msantos Add a BSD example
authored
180
f168c08 @msantos Clean up examples, README
authored
181 f(Dev) ->
182 f(Dev, "ip and ( src host 192.168.10.1 or dst host 192.168.10.1 )").
1a5cca4 @msantos Add a BSD example
authored
183
f168c08 @msantos Clean up examples, README
authored
184 f(Dev, Filter) ->
1a5cca4 @msantos Add a BSD example
authored
185 {ok, Socket, Length} = bpf:open(Dev),
186 {ok, Fcode} = epcap_compile:compile(Filter),
187 {ok, _} = bpf:ctl(Socket, setf, Fcode),
188 loop(Socket, Length).
189
190 loop(Socket, Length) ->
191 case procket:read(Socket, Length) of
192 {ok, <<>>} ->
193 loop(Socket, Length);
194 {ok, Data} ->
195 {bpf_buf, Time, Datalen, Packet, Rest} = bpf:buf(Data),
196 error_logger:info_report([
197 {time, Time},
198 {packet_is_truncated, Datalen /= byte_size(Packet)},
199 {packet, Packet},
200 {packet_size, byte_size(Packet)},
201 {remaining, byte_size(Rest)}
202 ]),
203 loop(Socket, Length);
204 {error, eagain} ->
205 timer:sleep(10),
206 loop(Socket, Length)
207 end.
Something went wrong with that request. Please try again.