Skip to content

HTTPS clone URL

Subversion checkout URL

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