Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 231 lines (196 sloc) 7.241 kb
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
1 %% Copyright (c) 2009, 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(epcap_net).
32
33 -include("epcap_net.hrl").
34
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
35 -define(ETHERHDRLEN, 16).
36 -define(IPV4HDRLEN, 20).
88cacab @oliv3 IPv6 support
oliv3 authored
37 -define(IPV6HDRLEN, 40).
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
38 -define(TCPHDRLEN, 20).
39 -define(UDPHDRLEN, 8).
40 -define(ICMPHDRLEN, 8).
41
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
42 -export([
43 checksum/1,
44 checksum/3,
45 decapsulate/1,
46 makesum/1,
47 valid/1,
48 ether/1,
49 ether_addr/1,
50 icmp/1,
51 ipv4/1,
1fac0f7 @msantos Now compiler friendly, typo free!
authored
52 payload/1,
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
53 proto/1,
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
54 tcp/1,
55 tcp_flags/1,
56 udp/1
57 ]).
58
59 -define(is_print(C), C >= $ , C =< $~).
60
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
61 decapsulate(P) when byte_size(P) < ?ETHERHDRLEN ->
62 invalid_packet;
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
63 decapsulate(P) ->
88cacab @oliv3 IPv6 support
oliv3 authored
64 {EtherType, EtherHdr, EtherData} = ether(P),
65 case truncated(EtherType, byte_size(P)) of
66 true ->
67 [EtherHdr, {truncated, EtherData}, <<>>, <<>>];
68
69 false ->
70 decapsulate(EtherType, EtherHdr, EtherData)
71 end.
72
73 truncated(?ETHTYPE_IPV4, Size) ->
74 Size < ?ETHERHDRLEN + ?IPV4HDRLEN;
75 truncated(?ETHTYPE_IPV6, 0) -> %% Jumbo payload
76 false;
77 truncated(?ETHTYPE_IPV6, Size) ->
78 Size < ?ETHERHDRLEN + ?IPV6HDRLEN;
79 truncated(_EtherType, _Size) ->
80 false.
81
82 decapsulate(?ETHTYPE_IPV4, EtherHdr, EtherData) ->
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
83 {IPHdr, IPData} = ipv4(EtherData),
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
84 {Hdr, Payload} = decapsulate(proto(IPHdr#ipv4.p), (IPData)),
88cacab @oliv3 IPv6 support
oliv3 authored
85 [EtherHdr, IPHdr, Hdr, Payload];
86 decapsulate(?ETHTYPE_IPV6, _EtherHdr, _EtherData) ->
87 {unsupported, {ethertype, 'IPv6'}};
88 decapsulate(EtherType, _EtherHdr, _EtherData) ->
89 {unsupported, {ethertype, EtherType}}.
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
90
965b308 @msantos Decapsulate truncated packets. Convert sniff to a gen_server.
authored
91 decapsulate(tcp, Packet) when byte_size(Packet) >= ?TCPHDRLEN ->
92 tcp(Packet);
93 decapsulate(udp, Packet) when byte_size(Packet) >= ?UDPHDRLEN ->
94 udp(Packet);
95 decapsulate(icmp, Packet) when byte_size(Packet) >= ?ICMPHDRLEN ->
96 icmp(Packet);
97 decapsulate(_, Packet) ->
98 {{truncated, Packet}, <<>>}.
99
100
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
101 proto(?IPPROTO_ICMP) -> icmp;
102 proto(?IPPROTO_TCP) -> tcp;
103 proto(?IPPROTO_UDP) -> udp.
104
ec0ca16 @msantos pcap can't return the ethernet CRC trailer.
authored
105 ether(<<Dhost:6/bytes, Shost:6/bytes, Type:2/bytes, Payload/binary>>) ->
106 % Len = byte_size(Packet) - 4,
107 % <<Payload:Len/bytes, CRC:4/bytes>> = Packet,
88cacab @oliv3 IPv6 support
oliv3 authored
108 {Type, #ether{
109 dhost = Dhost, shost = Shost,
110 type = Type
111 }, Payload}.
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
112
113 ipv4(
114 <<V:4, HL:4, ToS:8, Len:16,
88cacab @oliv3 IPv6 support
oliv3 authored
115 Id:16, 0:1, DF:1, MF:1, %% RFC791 states it's a MUST
0406018 @msantos Add licensing and do cleanup. In other words, do stuff.
authored
116 Off:13, TTL:8, P:8, Sum:16,
117 SA1:8, SA2:8, SA3:8, SA4:8,
118 DA1:8, DA2:8, DA3:8, DA4:8,
119 Payload/binary>> = Raw
120 ) ->
121 <<Hdr:160/bitstring, _/binary>> = Raw,
122 Valid = case makesum(Hdr) of
123 0 -> true;
124 _ -> false
125 end,
126
127 {#ipv4{
128 valid = Valid,
129 v = V, hl = HL, tos = ToS, len = Len,
130 id = Id, df = DF, mf = MF,
131 off = Off, ttl = TTL, p = P, sum = Sum,
132 saddr = {SA1,SA2,SA3,SA4},
133 daddr = {DA1,DA2,DA3,DA4}
134 }, Payload}.
135
136 tcp(
137 <<SPort:16, DPort:16,
138 SeqNo:32,
139 AckNo:32,
140 Off:4, 0:4, CWR:1, ECE:1, URG:1, ACK:1,
141 PSH:1, RST:1, SYN:1, FIN:1, Win:16,
142 Sum:16, Urp:16,
143 Payload/binary>>
144 ) ->
145 {Opt, Msg} = tcp_options(tcp_offset(Off), Payload),
146 {#tcp{
147 sport = SPort, dport = DPort,
148 seqno = SeqNo,
149 ackno = AckNo,
150 off = Off, cwr = CWR, ece = ECE, urg = URG, ack = ACK,
151 psh = PSH, rst = RST, syn = SYN, fin = FIN, win = Win,
152 sum = Sum, urp = Urp,
153 opt = Opt
154 }, Msg}.
155
156 tcp_offset(N) when N > 5 -> (N - 5) * 4;
157 tcp_offset(_) -> 0.
158
159 tcp_options(Offset, Payload) when Offset > 0 ->
160 <<Opt:Offset/bytes, Msg/binary>> = Payload,
161 {Opt, Msg};
162 tcp_options(_, Payload) ->
163 {<<>>, Payload}.
164
165 udp(<<SPort:16, DPort:16, ULen:16, Sum:16, Payload/binary>>) ->
166 {#udp{sport = SPort, dport = DPort, ulen = ULen, sum = Sum}, Payload}.
167
168 icmp(<<?ICMP_ECHO:8, Code:8, Checksum:16, Id:16, Sequence:16, Payload/binary>>) ->
169 {#icmp{
170 type = ?ICMP_ECHO, code = Code, checksum = Checksum, id = Id,
171 sequence = Sequence
172 }, Payload};
173
174 % PLACEHOLDER: gateway
175 icmp(<<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16, Gateway:32, Payload/binary>>) ->
176 {#icmp{
177 type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum, gateway = Gateway
178 }, Payload};
179
180 % PLACEHOLDER: frag
181 icmp(<<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16, _Unused:16, MTU:16, Payload/binary>>) ->
182 {#icmp{
183 type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum, mtu = MTU
184 }, Payload};
185
186 % Catch unknown types
187 icmp(<<Type:8, Code:8, Checksum:16, Un:32, Payload/binary>>) ->
188 {#icmp{
189 type = Type, code = Code, checksum = Checksum, un = Un
190 }, Payload}.
191
192 payload(Payload) ->
193 [ to_ascii(C) || <<C:8>> <= Payload ].
194
195 checksum(Hdr) ->
196 lists:foldl(fun compl/2, 0, [ W || <<W:16>> <= Hdr ]).
197
198 checksum(tcp, #ipv4{saddr = {S1,S2,S3,S4}, daddr = {D1,D2,D3,D4}, p = P},
199 <<Head:16/bytes, _:2/bytes, Trailer/binary>> = Payload) ->
200 Len = byte_size(Payload),
201 PseudoHdr = case Len rem 2 of
202 0 -> <<S1,S2,S3,S4,D1,D2,D3,D4,0:8,P,Len:16,Head/bytes,0:16,Trailer/bytes>>;
203 1 -> <<S1,S2,S3,S4,D1,D2,D3,D4,0:8,P,Len:16,Head/bytes,0:16,Trailer/bytes,0>>
204 end,
205 checksum(PseudoHdr).
206
207 makesum(Hdr) -> 16#FFFF - checksum(Hdr).
208
209 compl(N) when N =< 16#FFFF -> N;
210 compl(N) -> (N band 16#FFFF) + (N bsr 16).
211 compl(N,S) -> compl(N+S).
212
213 valid(16#FFFF) -> true;
214 valid(_) -> false.
215
216 to_ascii(C) when ?is_print(C) -> C;
217 to_ascii(_) -> $..
218
219 ether_addr(B) when is_binary(B) ->
220 ether_addr(binary_to_list(B));
221 ether_addr(L) when is_list(L) ->
222 [ hd(io_lib:format("~.16B", [N])) || N <- L ].
223
224 tcp_flags(#tcp{cwr = CWR, ece = ECE, urg = URG, ack = ACK,
225 psh = PSH, rst = RST, syn = SYN, fin = FIN}) ->
226 [ atom_to_list(F) || {F,V} <-
227 [{cwr,CWR}, {ece,ECE}, {urg,URG}, {ack,ACK}, {psh,PSH}, {rst,RST}, {syn,SYN}, {fin,FIN}], V =:= 1 ].
228
229
230
Something went wrong with that request. Please try again.